fix(subscription): read the subscription of the environment the user owns

A user who is both a doctor and a clinic owner always resolved to the
doctor: SubscriptionController had its own role-first resolveEntity, and
ownedEntity() returned the doctor whenever one existed. So a subscription
granted to that user's clinic was stored correctly but never surfaced —
/subscription/my kept reporting the free plan and the panel kept the
feature-gated menu items locked.

ownedEntity() now disambiguates with the active context when the user owns
both environments, and the controller delegates to it instead of re-deriving
the pair from roles. Payment already used ownedEntity(), so display, purchase
and admin grant now agree on one environment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
hamed
2026-08-19 22:07:56 +03:30
co-authored by Claude Opus 5
parent b81cb8a90e
commit 32044c8fa9
4 changed files with 89 additions and 28 deletions
+21 -2
View File
@@ -81,16 +81,35 @@ class EntityContextResolver
* برای خریدهایی است که به حساب خودِ صاحب می‌نشیند (اشتراک): آنجا «کجا ایستاده‌ام»
* مهم نیست، «چه چیزی دارم» مهم است. تنها مرجعِ این پرسش همین متد است تا پرداختِ
* اشتراک و خودِ اشتراک هرگز روی دو محیط متفاوت ننشینند.
*
* استثنا: کاربری که هر دو محیط را دارد. آنجا محیط فعال تعیین می‌کند کدام‌یک،
* وگرنه یکی از دو محیطِ صاحب‌شده هرگز اشتراک نمی‌گیرد.
*/
public function ownedEntity(User $user): EntityContext
{
$doctor = $this->doctorRepo->findByUser($user);
$clinic = $this->clinicRepo->findByUser($user);
// کاربری که هم پزشک است و هم مالک کلینیک، دو محیطِ صاحب‌شده دارد و «چه چیزی
// دارم» به‌تنهایی جواب یکتا ندارد. محیط فعال گره را باز می‌کند: اشتراک همان
// جایی می‌نشیند که کاربر ایستاده و آن را می‌بیند. بدون این، اعطای اشتراک به
// کلینیک برای چنین کاربری بی‌اثر می‌ماند، چون پنل همیشه پزشک را می‌خواند.
if ($doctor !== null && $clinic !== null) {
$active = $this->fromActiveContext($user);
if ($active !== null) {
if ($active->isClinic() && $active->toEntityPair()[1] === $clinic->getId()) {
return EntityContext::forClinic($clinic);
}
if (!$active->isClinic() && $active->toEntityPair()[1] === $doctor->getId()) {
return EntityContext::forDoctor($doctor);
}
}
}
if ($doctor !== null) {
return EntityContext::forDoctor($doctor);
}
$clinic = $this->clinicRepo->findByUser($user);
return $clinic !== null ? EntityContext::forClinic($clinic) : EntityContext::unknown();
}