Files
clinicpro/tests/Sms/SmsWalletTaxTest.php
hamed 7716b40f6a feat: implement tax calculations for subscription and SMS wallet payments
- Updated SubscriptionPeriod interface to include tax-related fields: tax_percent, tax_rials, and payable_rials.
- Modified payment API documentation to reflect changes in tax handling for subscriptions and SMS wallet charges.
- Adjusted PaymentController to calculate payment amounts based on subscription period details instead of client input.
- Enhanced PaymentManager to handle net amounts for SMS wallet charges, ensuring tax is not credited to the wallet.
- Created PaymentTaxCalculator and SubscriptionTaxCalculator services to manage tax calculations consistently across payment types.
- Added tests for tax calculations in both subscription and SMS wallet contexts, ensuring correct behavior with and without tax enabled.
- Updated frontend components to display tax information appropriately during payment processes.
2026-08-09 16:51:22 +03:30

117 lines
4.1 KiB
PHP

<?php
namespace App\Tests\Sms;
use App\Config\Entity\SiteConfig;
use App\Doctor\Entity\Doctor;
use App\Payment\Entity\Payment;
use App\Sms\Service\SmsWalletService;
use App\Tests\ApiTestCase;
/**
* شارژ کیف پول پیامک مثل اشتراک است: مبلغ درخواستی خالص است و مالیات رویش اضافه
* می‌شود. نکتهٔ اصلی این است که **اعتبارِ کیف پول همان مبلغ خالص می‌ماند** — اگر
* مالیات هم اعتبار می‌شد، کاربر آن را به‌صورت پیامک پس می‌گرفت.
*/
class SmsWalletTaxTest extends ApiTestCase
{
private function setConfig(string $key, string $value): void
{
$cfg = $this->em->getRepository(SiteConfig::class)->findOneBy(['configKey' => $key]);
if ($cfg === null) {
$this->em->persist(new SiteConfig($key, $value));
} else {
$cfg->setValue($value);
}
$this->em->flush();
}
private function enableTax(string $percent = '10'): void
{
$this->setConfig('tax_enabled', '1');
$this->setConfig('tax_percent', $percent);
}
private function makeDoctor(): Doctor
{
$doctor = new Doctor($this->createUser(['ROLE_DOCTOR']), 'دکتر کیف پول');
$this->em->persist($doctor);
$this->em->flush();
return $doctor;
}
/** @return array<string, mixed> */
private function charge(Doctor $doctor, int $netRials): array
{
$res = $this->authJson('POST', '/api/v1/sms/wallet/charge', $doctor->getUser(), [
'gateway' => 'mellat',
'amount_rials' => $netRials,
]);
self::assertSame(200, $this->responseCode());
return $res['data'];
}
public function testChargeResponseSplitsNetAndTax(): void
{
$this->enableTax('10');
$data = $this->charge($this->makeDoctor(), 1_000_000);
self::assertSame(1_000_000, $data['net_rials']);
// JSON عدد اعشاریِ ۱۰٫۰ را ۱۰ سریالایز می‌کند، پس مقایسه با نوعِ شل.
self::assertEquals(10, $data['tax_percent']);
self::assertSame(100_000, $data['tax_rials']);
self::assertSame(1_100_000, $data['payable_rials']);
}
public function testThePaymentRowCarriesTheTaxedAmount(): void
{
$this->enableTax('10');
$data = $this->charge($this->makeDoctor(), 1_000_000);
$payment = $this->em->getRepository(Payment::class)->findOneBy(['uuid' => $data['payment_uuid']]);
self::assertSame(1_100_000, $payment->getAmountRials(), 'مبلغ بانک باید شامل مالیات باشد');
self::assertSame(1_000_000, $payment->getMetadata()['net_rials']);
}
public function testWalletIsCreditedWithTheNetAmountNotTheTaxedOne(): void
{
$this->enableTax('10');
$doctor = $this->makeDoctor();
$wallets = static::getContainer()->get(SmsWalletService::class);
$before = $wallets->getBalance('doctor', $doctor->getId());
$data = $this->charge($doctor, 1_000_000);
$payment = $this->em->getRepository(Payment::class)->findOneBy(['uuid' => $data['payment_uuid']]);
$this->client->request('POST', \App\Payment\Service\PaymentManager::CALLBACK_PATH . '?' . http_build_query([
'gateway' => 'mellat',
'order_id' => $payment->getOrderId(),
'mock' => '1',
'ResCode' => '0',
'mock_amount' => '1100000',
]));
$this->em->clear();
self::assertSame(
$before + 1_000_000,
$wallets->getBalance('doctor', $doctor->getId()),
'مالیات نباید به اعتبار پیامک تبدیل شود',
);
}
public function testDisabledTaxKeepsChargeAmountUnchanged(): void
{
$this->setConfig('tax_enabled', '0');
$this->setConfig('tax_percent', '10');
$data = $this->charge($this->makeDoctor(), 1_000_000);
self::assertSame(0, $data['tax_rials']);
self::assertSame(1_000_000, $data['payable_rials']);
}
}