141 lines
6.0 KiB
PHP
141 lines
6.0 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Representation;
|
|
|
|
use App\Config\Repository\SiteConfigRepository;
|
|
use App\Payment\Entity\Payment;
|
|
use App\Representation\Entity\Representation;
|
|
use App\Representation\Service\DomainContextResolver;
|
|
use App\Settlement\Repository\FinancialBreakdownRepository;
|
|
use App\Settlement\Service\CommissionService;
|
|
use App\Tests\ApiTestCase;
|
|
|
|
/**
|
|
* قانون کمیسیون دامنهمحور: کمیسیون فقط وقتی ثبت میشود که خرید از دامنهی نماینده
|
|
* انجام شده باشد و پزشک/کلینیک هم متعلق به همان نماینده باشد. DomainContextResolver
|
|
* تنها نقطهی نگاشت دامنه است.
|
|
*/
|
|
class DomainCommissionTest extends ApiTestCase
|
|
{
|
|
private function makeRep(?string $domain = null, bool $global = false, bool $active = true): Representation
|
|
{
|
|
$owner = $this->createUser(['ROLE_USER', 'ROLE_REPRESENTATION']);
|
|
$rep = new Representation($owner, 'نماینده دامنه');
|
|
$rep->setCommissionPercent('10');
|
|
if ($domain !== null) $rep->setDomain($domain);
|
|
$rep->setIsGlobal($global);
|
|
$rep->setActive($active);
|
|
$this->em->persist($rep);
|
|
$this->em->flush();
|
|
|
|
return $rep;
|
|
}
|
|
|
|
private function makePayment(string $frontendAddress): Payment
|
|
{
|
|
$payment = new Payment($this->createUser(), 2_000_000, 'mock', Payment::TYPE_APPOINTMENT, $frontendAddress);
|
|
$this->em->persist($payment);
|
|
$this->em->flush();
|
|
|
|
return $payment;
|
|
}
|
|
|
|
private function resolver(): DomainContextResolver
|
|
{
|
|
return static::getContainer()->get(DomainContextResolver::class);
|
|
}
|
|
|
|
// ── DomainContextResolver ────────────────────────────────────────────────
|
|
|
|
public function testResolverMatchesRepresentationDomainWithNormalization(): void
|
|
{
|
|
$domain = 'rep-' . uniqid() . '.ir';
|
|
$rep = $this->makeRep($domain, global: true);
|
|
|
|
$ctx = $this->resolver()->resolve('https://www.' . $domain . ':443/payment/result');
|
|
|
|
$this->assertSame($rep->getId(), $ctx->representationId());
|
|
$this->assertTrue($ctx->isGlobalRepresentation);
|
|
$this->assertNull($ctx->city);
|
|
}
|
|
|
|
public function testResolverIgnoresInactiveRepresentation(): void
|
|
{
|
|
$domain = 'rep-' . uniqid() . '.ir';
|
|
$this->makeRep($domain, active: false);
|
|
|
|
$ctx = $this->resolver()->resolve($domain);
|
|
|
|
$this->assertNull($ctx->representation);
|
|
$this->assertFalse($ctx->isGlobalRepresentation);
|
|
}
|
|
|
|
public function testResolverUnknownDomainIsEmpty(): void
|
|
{
|
|
$ctx = $this->resolver()->resolve('nowhere-' . uniqid() . '.ir');
|
|
|
|
$this->assertNull($ctx->representation);
|
|
$this->assertNull($ctx->city);
|
|
}
|
|
|
|
public function testResolverMatchesByFirstLabelForLocalDev(): void
|
|
{
|
|
$prefix = 'repdev' . substr(uniqid(), -6);
|
|
$rep = $this->makeRep($prefix . '.ir', global: true);
|
|
|
|
// host لوکال با TLD متفاوت (`.localhost`) باید همان نماینده را بیابد.
|
|
$ctx = $this->resolver()->resolve($prefix . '.localhost');
|
|
|
|
$this->assertSame($rep->getId(), $ctx->representationId());
|
|
$this->assertTrue($ctx->isGlobalRepresentation);
|
|
}
|
|
|
|
// ── CommissionService: گارد دوشرطی ───────────────────────────────────────
|
|
|
|
public function testAppointmentCommissionOnlyWhenDomainOwnerMatchesDoctorOwner(): void
|
|
{
|
|
static::getContainer()->get(SiteConfigRepository::class)->set('appointment_commission_enabled', '1');
|
|
$commission = static::getContainer()->get(CommissionService::class);
|
|
$breakdowns = static::getContainer()->get(FinancialBreakdownRepository::class);
|
|
|
|
$rep = $this->makeRep('rep-' . uniqid() . '.ir');
|
|
$other = $this->makeRep('rep-' . uniqid() . '.ir');
|
|
|
|
// دامنهی نمایندهی دیگر → بدون کمیسیون
|
|
$p1 = $this->makePayment('https://' . $other->getDomain() . '/payment/result');
|
|
$commission->processAppointment($p1, $rep->getId(), $other->getId(), 7);
|
|
$this->assertFalse($breakdowns->existsForPayment($p1));
|
|
|
|
// بدون دامنه (پرداخت بدون frontend_address) → بدون کمیسیون
|
|
$p2 = $this->makePayment('');
|
|
$commission->processAppointment($p2, $rep->getId(), null, 7);
|
|
$this->assertFalse($breakdowns->existsForPayment($p2));
|
|
|
|
// دامنه و مالک یکی → کمیسیون ثبت میشود
|
|
$p3 = $this->makePayment('https://' . $rep->getDomain() . '/payment/result');
|
|
$commission->processAppointment($p3, $rep->getId(), $rep->getId(), 7);
|
|
$this->assertTrue($breakdowns->existsForPayment($p3));
|
|
}
|
|
|
|
public function testSubscriptionCommissionUsesSameDomainGuard(): void
|
|
{
|
|
$config = static::getContainer()->get(SiteConfigRepository::class);
|
|
$config->set('upgrade_commission_enabled', '1');
|
|
$config->set('upgrade_commission_percent', '20');
|
|
$commission = static::getContainer()->get(CommissionService::class);
|
|
$breakdowns = static::getContainer()->get(FinancialBreakdownRepository::class);
|
|
|
|
$rep = $this->makeRep('rep-' . uniqid() . '.ir');
|
|
|
|
// نمایندهی دامنه معلوم نیست → بدون کمیسیون (رفتار قدیمی کمیسیون میداد)
|
|
$p1 = $this->makePayment('');
|
|
$commission->processSubscription($p1, $rep->getId(), null, 5, null);
|
|
$this->assertFalse($breakdowns->existsForPayment($p1));
|
|
|
|
// دامنه و مالک یکی → کمیسیون
|
|
$p2 = $this->makePayment('https://' . $rep->getDomain() . '/panel');
|
|
$commission->processSubscription($p2, $rep->getId(), $rep->getId(), 5, null);
|
|
$this->assertTrue($breakdowns->existsForPayment($p2));
|
|
}
|
|
}
|