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.
This commit is contained in:
hamed
2026-08-09 16:51:22 +03:30
parent 2471c90cbb
commit 7716b40f6a
18 changed files with 762 additions and 45 deletions
@@ -15,6 +15,7 @@ use App\Subscription\Repository\SubscriptionPlanRepository;
use App\Subscription\Repository\SubscriptionPeriodRepository;
use App\Subscription\Repository\ClinicSubscriptionRepository;
use App\Subscription\Service\SubscriptionService;
use App\Subscription\Service\SubscriptionTaxCalculator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -36,6 +37,7 @@ class SubscriptionController extends BaseController
private readonly UserActiveContextRepository $contextRepo,
private readonly EntityManagerInterface $em,
private readonly \App\Secretary\Security\SecretaryAccessChecker $secretaryAccess,
private readonly SubscriptionTaxCalculator $tax,
) {}
// ── Public ──────────────────────────────────────────────────────────────
@@ -45,10 +47,10 @@ class SubscriptionController extends BaseController
{
$plans = $this->planRepo->findAllActive();
return $this->success(array_map(
return $this->success($this->tax->decoratePlans(array_map(
fn(SubscriptionPlan $p) => $p->toArray(withPeriods: true),
$plans
));
)));
}
// ── Authenticated ────────────────────────────────────────────────────────
@@ -123,7 +125,7 @@ class SubscriptionController extends BaseController
$plans = $this->planRepo->findAllForAdmin();
return $this->paginated(
array_map(fn(SubscriptionPlan $p) => $p->toArray(withPeriods: true), $plans),
$this->tax->decoratePlans(array_map(fn(SubscriptionPlan $p) => $p->toArray(withPeriods: true), $plans)),
count($plans),
1,
100
@@ -247,7 +249,7 @@ class SubscriptionController extends BaseController
$this->periodRepo->save($period);
return $this->success($period->toArray(), 201);
return $this->success($this->tax->decoratePeriod($period->toArray()), 201);
}
#[Route('/api/v1/admin/subscription/period/{uuid}', methods: ['PATCH'])]
@@ -269,7 +271,7 @@ class SubscriptionController extends BaseController
$this->periodRepo->save($period);
return $this->success($period->toArray());
return $this->success($this->tax->decoratePeriod($period->toArray()));
}
#[Route('/api/v1/admin/subscription/period/{uuid}', methods: ['DELETE'])]