From 6ab1eb64830f87c19cb352217f4c98f1fe92e125 Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Tue, 28 Jul 2026 15:21:55 +0330 Subject: [PATCH] fix(tenant): scope the patient wallet ledger to the environment reading it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ownsRecord guards the patient record, not the rows underneath it, so GET /api/v1/patient/{uuid}/wallet/transactions — and the recent_transactions in the balance summary — returned the patient's entire history. Clinic A could read what the patient paid at clinic B, down to the name of the staff member who entered it. The wallet stays the person's: the balance is still the sum of that user's credits minus debits across every environment. Scoping it would show a patient part of their own money and would make the running balance_after meaningless. So this is attribution per row, not ownership per wallet. The columns are deliberately named recorded_entity_type / recorded_entity_id rather than entity_type / entity_id. TenantFilter keys on the latter and would then scope the balance query too — the exact bug this avoids. The naming is load-bearing, and both the entity and the architecture doc say so. Rows that cannot be attributed — entered before this split, or outside any environment such as a representation's commission — stay NULL and remain visible everywhere; hiding them would make an existing patient's history look deleted. The migration reports how many there are (0 in dev, all attributable from payments and session references). Consequence, documented in both docs/api/patient.md and the wallet tab: the listed rows no longer sum to the displayed balance. Removing the fix turns 3 of the 6 new tests red. Tests: 902 backend (+6), 570 frontend. PHPStan unchanged at 17. Co-Authored-By: Claude Opus 5 (1M context) --- assets/admin/pages/PatientDetailPage.tsx | 5 + docs/api/patient.md | 20 +- docs/architecture/tenancy.md | 23 ++- migrations/Version20260728160000.php | 81 ++++++++ src/Patient/Controller/PatientController.php | 17 +- src/Patient/Service/PatientService.php | 5 +- src/Settlement/Entity/WalletTransaction.php | 32 ++++ .../WalletTransactionRepository.php | 43 +++++ src/Settlement/Service/WalletService.php | 17 +- tests/Patient/PatientWalletTenantTest.php | 177 ++++++++++++++++++ 10 files changed, 410 insertions(+), 10 deletions(-) create mode 100644 migrations/Version20260728160000.php create mode 100644 tests/Patient/PatientWalletTenantTest.php diff --git a/assets/admin/pages/PatientDetailPage.tsx b/assets/admin/pages/PatientDetailPage.tsx index 20a3e4ce..66c906c7 100644 --- a/assets/admin/pages/PatientDetailPage.tsx +++ b/assets/admin/pages/PatientDetailPage.tsx @@ -878,6 +878,11 @@ function WalletTab({ uuid }: { uuid: string }) {
موجودی کیف پول
{formatRial(balanceRials)}
+ {/* موجودی کلِ بیمار است ولی فهرست فقط تراکنش‌های همین محیط را می‌آورد؛ + بدون این توضیح، اختلافِ جمعِ سطرها با موجودی شبیه باگ دیده می‌شود. */} +
+ موجودی کل بیمار؛ تراکنش‌های زیر فقط مربوط به همین محل کار است +
{canUpdate && (