em->getRepository(SiteConfig::class)->findOneBy(['configKey' => 'payment_test_mode']); if ($cfg === null) { $cfg = new SiteConfig('payment_test_mode', '1'); $this->em->persist($cfg); } else { $cfg->setValue('1'); } $this->em->flush(); } private function makePayment(string $type, string $gateway = 'mock'): Payment { $payment = $this->stampTenant(new Payment($this->createUser(), 50000, $gateway, $type)); $this->em->persist($payment); $this->em->flush(); return $payment; } private function reload(Payment $payment): Payment { $this->em->clear(); return $this->em->getRepository(Payment::class)->find($payment->getId()); } /** @param array $extra */ private function fireCallback(Payment $payment, array $extra = []): void { $this->client->request('POST', PaymentManager::CALLBACK_PATH . '?' . http_build_query(array_merge([ 'order_id' => $payment->getOrderId(), 'mock' => '1', 'ResCode' => '0', 'mock_amount' => '50000', ], $extra))); } /** @return array */ public static function paymentTypeProvider(): array { return [ 'appointment' => [Payment::TYPE_APPOINTMENT], 'subscription' => [Payment::TYPE_SUBSCRIPTION], 'sms wallet' => [Payment::TYPE_SMS_WALLET], ]; } #[\PHPUnit\Framework\Attributes\DataProvider('paymentTypeProvider')] public function testEveryPaymentTypeUsesTheSameCallbackPath(string $type): void { $this->enableTestMode(); $payment = $this->makePayment($type); $url = static::getContainer()->get(PaymentManager::class)->callbackUrl($payment); $this->assertStringContainsString(PaymentManager::CALLBACK_PATH . '?', $url); $this->assertStringNotContainsString('/subscription-payment/', $url); $this->assertStringContainsString('gateway=mock', $url); $this->assertStringContainsString('order_id=' . $payment->getOrderId(), $url); } public function testCallbackAcceptsGatewayAsQueryParam(): void { $this->enableTestMode(); $payment = $this->makePayment(Payment::TYPE_SMS_WALLET); $this->fireCallback($payment, ['gateway' => 'mock']); $this->assertSame(Payment::STATUS_SUCCESS, $this->reload($payment)->getStatus()); } public function testCallbackFallsBackToTheGatewayStoredOnThePayment(): void { $this->enableTestMode(); $payment = $this->makePayment(Payment::TYPE_SMS_WALLET); $this->fireCallback($payment); $this->assertSame(Payment::STATUS_SUCCESS, $this->reload($payment)->getStatus()); } public function testUnknownOrderWithoutGatewayIsNotFound(): void { $this->enableTestMode(); $this->client->request('POST', PaymentManager::CALLBACK_PATH . '?' . http_build_query([ 'order_id' => 'ORD-DOES-NOT-EXIST', 'mock' => '1', 'ResCode' => '0', ])); $this->assertSame(200, $this->client->getResponse()->getStatusCode()); $this->assertStringContainsString('یافت نشد', (string) $this->client->getResponse()->getContent()); } public function testRemovedLegacyCallbackRoutesReturn404(): void { $this->enableTestMode(); $payment = $this->makePayment(Payment::TYPE_SUBSCRIPTION); $query = '?' . http_build_query(['order_id' => $payment->getOrderId()]); foreach (['/api/v1/payment/callback/mock', '/api/v1/subscription-payment/callback/mock'] as $legacy) { $this->client->request('POST', $legacy . $query); $this->assertSame(404, $this->client->getResponse()->getStatusCode(), $legacy); } } }