- Added new configuration keys for appointment and upgrade commissions, tax settings, and SMS panel fee in SiteConfigController and SiteConfigRepository. - Introduced CommissionService to handle commission calculations for appointments and subscriptions, including tax deductions and SMS fees. - Created FinancialBreakdown entity and repository to log financial transactions. - Updated PaymentController to process commissions upon successful payments for appointments and subscriptions. - Developed FinancialReportPage in the admin panel to display financial breakdowns and summaries. - Added database migration for the new financial_breakdowns table.
331 lines
22 KiB
Markdown
331 lines
22 KiB
Markdown
# موتور مالی نمایندگی: پورسانت نوبت/ارتقاء + مالیات بر ارزش افزوده + هزینه پنل پیامک
|
||
|
||
## پروژه
|
||
|
||
`clinicpro` (Backend Symfony + پنل ادمین React). کاملاً داخل همین پروژه است؛ cross-repo نیست.
|
||
سایت عمومی `nobat724_front` فقط مصرفکنندهی مبلغِ نهایی نوبت است و در این تغییر دست نمیخورد (مبلغ پرداختی کاربر تغییر نمیکند؛ فقط تقسیمِ پس از پرداخت در بکاند اضافه میشود).
|
||
|
||
## زمینه
|
||
|
||
هر `Representation` یک فیلد `commission_percent` دارد که در `/admin/representations` ذخیره و ویرایش میشود، **اما در هیچ محاسبهی مالی استفاده نمیشود** — صرفاً نمایشی است. هر `Doctor` و هر `Clinic` فیلد `representationId` دارند (نمایندهای که آنها را اضافه کرده). هنگام موفقشدن پرداخت، `PaymentController` فقط نوبت را `confirmed` یا اشتراک را فعال میکند و **هیچ سهمی به کیفپول نماینده واریز نمیشود**.
|
||
|
||
کیفپول نماینده با `WalletTransaction` (credit/debit + `balance_after`) و موجودی با `SettlementRepository::getWalletBalance(User)` مدیریت میشود؛ نماینده از طریق `Settlement` برداشت میکند. تنظیمات سراسری در `SiteConfig` (کلید/مقدار) با whitelist در `SiteConfigController::ALLOWED_KEYS` و defaults در `SiteConfigRepository::DEFAULTS` نگهداری میشوند. کلیدهای `commission_enabled` و `commission_percent` از قبل تعریف شده ولی بلااستفادهاند.
|
||
|
||
## مشکل / هدف
|
||
|
||
۱. هنگام پرداخت موفقِ **نوبت** برای پزشکی که `representationId` دارد، سهم نماینده محاسبه و به کیفپولش واریز شود (درصد = `commission_percent` همان نماینده).
|
||
۲. هنگام پرداخت موفقِ **ارتقاء/خرید اشتراک** پزشک یا کلینیکی که `representationId` دارد، درصدِ ارتقاء (پیشفرض ۲۰٪، **غیر هاردکد**، از تنظیمات ادمین) به کیفپول نماینده واریز شود.
|
||
۳. **مالیات بر ارزش افزوده**: همهی مبالغ شامل مالیاتاند. درصد مالیات + فعال/غیرفعال + (اختیاری) تاریخچه از پنل ادمین کنترل شود. برای هر تراکنش مبلغ مالیات ذخیره شود.
|
||
۴. **هزینه ثابت پنل پیامک**: مبلغ ثابت ۱۵۰٬۰۰۰ تومان = **۱٬۵۰۰٬۰۰۰ ریال** از مبلغ نوبت کسر شود (مبلغ از تنظیمات ادمین قابل کنترل).
|
||
۵. **ترتیب محاسبه (بسیار مهم)**: ۱) کسر هزینه پنل پیامک، ۲) کسر مالیات از باقیمانده، ۳) پورسانت نماینده از **مبلغ خالصِ پس از مالیات**.
|
||
۶. ثبت لاگ کامل مالی برای هر تراکنش + مشاهده/گزارشگیری در پنل ادمین.
|
||
|
||
## فایلهای مرتبط
|
||
|
||
| فایل | نقش |
|
||
|------|-----|
|
||
| `clinicpro/src/Config/Controller/SiteConfigController.php` | افزودن کلیدهای مالی به `ALLOWED_KEYS` |
|
||
| `clinicpro/src/Config/Repository/SiteConfigRepository.php` | افزودن `DEFAULTS` کلیدهای مالی |
|
||
| `clinicpro/src/Settlement/Entity/FinancialBreakdown.php` (جدید) | Entity لاگ تفکیک مالی هر تراکنش |
|
||
| `clinicpro/src/Settlement/Repository/FinancialBreakdownRepository.php` (جدید) | repository + کوئری گزارشها |
|
||
| `clinicpro/src/Settlement/Service/CommissionService.php` (جدید) | منطق محاسبه (ترتیب کسر) + واریز کیفپول + ثبت لاگ |
|
||
| `clinicpro/src/Payment/Controller/PaymentController.php` | فراخوانی `CommissionService` در `handleAppointmentConfirmation` و `handleSubscriptionActivation` |
|
||
| `clinicpro/src/Representation/Entity/Representation.php` | منبع `commission_percent` نوبتِ هر نماینده (موجود) |
|
||
| `clinicpro/src/Doctor/Entity/Doctor.php` / `Clinic/Entity/Clinic.php` | `getRepresentationId()` (موجود) |
|
||
| `clinicpro/src/Representation/Repository/RepresentationRepository.php` | افزودن `find(int $id)` برای یافتن نماینده از روی `representationId` |
|
||
| `clinicpro/src/Settlement/Repository/SettlementRepository.php` | `getWalletBalance(User)` (موجود) برای محاسبه `balance_after` |
|
||
| `clinicpro/src/Admin/Controller/AdminApiController.php` | endpointهای گزارش مالی (لیست breakdown + جمعها) |
|
||
| `clinicpro/assets/admin/pages/SettingsPage.tsx` | فرم تنظیمات مالی |
|
||
| `clinicpro/assets/admin/pages/FinancialReportPage.tsx` (جدید) | جدول تراکنشها + کارتهای جمع |
|
||
| `clinicpro/docs/api/admin.md`، `docs/api/settlement.md`، `docs/api/payment.md` | مستندسازی |
|
||
|
||
## وضعیت فعلی
|
||
|
||
### الف) هوک پرداخت موفق — هیچ پورسانتی واریز نمیشود
|
||
|
||
`clinicpro/src/Payment/Controller/PaymentController.php`
|
||
|
||
```php
|
||
$payment->setStatus(Payment::STATUS_SUCCESS);
|
||
$payment->setReferenceId($result->referenceId);
|
||
$this->paymentRepo->save($payment);
|
||
|
||
if ($payment->getType() === Payment::TYPE_SUBSCRIPTION) {
|
||
$this->handleSubscriptionActivation($payment);
|
||
} elseif ($payment->getType() === Payment::TYPE_SMS_WALLET) {
|
||
$this->handleSmsWalletCharge($payment);
|
||
} elseif ($payment->getType() === Payment::TYPE_APPOINTMENT) {
|
||
$this->handleAppointmentConfirmation($payment);
|
||
}
|
||
```
|
||
|
||
```php
|
||
private function handleAppointmentConfirmation(Payment $payment): void
|
||
{
|
||
$appointment = $payment->getAppointment();
|
||
if ($appointment === null || !$appointment->canTransitionTo(Appointment::STATUS_CONFIRMED)) {
|
||
return;
|
||
}
|
||
$appointment->transitionTo(Appointment::STATUS_CONFIRMED);
|
||
$this->appointmentRepo->save($appointment);
|
||
// ... فقط SMS؛ هیچ پورسانت/مالیاتی نیست
|
||
}
|
||
|
||
private function handleSubscriptionActivation(Payment $payment): void
|
||
{
|
||
$meta = $payment->getMetadata() ?? [];
|
||
$periodUuid = $meta['period_uuid'] ?? null;
|
||
if ($periodUuid === null) return;
|
||
|
||
$user = $payment->getUser();
|
||
$doctor = $this->doctorRepo->findByUser($user);
|
||
if ($doctor !== null) {
|
||
$this->subscriptionService->createFromPayment($payment, 'doctor', $doctor->getId(), $periodUuid);
|
||
return;
|
||
}
|
||
$clinic = $this->clinicRepo->findByUser($user);
|
||
if ($clinic !== null) {
|
||
$this->subscriptionService->createFromPayment($payment, 'clinic', $clinic->getId(), $periodUuid);
|
||
}
|
||
}
|
||
```
|
||
|
||
### ب) `commission_percent` بلااستفاده
|
||
|
||
`Representation::getCommissionPercent(): string` (decimal 5,2، پیشفرض `'10.00'`) فقط در `RepresentationController` و خروجی admin خوانده/نوشته میشود؛ در هیچ محاسبهی مالی بهکار نمیرود.
|
||
|
||
### ج) الگوی واریز کیفپول (از `SettlementController::reject`)
|
||
|
||
```php
|
||
$balance = $this->settlementRepo->getWalletBalance($settlement->getUser());
|
||
$tx = new WalletTransaction(
|
||
$settlement->getUser(),
|
||
$settlement->getAmountRials(),
|
||
WalletTransaction::TYPE_CREDIT,
|
||
$balance + $settlement->getAmountRials()
|
||
);
|
||
$tx->setDescription('...');
|
||
$this->walletRepo->save($tx);
|
||
```
|
||
|
||
### د) تنظیمات ادمین (whitelist + defaults)
|
||
|
||
```php
|
||
// SiteConfigController::ALLOWED_KEYS — فعلاً: commission_enabled, commission_percent, ...
|
||
// SiteConfigRepository::DEFAULTS — 'commission_enabled' => '0', 'commission_percent' => '0', ...
|
||
// GET/PATCH /api/v1/admin/settings از قبل کار میکند
|
||
```
|
||
|
||
## وظایف
|
||
|
||
### ۱. کلیدهای تنظیمات مالی در `SiteConfig`
|
||
|
||
به `SiteConfigController::ALLOWED_KEYS` و `SiteConfigRepository::DEFAULTS` این کلیدها اضافه شود (همه بهصورت رشته ذخیره میشوند):
|
||
|
||
```php
|
||
// ALLOWED_KEYS + DEFAULTS
|
||
'appointment_commission_enabled' => '0', // پورسانت نوبت فعال؟ (درصد از خودِ نماینده خوانده میشود)
|
||
'upgrade_commission_enabled' => '0', // پورسانت ارتقاء اشتراک فعال؟
|
||
'upgrade_commission_percent' => '20', // درصد پورسانت ارتقاء (غیر هاردکد)
|
||
'tax_enabled' => '0', // مالیات بر ارزش افزوده فعال؟
|
||
'tax_percent' => '10', // درصد مالیات بر ارزش افزوده
|
||
'sms_panel_fee_rials' => '1500000',// هزینه ثابت پنل پیامک به ریال (۱۵۰٬۰۰۰ تومان)
|
||
```
|
||
|
||
> توجه: `commission_percent`/`commission_enabled` قدیمی بلااستفادهاند؛ دست نزن یا در همین تسک منسوخشان کن (در `SettingsPage` پنهان کن). کلید پورسانت نوبت اکنون `appointment_commission_enabled` + درصدِ هر نماینده است.
|
||
|
||
### ۲. Entity لاگ مالی `FinancialBreakdown`
|
||
|
||
فایل جدید `clinicpro/src/Settlement/Entity/FinancialBreakdown.php`. برای هر تراکنشی که مشمول قانون مالی میشود یک ردیف ثبت شود. فیلدها (همگی ریال، تاریخها Unix timestamp صحیح):
|
||
|
||
```php
|
||
#[ORM\Entity]
|
||
#[ORM\Table(name: 'financial_breakdowns')]
|
||
class FinancialBreakdown
|
||
{
|
||
public const SOURCE_APPOINTMENT = 'appointment';
|
||
public const SOURCE_SUBSCRIPTION = 'subscription';
|
||
|
||
private ?int $id;
|
||
private string $uuid; // Uuid::v4()->toRfc4122()
|
||
#[ORM\ManyToOne(targetEntity: Payment::class)] private Payment $payment;
|
||
private string $source; // appointment | subscription
|
||
private int $grossRials; // مبلغ اولیه تراکنش
|
||
private int $smsFeeRials; // کسر پنل پیامک
|
||
private string $taxPercent; // decimal 5,2 — درصد مالیاتِ اعمالشده
|
||
private int $taxRials; // مبلغ مالیات
|
||
private int $netAfterTaxRials; // خالص پس از پیامک و مالیات
|
||
private string $commissionPercent; // decimal 5,2 — درصد پورسانتِ اعمالشده
|
||
private int $representationShareRials;// سهم نماینده
|
||
private int $systemShareRials; // سهم سیستم
|
||
private ?int $representationId = null;
|
||
private ?int $doctorId = null;
|
||
private ?int $clinicId = null;
|
||
#[ORM\ManyToOne(targetEntity: User::class)] private User $user; // پرداختکننده
|
||
private int $createdAt;
|
||
// getters + toArray()
|
||
}
|
||
```
|
||
|
||
`toArray()` همهی این مبالغ + ids را برگرداند تا در گزارش ادمین نمایش داده شوند.
|
||
|
||
migration لازم است: `ddev exec php bin/console doctrine:migrations:diff --no-interaction` سپس `migrate`.
|
||
|
||
### ۳. سرویس محاسبه `CommissionService`
|
||
|
||
فایل جدید `clinicpro/src/Settlement/Service/CommissionService.php`. مسئول: محاسبه با **ترتیب دقیق**، واریز کیفپول نماینده، ثبت `FinancialBreakdown`.
|
||
|
||
```php
|
||
class CommissionService
|
||
{
|
||
public function __construct(
|
||
private SiteConfigRepository $configRepo,
|
||
private RepresentationRepository $representationRepo,
|
||
private SettlementRepository $settlementRepo, // getWalletBalance
|
||
private WalletTransactionRepository $walletRepo,
|
||
private FinancialBreakdownRepository $breakdownRepo,
|
||
private EntityManagerInterface $em,
|
||
) {}
|
||
|
||
/**
|
||
* نوبت: درصد پورسانت = commission_percent همان نماینده.
|
||
* هزینه پیامک فقط در مسیر نوبت کسر میشود.
|
||
*/
|
||
public function processAppointment(Payment $payment, ?int $representationId, ?int $doctorId): void
|
||
{
|
||
if ($this->configRepo->get('appointment_commission_enabled') !== '1') return;
|
||
$rep = $representationId ? $this->representationRepo->find($representationId) : null;
|
||
if ($rep === null || !$rep->isActive()) return;
|
||
|
||
$smsFee = (int) $this->configRepo->get('sms_panel_fee_rials');
|
||
$percent = (float) $rep->getCommissionPercent();
|
||
$this->settle($payment, FinancialBreakdown::SOURCE_APPOINTMENT, $smsFee, $percent, $rep, $doctorId, null);
|
||
}
|
||
|
||
/**
|
||
* اشتراک/ارتقاء: درصد = upgrade_commission_percent (سراسری). بدون کسر هزینه پیامک.
|
||
*/
|
||
public function processSubscription(Payment $payment, ?int $representationId, ?int $doctorId, ?int $clinicId): void
|
||
{
|
||
if ($this->configRepo->get('upgrade_commission_enabled') !== '1') return;
|
||
$rep = $representationId ? $this->representationRepo->find($representationId) : null;
|
||
if ($rep === null || !$rep->isActive()) return;
|
||
|
||
$percent = (float) $this->configRepo->get('upgrade_commission_percent');
|
||
$this->settle($payment, FinancialBreakdown::SOURCE_SUBSCRIPTION, 0, $percent, $rep, $doctorId, $clinicId);
|
||
}
|
||
|
||
private function settle(
|
||
Payment $payment, string $source, int $smsFee, float $commissionPercent,
|
||
Representation $rep, ?int $doctorId, ?int $clinicId
|
||
): void {
|
||
$gross = $payment->getAmountRials();
|
||
|
||
// مرحله ۱: کسر هزینه ثابت پنل پیامک
|
||
$afterSms = max(0, $gross - $smsFee);
|
||
|
||
// مرحله ۲: محاسبه و کسر مالیات از باقیمانده
|
||
$taxEnabled = $this->configRepo->get('tax_enabled') === '1';
|
||
$taxPercent = $taxEnabled ? (float) $this->configRepo->get('tax_percent') : 0.0;
|
||
// مبالغ شامل مالیاتاند ⇒ مالیات از مبلغِ مشمول استخراج میشود.
|
||
// در run-prompt با کاربر تأیید کن: «استخراج از مبلغِ شامل مالیات» یا «افزودن روی مبلغ».
|
||
$taxRials = $taxEnabled ? (int) round($afterSms * $taxPercent / (100 + $taxPercent)) : 0;
|
||
$netAfterTax = $afterSms - $taxRials;
|
||
|
||
// مرحله ۳: پورسانت نماینده از خالصِ پس از مالیات
|
||
$repShare = (int) round($netAfterTax * $commissionPercent / 100);
|
||
$systemShare = $gross - $smsFee - $taxRials - $repShare;
|
||
|
||
// واریز کیفپول نماینده (الگوی SettlementController)
|
||
$repUser = $rep->getUser();
|
||
$balance = $this->settlementRepo->getWalletBalance($repUser);
|
||
$tx = new WalletTransaction($repUser, $repShare, WalletTransaction::TYPE_CREDIT, $balance + $repShare);
|
||
$tx->setPayment($payment);
|
||
$tx->setDescription(sprintf('پورسانت %s %s', $source, $payment->getOrderId()));
|
||
$this->walletRepo->save($tx, false);
|
||
|
||
// ثبت لاگ مالی
|
||
$bd = new FinancialBreakdown(/* ... همهی مبالغ، درصدها، ids ... */);
|
||
$this->breakdownRepo->save($bd, false);
|
||
|
||
$this->em->flush();
|
||
}
|
||
}
|
||
```
|
||
|
||
نکات محاسبه:
|
||
- اگر `repShare <= 0` بود (مثلاً مبلغ پس از کسرها صفر شد) واریز کیفپول انجام نشود ولی لاگ با مقادیر صفر همچنان ثبت شود (برای گزارش).
|
||
- همهی مبالغ صحیح ریال؛ از `round` برای جلوگیری از خطای ممیز استفاده شود.
|
||
|
||
### ۴. اتصال به `PaymentController`
|
||
|
||
`CommissionService` به constructor تزریق شود و در دو هوک فراخوانی شود.
|
||
|
||
در `handleAppointmentConfirmation` بعد از `confirmed` شدن:
|
||
```php
|
||
$doctor = $appointment->getDoctor();
|
||
$this->commissionService->processAppointment(
|
||
$payment,
|
||
$doctor->getRepresentationId(),
|
||
$doctor->getId(),
|
||
);
|
||
```
|
||
|
||
در `handleSubscriptionActivation` بعد از فعالسازی اشتراک، با تشخیص doctor/clinic:
|
||
```php
|
||
// مسیر doctor:
|
||
$this->commissionService->processSubscription($payment, $doctor->getRepresentationId(), $doctor->getId(), null);
|
||
// مسیر clinic:
|
||
$this->commissionService->processSubscription($payment, $clinic->getRepresentationId(), null, $clinic->getId());
|
||
```
|
||
|
||
> idempotency: مطمئن شو یک پرداخت دوبار پردازش نشود (verify فقط یکبار success میشود؛ ولی برای اطمینان میتوان قبل از ثبت، نبودِ `FinancialBreakdown` با همان `payment_id` را بررسی کرد).
|
||
|
||
### ۵. `RepresentationRepository::find(int $id)`
|
||
|
||
متد یافتن نماینده از روی `representationId` (که روی Doctor/Clinic ذخیره است). `ServiceEntityRepository` بهصورت پیشفرض `find()` دارد؛ فقط مطمئن شو در سرویس از `->find($id)` استفاده میشود.
|
||
|
||
### ۶. endpointهای گزارش مالی در `AdminApiController`
|
||
|
||
طبق الگوی پروژه (`getArrayResult()` + `$this->paginated()` برای لیست، `$this->success()` برای جمعها):
|
||
|
||
- `GET /api/v1/admin/financial-breakdowns` (paginated): لیست تراکنشها با تفکیک کامل + join نام نماینده/پزشک/کلینیک. فیلتر اختیاری `representation_id`, `source`, بازهی تاریخ.
|
||
- `GET /api/v1/admin/financial-summary`: جمعها → `total_representation_income`, `total_tax_collected`, `total_sms_fee`, `total_system_share`, `total_gross`.
|
||
|
||
هر دو `#[IsGranted('ROLE_ADMIN')]`.
|
||
|
||
### ۷. پنل ادمین — تنظیمات + گزارش
|
||
|
||
**`SettingsPage.tsx`**: بخش «تنظیمات مالی» با فیلدهای:
|
||
- فعال/غیرفعال پورسانت نوبت (`appointment_commission_enabled`)
|
||
- فعال/غیرفعال + درصد پورسانت ارتقاء (`upgrade_commission_enabled`, `upgrade_commission_percent`)
|
||
- فعال/غیرفعال + درصد مالیات (`tax_enabled`, `tax_percent`)
|
||
- هزینه پنل پیامک به ریال (`sms_panel_fee_rials`) — نمایش معادل تومان کمکی
|
||
PATCH به `/api/v1/admin/settings` (الگوی موجود همان صفحه).
|
||
|
||
**`FinancialReportPage.tsx` (جدید)** + route در `App.tsx` (`roles={['admin']}`):
|
||
- کارتهای جمع از `financial-summary`
|
||
- جدول `DataTable` + `Pagination` از `financial-breakdowns` (مبالغ با `formatRial`، تاریخ شمسی با `formatDate`)
|
||
- لینک در `Sidebar.tsx`
|
||
|
||
> الگوهای frontend: paginated → items از `data?.data`، total از `data?.meta?.totalRecords`؛ single (summary) → `data?.data`. JWT از `localStorage['clinicpro-auth']`.
|
||
|
||
### ۸. (اختیاری طبق درخواست) تاریخچهی تغییرات مالیات
|
||
|
||
اگر در run-prompt لازم شد: یک Entity سادهی `TaxRateHistory` (percent, enabled, changed_by, changed_at) که در `SiteConfigController::patch` هنگام تغییر `tax_percent`/`tax_enabled` یک ردیف ثبت کند + endpoint لیست. در نسخهی اول میتوان فقط روی `updated_at`ِ `SiteConfig` اکتفا کرد و این را به فاز بعد سپرد — در run-prompt با کاربر تأیید شود.
|
||
|
||
## نکات مهم
|
||
|
||
- **ترتیب کسرها ثابت و غیرقابلجابهجایی است**: پیامک → مالیات → پورسانت. پورسانت حتماً روی `netAfterTax` نه `gross`.
|
||
- **«همه مبالغ شامل مالیاتاند»** ⇒ فرمول استخراجِ مالیات از مبلغِ ناخالص (`amount × p/(100+p)`) استفاده شده، نه افزودن روی آن. این تصمیم را در ابتدای run-prompt صریحاً با کاربر تأیید کن؛ اگر منظورش «افزودن مالیات روی مبلغ» باشد فرمول `amount × p/100` میشود.
|
||
- **هزینه پنل پیامک فقط روی نوبت** اعمال شده (طبق متن «از مبلغ نوبت کسر شود»). اگر باید روی اشتراک هم اعمال شود، در run-prompt تأیید بگیر.
|
||
- درصد پورسانتِ **نوبت** از `Representation::commission_percent` (هر نماینده جدا) و درصد **ارتقاء** از کلید سراسری `upgrade_commission_percent`. این تفکیک عمدی است.
|
||
- هیچ مبلغی نباید هاردکد شود؛ ۲۰٪ و ۱۵۰٬۰۰۰ تومان صرفاً defaults در `SiteConfig` هستند.
|
||
- همهی مبالغ **ریال صحیح**اند (۱۵۰٬۰۰۰ تومان = ۱٬۵۰۰٬۰۰۰ ریال). در UI با `formatRial` نمایش، در محاسبه با `int`.
|
||
- تاریخها Unix timestamp صحیحاند (نه DateTime). نمایش شمسی با `formatDate`.
|
||
- همهی controllerها از `BaseController` و پاسخها با `success/paginated/error`.
|
||
- **idempotency**: مطمئن شو واریز پورسانت برای یک پرداخت فقط یکبار رخ دهد.
|
||
- بعد از تغییر Entity: `doctrine:migrations:diff` + `migrate`. بعد از تغییر API: `docs/api/admin.md`, `settlement.md`, `payment.md` بهروز شوند.
|
||
- بعد از پایان: `ddev exec php vendor/bin/phpstan analyse` و `ddev exec yarn dev` برای صحت TS، سپس `graphify update .`.
|
||
- تست محاسبه: یک سناریوی عددی واقعی در PR/گزارش نشان بده — مثلاً نوبت ۲٬۰۰۰٬۰۰۰ ریال، پیامک ۱٬۵۰۰٬۰۰۰، مالیات ۱۰٪، پورسانت ۲۰٪ → خالص پس از پیامک ۵۰۰٬۰۰۰ → مالیات استخراجی ۴۵٬۴۵۵ → خالص ۴۵۴٬۵۴۵ → سهم نماینده ۹۰٬۹۰۹، سهم سیستم مابقی.
|