get('adyen_'.$this->orderId); // Aby když mě to přesměruje na detail a nestihl přijit webhook, naukázal se mi znova platební widget if ($adyenSession['paymentResult'] == \Adyen\Model\Checkout\SessionResultResponse::STATUS_COMPLETED) { return false; } // Když chci změnit metodu, tak tohle přeskočit if (!getVal('rpm')) { // Pokud mám sessionId a není starší pěti minut, použiji ho. if ($adyenSession['sessionId'] && $adyenSession['expired'] > time() - (5 * 60)) { return true; } } $service = new \Adyen\Service\Checkout\PaymentsApi($this->getApiClient()); $createCheckoutSessionRequest = new \Adyen\Model\Checkout\CreateCheckoutSessionRequest(); $createCheckoutSessionRequest->setCountryCode(Contexts::get(\KupShop\KupShopBundle\Context\CountryContext::class)->getActiveId()) ->setMerchantAccount($this->config['merchantAccount']) ->setReturnUrl($this->getGenericPaymentUrl(5)) ->setReference($this->order->order_no.'_'.time()) ->setShopperEmail($this->order->getUserEmail()) ->setShopperLocale($this->getLocale()); $amount = new \Adyen\Model\Checkout\Amount(); $amount->setValue($this->order->getRemainingPayment(true)->mul(DecimalConstants::hundred())->asInteger()) ->setCurrency($this->order->getCurrency()); $createCheckoutSessionRequest->setAmount($amount); $this->kibanaLogger->notice('[Adyen] Create session', [ 'order' => $this->order->order_no, 'amount' => $amount->getValue(), ]); if ($this->method && !getVal('rpm')) { $adyenMethods = [$this->method]; } else { $methods = $this->getAvailableMethods($amount); $adyenMethods = array_values(array_map(fn ($val) => $val['type'], $methods)); } $createCheckoutSessionRequest->setAllowedPaymentMethods($adyenMethods); $items = []; foreach ($this->order->fetchItems() as $item) { $items[] = (new \Adyen\Model\Checkout\LineItem()) ->setQuantity($item['pieces']) ->setTaxPercentage($item['vat']) ->setDescription($item['descr']) ->setAmountIncludingTax($item['total_price']['value_with_vat']->div(toDecimal($item['pieces']))->mul(DecimalConstants::hundred())->asInteger()); } $createCheckoutSessionRequest->setLineItems($items); $adyenSessionRequestResult = $service->sessions($createCheckoutSessionRequest); $session->set('adyen_'.$this->orderId, [ 'sessionId' => $adyenSessionRequestResult->getId(), 'sessionData' => $adyenSessionRequestResult->getSessionData(), 'expired' => time(), 'orderId' => $this->orderId, ] ); return true; } /** Return from gateway */ public function processStep_5() { $sessionId = $this->request->get('sessionId'); $sessionResult = $this->request->get('sessionResult'); if ($sessionResult) { $result = $this->getSessionStatus($sessionId, $sessionResult); } // Z informace redirectResult vubec nic nedostanu. Takze proste zakaznikovi zakazu znova zaplatit a bude se cekat az vysledek dorazi pres webhook. if (($result ?? false) == \Adyen\Model\Checkout\SessionResultResponse::STATUS_COMPLETED || $this->request->get('redirectResult')) { $adyenSession = $this->request->getSession()->get('adyen_'.$this->orderId) ?: []; $this->request->getSession()->set('adyen_'.$this->orderId, $adyenSession + ['paymentResult' => \Adyen\Model\Checkout\SessionResultResponse::STATUS_COMPLETED]); } $this->success(translate('paymentSuccess', 'payment')); } public function getSessionStatus($sessionId, $sessionResult) { $paymentsApi = new \Adyen\Service\Checkout\PaymentsApi($this->getApiClient()); $sessionResultResponse = $paymentsApi->getResultOfPaymentSession($sessionId, ['queryParams' => ['sessionResult' => $sessionResult]]); return $sessionResultResponse->getStatus(); } public function startPayment() { $pathData = ['id' => $this->order->id]; if (!\User::getCurrentUser()) { $pathData['cf'] = $this->order->getSecurityCode(); } redirection(path('payment-redirect', $pathData)); } public function processStep_1() { redirection($this->order->getDetailUrl()); } /** Return from gateway */ public function processStep_10() { $request = json_decode($this->request->getContent() ?? '', true); if (empty($request['notificationItems'])) { $this->error('Not found !!'); } // Setup NotificationReceiver with dependency injection or create an instance as follows $notificationReceiver = new NotificationReceiver(new HmacSignature()); $_SERVER['PHP_AUTH_USER'] = $this->request->headers->get('php-auth-user'); $_SERVER['PHP_AUTH_PW'] = $this->request->headers->get('php-auth-pw'); if (!$notificationReceiver->isAuthenticated( $request['notificationItems'][0]['NotificationRequestItem'], $this->config['merchantAccount'], $this->config['basic_name'], $this->config['basic_pass'] )) { throw new AuthenticationException('Incoming webhook wasn\'t authenticated!'); } foreach ($request['notificationItems'] as $notificationItem) { $notifItem = $notificationItem['NotificationRequestItem']; if ($notificationReceiver->validateHmac($notifItem, $this->config['hmac']) && in_array($notifItem['eventCode'], ['AUTHORISATION', 'REFUND'])) { $isRefund = ($notifItem['eventCode'] == 'REFUND'); $message = ($isRefund ? '[Adyen] Refund payment' : '[Adyen] Incoming payment'); $this->kibanaLogger->notice($message, [ 'notificationItem' => $notifItem, ]); $merchantReference = $notifItem['merchantReference']; $ref = explode('_', $merchantReference); $id_order = ($ref[0] ?? false); if ($notifItem['success'] == 'true') { if ($id_order) { try { $order = Order::createFromDbOrderNo($id_order); $payment_data = [ 'paymentClass' => self::class, 'session' => $notifItem['additionalData']['checkoutSessionId'] ?? null, 'pspReference' => $notifItem['pspReference'] ?? null, ]; $price = $notifItem['amount']['value'] / 100; $note = "Platba modulu {$this->class}"; if ($isRefund) { $price *= -1; $note = "Vrácení platby: objednávka {$order->order_no}, ID platby: {$notifItem['originalReference']}"; $payment_data['originalReference'] = $notifItem['originalReference']; } $order?->insertPayment($price, $note, method: self::METHOD_ONLINE, payment_data: json_encode($payment_data)); if ($order && !empty($notifItem['paymentMethod'])) { $this->setPaymentSubMethod($notifItem['paymentMethod'], $order); } } catch (InvalidArgumentException $exception) { getRaven()->captureException($exception); } } } else { addActivityLog(ActivityLog::SEVERITY_ERROR, ActivityLog::TYPE_COMMUNICATION, "Objednávka {$id_order}: {$message} error: {$notifItem['reason']}", $notifItem, [BankAutoPaymentBundle::LOG_TAG_ADYEN]); } } } $this->sendNotificationResponse(200, '[accepted]'); } public function doReturnPayment(array $payment, float $amount) { if ($paymentPspReference = $payment['payment_data']['pspReference'] ?? null) { $class = new \Adyen\Service\Checkout\ModificationsApi($this->getApiClient()); $paymentRefundRequest = new \Adyen\Model\Checkout\PaymentRefundRequest(); $paymentRefundRequest->setMerchantAccount($this->config['merchantAccount']); $paymentRefundRequest->setReference($this->order->order_no.'_'.time()); $amountCents = (int) floor($amount * -100); // musí být integer v centech $amount = new \Adyen\Model\Checkout\Amount(); $amount->setValue($amountCents)->setCurrency($this->order->getCurrency()); $paymentRefundRequest->setAmount($amount); $paymentRefundResponse = $class->refundCapturedPayment($paymentPspReference, $paymentRefundRequest); if ($paymentRefundResponse->getStatus() == 'received') { // the refund request was successfully received by Adyen - no result yet, // because you receive the outcome of the refund request asynchronously, in a REFUND webhook. // Vrácení platby bylo odesláno na platební bránu. throw new PaymentException(translate('returnSucceed', 'orderPayment'), 'Adyen'); } } // Vrácení platby se nezdařilo, vyřešte, prosím, na platební bráně.); throw new PaymentException(translate('returnFailed', 'orderPayment')); } public function getApiClient(): Adyen\Client { if (!isset($this->apiClient)) { $config = new \Adyen\Config(); $testEnv = (isDevelopment() || ($this->config['test'] ?? '0') == '1'); if (!$testEnv) { $config->set('prefix', $this->config['api_urls_prefix']); } $client = new \Adyen\Client($config); $client->setXApiKey($this->config['apikey']); $client->setEnvironment($testEnv ? \Adyen\Environment::TEST : \Adyen\Environment::LIVE); $client->setTimeout(5); $this->apiClient = $client; } return $this->apiClient; } /** * @throws \Adyen\AdyenException */ public function getAvailableMethods(Adyen\Model\Checkout\Amount|Decimal|null $amount = null) { $countryContext = Contexts::get(\KupShop\KupShopBundle\Context\CountryContext::class); $currencyContext = Contexts::get(\KupShop\KupShopBundle\Context\CurrencyContext::class); $currency = $currencyContext->getActiveId(); $country = $countryContext->getActiveId(); $cacheKey = "adyen-methods-{$currency}-{$country}-{$this->getLocale()}"; if (!$amount) { if ($paymentMethods = getCache($cacheKey)) { return $paymentMethods; } } try { $class = new \Adyen\Service\Checkout\PaymentsApi($this->getApiClient()); $paymentMethodsRequest = new \Adyen\Model\Checkout\PaymentMethodsRequest(); $paymentMethodsRequest->setMerchantAccount($this->config['merchantAccount']); $paymentMethodsRequest->setCountryCode($countryContext->getActiveId()); $paymentMethodsRequest->setShopperLocale($this->getLocale()); if ($amount instanceof Decimal) { $amount = (new \Adyen\Model\Checkout\Amount())->setValue($amount->mul(DecimalConstants::hundred())->asInteger())->setCurrency($currencyContext->getActiveId()); } if ($amount) { $paymentMethodsRequest->setAmount($amount); } $paymentMethodsResponse = $class->paymentMethods($paymentMethodsRequest); $paymentMethods = []; foreach ($paymentMethodsResponse->getPaymentMethods() as $method) { if ($method->getType() == 'scheme') { $images = array_map(function ($brand) { return "https://checkoutshopper-live.adyen.com/checkoutshopper/images/logos/{$brand}.svg"; }, $method->getBrands()); } else { $images = ["https://checkoutshopper-live.adyen.com/checkoutshopper/images/logos/{$method->getType()}.svg"]; } $paymentMethods[$method->getType()] = [ 'name' => $method->getName(), 'type' => $method->getType(), 'images' => $images, ]; } } catch (Exception $e) { addActivityLog(ActivityLog::SEVERITY_ERROR, ActivityLog::TYPE_COMMUNICATION, 'Chyba Adyen při načítání platebních metod: '.$e->getMessage(), ['key' => $cacheKey, 'config' => $this->config], [BankAutoPaymentBundle::LOG_TAG_ADYEN]); return []; } if (!$amount) { setCache($cacheKey, $paymentMethods); } return $paymentMethods; } public function hasOnlinePayment() { return true; } public static function getSettingsConfiguration(): array { return ['fields' => [ 'apikey' => [ 'title' => 'API klíč', 'type' => 'text', ], 'merchantAccount' => [ 'title' => 'Merchant Account', 'type' => 'text', ], 'clientKey' => [ 'title' => 'Client Key', 'type' => 'text', ], 'hmac' => [ 'title' => 'HMAC key', 'type' => 'text', ], 'api_urls_prefix' => [ 'title' => 'API URLs prefix', 'type' => 'text', ], 'basic_name' => [ 'title' => 'Basic auth name', 'type' => 'text', ], 'basic_pass' => [ 'title' => 'Basic auth pass', 'type' => 'text', ], 'test' => [ 'title' => 'Testovací režim', 'type' => 'toggle', ], ]]; } public function getLocale() { $languageContext = Contexts::get(\KupShop\KupShopBundle\Context\LanguageContext::class); return $languageContext->getActive()->getLocale(); } // private function checkWebhooks() // { // Maybe later alligator // // $merchantAccount = $this->config['merchantAccount']; // $webhooksApi = new \Adyen\Service\Management\WebhooksMerchantLevelApi($this->getApiClient()); // $allWebhooks = $webhooksApi->listAllWebhooks($merchantAccount); // // $webhooks = $allWebhooks->getData(); // // if ($webhooks) { // return true; // } // // $createMerchantWebhookRequest = new \Adyen\Model\Management\CreateMerchantWebhookRequest(); // $createMerchantWebhookRequest->setUrl(path('kupshop_ordering_payment_legacypayment', ['class' => 'Adyen', 'step' => 10], \Symfony\Component\Routing\Router::ABSOLUTE_URL)) // ->setDescription('API - wpjshop') // ->setType('standard') // ->setCommunicationFormat('json'); // // $webhooksApi->setUpWebhook($merchantAccount, $createMerchantWebhookRequest); // } }