diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 070503ac..9a5147b6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,15 +9,15 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - + - name: Validate composer.json and composer.lock run: composer validate - + - name: Install dependencies run: composer install --prefer-dist --no-progress - name: Run PHP Code Sniffer - run: vendor/bin/phpcs --ignore=*vendor/ --ignore=AdyenPayment.php --ignore=Controllers --standard=PSR2 . + run: vendor/bin/phpcs . - name: Make sure project files are compilable run: find -L . -path ./vendor -prune -o -path ./tests -prune -o -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l diff --git a/AdyenPayment.php b/AdyenPayment.php index c6c8ab90..b73ebb55 100644 --- a/AdyenPayment.php +++ b/AdyenPayment.php @@ -1,5 +1,7 @@ configuration->isPaymentmethodsCacheEnabled(); $cacheKey = $this->getCacheKey($countryCode ?? '', $currency ?? '', (string)$value ?? ''); if ($cache && isset($this->cache[$cacheKey])) { return $this->cache[$cacheKey]; @@ -88,7 +89,13 @@ public function getPaymentMethods( try { $paymentMethods = $checkout->paymentMethods($requestParams); } catch (AdyenException $e) { - $this->logger->critical($e); + $this->logger->critical('Adyen Exception', [ + 'message' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'errorType' => $e->getErrorType(), + 'status' => $e->getStatus() + ]); return []; } diff --git a/Components/Adyen/RefundService.php b/Components/Adyen/RefundService.php index d274bbc1..476c3c76 100644 --- a/Components/Adyen/RefundService.php +++ b/Components/Adyen/RefundService.php @@ -7,6 +7,7 @@ use Adyen\AdyenException; use Adyen\Service\Modification; use AdyenPayment\Components\NotificationManager; +use AdyenPayment\Models\PaymentInfo; use AdyenPayment\Models\Refund; use Shopware\Components\Model\ModelManager; use Shopware\Models\Order\Order; @@ -27,6 +28,10 @@ class RefundService * @var NotificationManager */ private $notificationManager; + /** + * @var \Doctrine\Common\Persistence\ObjectRepository|\Doctrine\ORM\EntityRepository + */ + private $paymentInfoRepository; /** * PaymentMethodService constructor. @@ -42,6 +47,7 @@ public function __construct( $this->apiFactory = $apiFactory; $this->modelManager = $modelManager; $this->notificationManager = $notificationManager; + $this->paymentInfoRepository = $modelManager->getRepository(PaymentInfo::class); } /** @@ -53,11 +59,23 @@ public function __construct( */ public function doRefund(int $orderId): Refund { + /** @var Order $order */ $order = $this->modelManager->find(Order::class, $orderId); $apiClient = $this->apiFactory->create($order->getShop()); $modification = new Modification($apiClient); - $notification = $this->notificationManager->getLastNotificationForOrderId($orderId); + /** @var PaymentInfo $paymentInfo */ + $paymentInfo = $this->paymentInfoRepository->findOneBy([ + 'orderId' => $orderId + ]); + + if ($paymentInfo && !empty($paymentInfo->getPspReference())) { + $notification = $this->notificationManager->getLastNotificationForPspReference( + $paymentInfo->getPspReference() + ); + } else { + $notification = $this->notificationManager->getLastNotificationForOrderId($orderId); + } $request = [ 'originalReference' => $notification->getPspReference(), diff --git a/Components/BasketService.php b/Components/BasketService.php index 309b4546..14c4520e 100644 --- a/Components/BasketService.php +++ b/Components/BasketService.php @@ -118,6 +118,11 @@ public function restoreFromOrder(Order $order) foreach ($orderDetails as $orderDetail) { $this->processOrderDetail($order, $orderDetail); } + + $this->events->notify(Event::BASKET_RESTORE_FROM_ORDER, [ + 'order' => $order + ]); + $this->sBasket->sRefreshBasket(); } diff --git a/Components/Configuration.php b/Components/Configuration.php index 1cb045bf..baeec468 100644 --- a/Components/Configuration.php +++ b/Components/Configuration.php @@ -46,13 +46,18 @@ public function __construct( * @param bool $shop * @return string */ - public function getEnvironment($shop = false): string + public function getEnvironment($shop = false, $lowercase = false): string { + $environment = Environment::TEST; if ($this->getConfig('environment', $shop) === self::ENV_LIVE) { - return Environment::LIVE; + $environment = Environment::LIVE; } - return Environment::TEST; + if ($lowercase) { + return strtolower($environment); + } + + return $environment; } /** @@ -97,22 +102,16 @@ public function getConfig($key = null, $shop = false) return null; } - /** - * @param bool|Shop $shop - * @return string - */ - public function getJsComponents3DS2ChallengeImageSize($shop = false): string - { - return (string)$this->getConfig('js_components_3DS2_challenge_image_size', $shop); - } - /** * @param bool|Shop $shop * @return string */ public function getApiKey($shop = false): string { - return (string)$this->getConfig('api_key', $shop); + return (string)$this->getConfig( + 'api_key_' . $this->getEnvironment($shop, true), + $shop + ); } /** @@ -139,7 +138,10 @@ public function getOriginKey($shop = false): string */ public function getNotificationHmac($shop = false): string { - return (string)$this->getConfig('notification_hmac', $shop); + return (string)$this->getConfig( + 'notification_hmac_' . $this->getEnvironment($shop, true), + $shop + ); } /** @@ -148,7 +150,10 @@ public function getNotificationHmac($shop = false): string */ public function getNotificationAuthUsername($shop = false): string { - return (string)$this->getConfig('notification_auth_username', $shop); + return (string)$this->getConfig( + 'notification_auth_username_' . $this->getEnvironment($shop, true), + $shop + ); } /** @@ -157,7 +162,10 @@ public function getNotificationAuthUsername($shop = false): string */ public function getNotificationAuthPassword($shop = false): string { - return (string)$this->getConfig('notification_auth_password', $shop); + return (string)$this->getConfig( + 'notification_auth_password_' . $this->getEnvironment($shop, true), + $shop + ); } /** @@ -169,6 +177,15 @@ public function getGoogleMerchantId($shop = false): string return (string)$this->getConfig('google_merchant_id', $shop); } + /** + * @param bool $shop + * @return bool + */ + public function isPaymentmethodsCacheEnabled($shop = false): bool + { + return (bool)$this->getConfig('paymentmethods_cache', $shop); + } + /** * @return string */ diff --git a/Components/NotificationManager.php b/Components/NotificationManager.php index 931f62b3..678078e4 100644 --- a/Components/NotificationManager.php +++ b/Components/NotificationManager.php @@ -77,4 +77,25 @@ public function getLastNotificationForOrderId(int $orderId) return null; } } + + /** + * @param string $pspReference + * @return mixed|null + * @throws NonUniqueResultException + */ + public function getLastNotificationForPspReference(string $pspReference) + { + try { + $lastNotification = $this->notificationRepository->createQueryBuilder('n') + ->where('n.pspReference = :pspReference') + ->setMaxResults(1) + ->orderBy('n.createdAt', 'ASC') + ->setParameter('pspReference', $pspReference) + ->getQuery() + ->getSingleResult(); + return $lastNotification; + } catch (NoResultException $ex) { + return null; + } + } } diff --git a/Components/NotificationProcessor.php b/Components/NotificationProcessor.php index 7a316eae..734b7782 100644 --- a/Components/NotificationProcessor.php +++ b/Components/NotificationProcessor.php @@ -136,7 +136,11 @@ private function process(Notification $notification) } catch (\Exception $exception) { $status = NotificationStatus::STATUS_FATAL; $this->logger->notice('General Exception', [ - 'exception' => $exception, + 'exception' => [ + 'message' => $exception->getMessage(), + 'file' => $exception->getFile(), + 'line' => $exception->getLine() + ], 'notificationId' => $notification->getId() ]); yield new NotificationProcessorFeedback( diff --git a/Components/NotificationProcessor/Authorisation.php b/Components/NotificationProcessor/Authorisation.php index 3757c81a..b3f500ef 100644 --- a/Components/NotificationProcessor/Authorisation.php +++ b/Components/NotificationProcessor/Authorisation.php @@ -5,8 +5,10 @@ use AdyenPayment\Components\PaymentStatusUpdate; use AdyenPayment\Models\Event; use AdyenPayment\Models\Notification; +use AdyenPayment\Models\PaymentInfo; use Psr\Log\LoggerInterface; use Shopware\Components\ContainerAwareEventManager; +use Shopware\Components\Model\ModelManager; use Shopware\Models\Order\Status; /** @@ -29,6 +31,14 @@ class Authorisation implements NotificationProcessorInterface * @var PaymentStatusUpdate */ private $paymentStatusUpdate; + /** + * @var ModelManager + */ + private $modelManager; + /** + * @var \Doctrine\Common\Persistence\ObjectRepository|\Doctrine\ORM\EntityRepository + */ + private $paymentInfoRepository; /** * Authorisation constructor. @@ -39,11 +49,14 @@ class Authorisation implements NotificationProcessorInterface public function __construct( LoggerInterface $logger, ContainerAwareEventManager $eventManager, - PaymentStatusUpdate $paymentStatusUpdate + PaymentStatusUpdate $paymentStatusUpdate, + ModelManager $modelManager ) { $this->logger = $logger; $this->eventManager = $eventManager; $this->paymentStatusUpdate = $paymentStatusUpdate->setLogger($this->logger); + $this->modelManager = $modelManager; + $this->paymentInfoRepository = $modelManager->getRepository(PaymentInfo::class); } /** @@ -78,9 +91,20 @@ public function process(Notification $notification) ); $status = $notification->isSuccess() ? - Status::PAYMENT_STATE_THE_CREDIT_HAS_BEEN_ACCEPTED : + Status::PAYMENT_STATE_COMPLETELY_PAID : Status::PAYMENT_STATE_THE_PROCESS_HAS_BEEN_CANCELLED; $this->paymentStatusUpdate->updatePaymentStatus($order, $status); + + if ($notification->isSuccess()) { + /** @var PaymentInfo $paymentInfo */ + $paymentInfo = $this->paymentInfoRepository->findOneBy([ + 'orderId' => $order->getId() + ]); + + $paymentInfo->setPspReference($notification->getPspReference()); + $this->modelManager->persist($paymentInfo); + $this->modelManager->flush($paymentInfo); + } } } diff --git a/Components/NotificationProcessor/Capture.php b/Components/NotificationProcessor/Capture.php index 33b69e4d..4bde5bac 100644 --- a/Components/NotificationProcessor/Capture.php +++ b/Components/NotificationProcessor/Capture.php @@ -2,6 +2,7 @@ namespace AdyenPayment\Components\NotificationProcessor; +use AdyenPayment\Models\PaymentInfo; use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\ORMException; use Doctrine\ORM\TransactionRequiredException; @@ -11,6 +12,7 @@ use AdyenPayment\Models\Notification; use Psr\Log\LoggerInterface; use Shopware\Components\ContainerAwareEventManager; +use Shopware\Components\Model\ModelManager; use Shopware\Models\Order\Status; /** @@ -33,6 +35,14 @@ class Capture implements NotificationProcessorInterface * @var PaymentStatusUpdate */ private $paymentStatusUpdate; + /** + * @var ModelManager + */ + private $modelManager; + /** + * @var \Doctrine\Common\Persistence\ObjectRepository|\Doctrine\ORM\EntityRepository + */ + private $paymentInfoRepository; /** @@ -44,11 +54,14 @@ class Capture implements NotificationProcessorInterface public function __construct( LoggerInterface $logger, ContainerAwareEventManager $eventManager, - PaymentStatusUpdate $paymentStatusUpdate + PaymentStatusUpdate $paymentStatusUpdate, + ModelManager $modelManager ) { $this->logger = $logger; $this->eventManager = $eventManager; $this->paymentStatusUpdate = $paymentStatusUpdate->setLogger($this->logger); + $this->modelManager = $modelManager; + $this->paymentInfoRepository = $modelManager->getRepository(PaymentInfo::class); } /** @@ -85,8 +98,17 @@ public function process(Notification $notification) if ($notification->isSuccess()) { $this->paymentStatusUpdate->updatePaymentStatus( $order, - Status::PAYMENT_STATE_THE_CREDIT_HAS_BEEN_ACCEPTED + Status::PAYMENT_STATE_COMPLETELY_PAID ); + + /** @var PaymentInfo $paymentInfo */ + $paymentInfo = $this->paymentInfoRepository->findOneBy([ + 'orderId' => $order->getId() + ]); + + $paymentInfo->setPspReference($notification->getPspReference()); + $this->modelManager->persist($paymentInfo); + $this->modelManager->flush($paymentInfo); } } } diff --git a/Components/NotificationProcessor/ChargebackReversed.php b/Components/NotificationProcessor/ChargebackReversed.php index f2d1178d..d67473ef 100644 --- a/Components/NotificationProcessor/ChargebackReversed.php +++ b/Components/NotificationProcessor/ChargebackReversed.php @@ -85,6 +85,6 @@ public function process(Notification $notification) ] ); - $this->paymentStatusUpdate->updatePaymentStatus($order, Status::PAYMENT_STATE_THE_CREDIT_HAS_BEEN_ACCEPTED); + $this->paymentStatusUpdate->updatePaymentStatus($order, Status::PAYMENT_STATE_COMPLETELY_PAID); } } diff --git a/Components/NotificationProcessor/OfferClosed.php b/Components/NotificationProcessor/OfferClosed.php new file mode 100644 index 00000000..717f01a1 --- /dev/null +++ b/Components/NotificationProcessor/OfferClosed.php @@ -0,0 +1,82 @@ +logger = $logger; + $this->eventManager = $eventManager; + $this->paymentStatusUpdate = $paymentStatusUpdate->setLogger($this->logger); + } + + /** + * Returns boolean on whether this processor can process the Notification object + * + * @param Notification $notification + * @return boolean + */ + public function supports(Notification $notification): bool + { + return strtoupper($notification->getEventCode()) === self::EVENT_CODE; + } + + /** + * Actual processing of the notification + * + * @param Notification $notification + * @throws \Doctrine\ORM\ORMException + * @throws \Doctrine\ORM\OptimisticLockException + * @throws \Doctrine\ORM\TransactionRequiredException + * @throws \Enlight_Event_Exception + */ + public function process(Notification $notification) + { + $order = $notification->getOrder(); + + $this->eventManager->notify( + Event::NOTIFICATION_PROCESS_OFFER_CLOSED, + [ + 'order' => $order, + 'notification' => $notification + ] + ); + + if ($notification->isSuccess()) { + $this->paymentStatusUpdate->updateOrderStatus( + $order, + Status::ORDER_STATE_CANCELLED_REJECTED + ); + $this->paymentStatusUpdate->updatePaymentStatus( + $order, + Status::PAYMENT_STATE_THE_PROCESS_HAS_BEEN_CANCELLED + ); + } + } +} diff --git a/Components/NotificationProcessor/RefundedReversed.php b/Components/NotificationProcessor/RefundedReversed.php index 40c03afa..57760fb1 100644 --- a/Components/NotificationProcessor/RefundedReversed.php +++ b/Components/NotificationProcessor/RefundedReversed.php @@ -78,6 +78,6 @@ public function process(Notification $notification) ] ); - $this->paymentStatusUpdate->updatePaymentStatus($order, Status::PAYMENT_STATE_THE_CREDIT_HAS_BEEN_ACCEPTED); + $this->paymentStatusUpdate->updatePaymentStatus($order, Status::PAYMENT_STATE_COMPLETELY_PAID); } } diff --git a/Components/Payload/Providers/ApplicationInfoProvider.php b/Components/Payload/Providers/ApplicationInfoProvider.php index 55159842..bdd25af8 100644 --- a/Components/Payload/Providers/ApplicationInfoProvider.php +++ b/Components/Payload/Providers/ApplicationInfoProvider.php @@ -8,6 +8,7 @@ use AdyenPayment\AdyenPayment; use Shopware\Components\Model\ModelManager; use Shopware\Models\Plugin\Plugin; +use AdyenPayment\Models\Enum\Channel; /** * Class ApplicationInfoProvider @@ -48,7 +49,7 @@ public function provide(PaymentContext $context): array 'executeThreeD' => true, 'allow3DS2' => true, ], - "channel" => "Web", + "channel" => Channel::WEB, 'origin' => $context->getOrigin(), 'returnUrl' => $returnUrl, 'merchantAccount' => $this->configuration->getMerchantAccount(), diff --git a/Components/Payload/Providers/BrowserInfoProvider.php b/Components/Payload/Providers/BrowserInfoProvider.php index 2d76877d..098737e5 100644 --- a/Components/Payload/Providers/BrowserInfoProvider.php +++ b/Components/Payload/Providers/BrowserInfoProvider.php @@ -17,9 +17,11 @@ class BrowserInfoProvider implements PaymentPayloadProvider */ public function provide(PaymentContext $context): array { - $browserInfo = [ - 'acceptHeader' => $_SERVER['HTTP_ACCEPT'] ?? '', - ]; + $browserInfo = []; + + if (!empty($_SERVER['HTTP_ACCEPT'])) { + $browserInfo['acceptHeader'] = $_SERVER['HTTP_ACCEPT']; + } return [ 'browserInfo' => array_merge($browserInfo, $context->getBrowserInfo()), diff --git a/Components/Payload/Providers/ShopperInfoProvider.php b/Components/Payload/Providers/ShopperInfoProvider.php index b45785f9..005abe81 100644 --- a/Components/Payload/Providers/ShopperInfoProvider.php +++ b/Components/Payload/Providers/ShopperInfoProvider.php @@ -31,7 +31,7 @@ public function provide(PaymentContext $context): array 'billingAddress' => [ 'city' => $context->getOrder()->getBilling()->getCity(), 'country' => $context->getOrder()->getBilling()->getCountry()->getIso(), - 'houseNumberOrName' => $context->getOrder()->getBilling()->getNumber(), + 'houseNumberOrName' => 'N/A', 'postalCode' => $context->getOrder()->getBilling()->getZipCode(), 'street' => $context->getOrder()->getBilling()->getStreet(), ], diff --git a/Components/PaymentMethodService.php b/Components/PaymentMethodService.php index 26b439ea..255177bb 100644 --- a/Components/PaymentMethodService.php +++ b/Components/PaymentMethodService.php @@ -18,6 +18,12 @@ */ class PaymentMethodService { + + const PM_LOGO_FILENAME = [ + 'scheme' => 'card', + 'yandex_money' => 'yandex' + ]; + /** * @var ModelManager */ @@ -203,8 +209,9 @@ public function getAdyenImage($adyenMethod) */ public function getAdyenImageByType($type) { - if ($type === 'scheme') { - $type = 'card'; + //Some payment method codes don't match the logo filename + if (!empty(self::PM_LOGO_FILENAME[$type])) { + $type = self::PM_LOGO_FILENAME[$type]; } return sprintf('https://checkoutshopper-live.adyen.com/checkoutshopper/images/logos/%s.svg', $type); } diff --git a/Components/PaymentStatusUpdate.php b/Components/PaymentStatusUpdate.php index b836071d..11145cb4 100644 --- a/Components/PaymentStatusUpdate.php +++ b/Components/PaymentStatusUpdate.php @@ -31,6 +31,30 @@ public function __construct( $this->modelManager = $modelManager; } + /** + * @param Order $order + * @param int $statusId + * @throws \Doctrine\ORM\ORMException + * @throws \Doctrine\ORM\OptimisticLockException + * @throws \Doctrine\ORM\TransactionRequiredException + */ + public function updateOrderStatus(Order $order, int $statusId) + { + $orderStatus = $this->modelManager->find(Status::class, $statusId); + + if ($this->logger) { + $this->logger->debug('Update order status', [ + 'number' => $order->getNumber(), + 'oldStatus' => $order->getOrderStatus()->getName(), + 'newStatus' => $orderStatus->getName() + ]); + } + + $order->setOrderStatus($orderStatus); + $this->modelManager->persist($order); + $this->modelManager->flush(); + } + /** * @param Order $order * @param int $statusId diff --git a/Components/ShopwareVersionCheck.php b/Components/ShopwareVersionCheck.php index fc80a0a5..dad5fb9b 100644 --- a/Components/ShopwareVersionCheck.php +++ b/Components/ShopwareVersionCheck.php @@ -45,7 +45,11 @@ public function isHigherThanShopwareVersion(string $shopwareVersion): bool list($composerVersion, $sha) = explode('@', Versions::getVersion('shopware/shopware')); $version = $composerVersion; } catch (OutOfBoundsException $ex) { - $this->logger->error($ex); + $this->logger->error('OutOfBoundsException', [ + 'message' => $ex->getMessage(), + 'file' => $ex->getFile(), + 'line' => $ex->getLine() + ]); } } diff --git a/Controllers/Backend/AdyenPaymentNotificationsListingExtension.php b/Controllers/Backend/AdyenPaymentNotificationsListingExtension.php index 08a89ff0..361a3afd 100644 --- a/Controllers/Backend/AdyenPaymentNotificationsListingExtension.php +++ b/Controllers/Backend/AdyenPaymentNotificationsListingExtension.php @@ -3,6 +3,7 @@ use AdyenPayment\Models\Enum\NotificationStatus; use AdyenPayment\Models\Notification; +//phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace, Squiz.Classes.ValidClassName.NotCamelCaps, Generic.Files.LineLength.TooLong class Shopware_Controllers_Backend_AdyenPaymentNotificationsListingExtension extends Shopware_Controllers_Backend_Application { protected $model = Notification::class; diff --git a/Controllers/Backend/AdyenPaymentRefund.php b/Controllers/Backend/AdyenPaymentRefund.php index 4c5fa6de..b2e83b41 100644 --- a/Controllers/Backend/AdyenPaymentRefund.php +++ b/Controllers/Backend/AdyenPaymentRefund.php @@ -2,6 +2,7 @@ use Shopware\Components\CSRFWhitelistAware; +//phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace, Squiz.Classes.ValidClassName.NotCamelCaps, Generic.Files.LineLength.TooLong class Shopware_Controllers_Backend_AdyenPaymentRefund extends Shopware_Controllers_Backend_ExtJs implements CSRFWhitelistAware { public function refundAction() diff --git a/Controllers/Backend/TestAdyenApi.php b/Controllers/Backend/TestAdyenApi.php index a5badba8..6fc98982 100644 --- a/Controllers/Backend/TestAdyenApi.php +++ b/Controllers/Backend/TestAdyenApi.php @@ -2,6 +2,7 @@ use Symfony\Component\HttpFoundation\Response; +//phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace, Squiz.Classes.ValidClassName.NotCamelCaps class Shopware_Controllers_Backend_TestAdyenApi extends Shopware_Controllers_Backend_ExtJs { public function runAction() @@ -10,16 +11,20 @@ public function runAction() $configuration = $this->get('adyen_payment.components.configuration'); $responseText = 'Adyen API failed, check error logs'; - $this->response->setHttpResponseCode(Response::HTTP_INTERNAL_SERVER_ERROR); + $this->response->setHttpResponseCode(Response::HTTP_BAD_REQUEST); if (empty($configuration->getApiKey()) || empty($configuration->getMerchantAccount())) { - $this->response->setHttpResponseCode(Response::HTTP_INTERNAL_SERVER_ERROR); + $this->response->setHttpResponseCode(Response::HTTP_BAD_REQUEST); $responseText = 'Missing API configuration. Save the configuration form before testing'; } - if (!empty($paymentMethodService->getPaymentMethods('BE', 'EUR', 20, 'nl_NL', false))) { - $this->response->setHttpResponseCode(Response::HTTP_OK); - $responseText = 'Adyen API connected'; + try { + if (!empty($paymentMethodService->getPaymentMethods('BE', 'EUR', 20, 'nl_NL', false))) { + $this->response->setHttpResponseCode(Response::HTTP_OK); + $responseText = 'Adyen API connected'; + } + } catch (\Exception $exception) { + $responseText = 'Adyen API failed, check error logs'; } $this->View()->assign('responseText', $responseText); diff --git a/Controllers/Frontend/Adyen.php b/Controllers/Frontend/Adyen.php index a0ee2b19..f31c17fd 100644 --- a/Controllers/Frontend/Adyen.php +++ b/Controllers/Frontend/Adyen.php @@ -21,6 +21,7 @@ /** * Class Shopware_Controllers_Frontend_Adyen */ +//phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace, Squiz.Classes.ValidClassName.NotCamelCaps class Shopware_Controllers_Frontend_Adyen extends Shopware_Controllers_Frontend_Payment { /** @@ -92,12 +93,17 @@ public function ajaxDoPaymentAction() 'content' => $paymentInfo ] )); - } catch (\Adyen\AdyenException $e) { - $this->logger->debug($e); + } catch (\Adyen\AdyenException $ex) { + $this->logger->debug('AdyenException during doPayment', [ + 'message' => $ex->getMessage(), + 'file' => $ex->getFile(), + 'line' => $ex->getLine() + ]); + $this->Response()->setBody(json_encode( [ 'status' => 'error', - 'content' => $e->getMessage() + 'content' => $ex->getMessage() ] )); } diff --git a/Controllers/Frontend/Notification.php b/Controllers/Frontend/Notification.php index ee0f0366..101fdd93 100644 --- a/Controllers/Frontend/Notification.php +++ b/Controllers/Frontend/Notification.php @@ -8,6 +8,7 @@ use Shopware\Components\ContainerAwareEventManager; use Shopware\Components\CSRFWhitelistAware; +//phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace, Squiz.Classes.ValidClassName.NotCamelCaps, Generic.Files.LineLength.TooLong class Shopware_Controllers_Frontend_Notification extends Shopware_Controllers_Frontend_Payment implements CSRFWhitelistAware { /** diff --git a/Controllers/Frontend/Process.php b/Controllers/Frontend/Process.php index 54d8fe6e..26fb3dc0 100644 --- a/Controllers/Frontend/Process.php +++ b/Controllers/Frontend/Process.php @@ -10,6 +10,7 @@ /** * Class Redirect */ +//phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace, Squiz.Classes.ValidClassName.NotCamelCaps class Shopware_Controllers_Frontend_Process extends Shopware_Controllers_Frontend_Payment implements CSRFWhitelistAware { /** @@ -111,18 +112,17 @@ private function handleReturnResult($result) } switch ($result['resultCode']) { - case 'Authorised': - case 'Pending': - case 'Received': + case PaymentResultCodes::AUTHORISED: + case PaymentResultCodes::PENDING: + case PaymentResultCodes::RECEIVED: $paymentStatus = $this->getModelManager()->find( Status::class, Status::PAYMENT_STATE_THE_PAYMENT_HAS_BEEN_ORDERED ); break; - case 'Cancelled': - case 'Error': - case 'Fail': - case 'Refused': + case PaymentResultCodes::CANCELLED: + case PaymentResultCodes::ERROR: + case PaymentResultCodes::REFUSED: $paymentStatus = $this->getModelManager()->find( Status::class, Status::PAYMENT_STATE_THE_PROCESS_HAS_BEEN_CANCELLED diff --git a/Models/Event.php b/Models/Event.php index 1ba666a1..090868fe 100644 --- a/Models/Event.php +++ b/Models/Event.php @@ -17,12 +17,14 @@ class Event const NOTIFICATION_PROCESS_CANCELLATION = 'Adyen_Notification_Process_Cancellation'; const NOTIFICATION_PROCESS_CAPTURE = 'Adyen_Notification_Process_Capture'; const NOTIFICATION_PROCESS_CAPTURE_FAILED = 'Adyen_Notification_Process_CaptureFailed'; + const NOTIFICATION_PROCESS_OFFER_CLOSED = 'Adyen_Notification_Process_OfferClosed'; const NOTIFICATION_PROCESS_REFUND = 'Adyen_Notification_Process_Refund'; const NOTIFICATION_PROCESS_REFUND_FAILED = 'Adyen_Notification_Process_RefundFailed'; const NOTIFICATION_PROCESS_REFUNDED_REVERSED = 'Adyen_Notification_Process_RefundedReversed'; const NOTIFICATION_PROCESS_CHARGEBACK = 'Adyen_Notification_Process_Chargeback'; const NOTIFICATION_PROCESS_CHARGEBACK_REVERSED = 'Adyen_Notification_Process_ChargebackReversed'; + const BASKET_RESTORE_FROM_ORDER = 'Adyen_Basket_RestoreFromOrder'; const BASKET_BEFORE_PROCESS_ORDER_DETAIL = 'Adyen_Basket_Before_ProcessOrderDetail'; const BASKET_STOPPED_PROCESS_ORDER_DETAIL = 'Adyen_Basket_Stopped_ProcessOrderDetail'; const BASKET_AFTER_PROCESS_ORDER_DETAIL = 'Adyen_Basket_After_ProcessOrderDetail'; diff --git a/Models/ShopwareInfo.php b/Models/ShopwareInfo.php deleted file mode 100644 index f0d045ca..00000000 --- a/Models/ShopwareInfo.php +++ /dev/null @@ -1,52 +0,0 @@ -Merchant account - api_key - + api_key_test + + + + api_key_live + api_url_prefix - notification_hmac - + notification_hmac_test + - notification_auth_username - + notification_auth_username_test + - notification_auth_password - + notification_auth_password_test + - - js_components_3DS2_challenge_image_size - - - - - - - - + + notification_hmac_live + + + + notification_auth_username_live + + + + notification_auth_password_live + google_merchant_id + + paymentmethods_cache + + Caches the payment methods active in Adyen Customer Area for better performance. + testAPIconnection - - - + + + diff --git a/Resources/frontend/js/jquery.adyen-confirm-order.js b/Resources/frontend/js/jquery.adyen-confirm-order.js index 935c7b99..f1d31aa3 100644 --- a/Resources/frontend/js/jquery.adyen-confirm-order.js +++ b/Resources/frontend/js/jquery.adyen-confirm-order.js @@ -10,7 +10,6 @@ confirmFormSelector: '#confirm--form', mountRedirectSelector: '.is--act-confirm', adyenType: '', - adyen3ds2challengeimagesize: '', adyenGoogleConfig: {}, adyenSetSession: {}, adyenAjaxDoPaymentUrl: '/frontend/adyen/ajaxDoPayment', @@ -179,8 +178,7 @@ }, onError: function (error) { console.log(error); - }, - size: me.getThreeDS2ChallengeSize(), + } }) .mount('#AdyenChallengeShopperThreeDS2'); }, @@ -246,11 +244,6 @@ this.addAdyenError(me.opts.adyenSnippets.errorGooglePayNotAvailable); }); }, - getThreeDS2ChallengeSize: function () { - var me = this; - - return '0' + me.opts.adyen3ds2challengeimagesize; - }, addAdyenError: function (message) { var me = this; $.publish('plugin/AdyenPaymentCheckoutError/addError', message); @@ -316,4 +309,4 @@ }, }); -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/Resources/frontend/js/jquery.adyen-payment-selection.js b/Resources/frontend/js/jquery.adyen-payment-selection.js index de12fa1b..fad6e826 100644 --- a/Resources/frontend/js/jquery.adyen-payment-selection.js +++ b/Resources/frontend/js/jquery.adyen-payment-selection.js @@ -148,9 +148,9 @@ getPaymentMethodByType(type) { var me = this; - type = type.split(me.opts.adyenPaymentMethodPrefix).pop(); + var pmType = type.split(me.opts.adyenPaymentMethodPrefix).pop(); return me.opts.adyenPaymentMethodsResponse['paymentMethods'].find(function (paymentMethod) { - return paymentMethod.type === type + return paymentMethod.type === pmType }); }, setCheckout: function () { @@ -296,4 +296,4 @@ }, }); -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/Resources/services/components.xml b/Resources/services/components.xml index eb3857a5..0b109363 100644 --- a/Resources/services/components.xml +++ b/Resources/services/components.xml @@ -115,6 +115,13 @@ + + + + + + diff --git a/Resources/views/frontend/checkout/confirm.tpl b/Resources/views/frontend/checkout/confirm.tpl index b1e2d9f1..ef8472ab 100644 --- a/Resources/views/frontend/checkout/confirm.tpl +++ b/Resources/views/frontend/checkout/confirm.tpl @@ -31,9 +31,6 @@ {if $sAdyenGoogleConfig} data-adyenGoogleConfig='{$sAdyenGoogleConfig}' {/if} - {if $sAdyenConfig} - data-adyen3DS2ChallengeImageSize='{$sAdyenConfig.jsComponents3DS2ChallengeImageSize}' - {/if} {if $sAdyenSetSession} data-adyenSetSession='{$sAdyenSetSession}' {/if} @@ -46,4 +43,4 @@
{$smarty.block.parent} -{/block} \ No newline at end of file +{/block} diff --git a/Subscriber/BackendConfigSubscriber.php b/Subscriber/BackendConfigSubscriber.php index 91063bc0..783b583f 100644 --- a/Subscriber/BackendConfigSubscriber.php +++ b/Subscriber/BackendConfigSubscriber.php @@ -67,8 +67,12 @@ public function onBackendConfig(\Enlight_Event_EventArgs $args) ) { try { $this->originKeysService->generateAndSave(); - } catch (AdyenException $e) { - $this->logger->error($e); + } catch (AdyenException $ex) { + $this->logger->error('AdyenException on Backend Config', [ + 'message' => $ex->getMessage(), + 'file' => $ex->getFile(), + 'line' => $ex->getLine() + ]); } if ($this->shopwareVersionCheck->isHigherThanShopwareVersion('v5.5.6')) { diff --git a/Subscriber/CheckoutSubscriber.php b/Subscriber/CheckoutSubscriber.php index f2d52dd5..aec4f8f2 100644 --- a/Subscriber/CheckoutSubscriber.php +++ b/Subscriber/CheckoutSubscriber.php @@ -139,7 +139,6 @@ public function checkoutFrontendPostDispatch(Enlight_Event_EventArgs $args) $this->checkFirstCheckoutStep($args); $this->rewritePaymentData($args); $this->addAdyenConfigOnShipping($args); - $this->addAdyenConfigOnConfirm($args); $this->addAdyenSnippets($args); $this->addAdyenGooglePay($args); } @@ -213,32 +212,11 @@ private function addAdyenConfigOnShipping(Enlight_Event_EventArgs $args) "environment" => $this->configuration->getEnvironment($shop), "paymentMethods" => json_encode($paymentMethods), "paymentMethodPrefix" => $this->configuration->getPaymentMethodPrefix($shop), - "jsComponents3DS2ChallengeImageSize" => $this->configuration->getJsComponents3DS2ChallengeImageSize($shop), ]; $view->assign('sAdyenConfig', $adyenConfig); } - - /** - * @param Enlight_Event_EventArgs $args - */ - private function addAdyenConfigOnConfirm(Enlight_Event_EventArgs $args) - { - /** @var Shopware_Controllers_Frontend_Checkout $subject */ - $subject = $args->getSubject(); - - if (!in_array($subject->Request()->getActionName(), ['confirm'])) { - return; - } - - $adyenConfig = [ - "jsComponents3DS2ChallengeImageSize" => $this->configuration->getJsComponents3DS2ChallengeImageSize(), - ]; - - $subject->View()->assign('sAdyenConfig', $adyenConfig); - } - /** * @param Enlight_Event_EventArgs $args */ diff --git a/composer.json b/composer.json index c3f43925..bdf0c9eb 100644 --- a/composer.json +++ b/composer.json @@ -5,6 +5,9 @@ "keywords": ["adyen", "payment", "payment platform"], "homepage": "https://adyen.com", "license": "MIT", + "extra": { + "installer-name": "AdyenPayment" + }, "authors": [ { "name": "Adyen", @@ -21,10 +24,10 @@ "require-dev": { "shopware/shopware": "^5.6", "phpro/grumphp": "^0.16.1", - "squizlabs/php_codesniffer": "2.*", "phpcompatibility/php-compatibility": "^9.3", "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "friendsofphp/php-cs-fixer": "^2.16" + "friendsofphp/php-cs-fixer": "^2.16", + "squizlabs/php_codesniffer": "3.*" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/phpcs.xml b/phpcs.xml index 0ecfd23d..dfbda88e 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -13,10 +13,10 @@ ~ ############# ~ ############ ~ - ~ Adyen PrestaShop plugin + ~ Adyen Shopware 5 plugin ~ ~ @author Adyen BV - ~ @copyright (c) 2020 Adyen B.V. + ~ @copyright (c) 2020 Adyen N.V. ~ @license https://opensource.org/licenses/MIT MIT license ~ This file is open source and available under the MIT license. ~ See the LICENSE file for more info. @@ -25,9 +25,7 @@ vendor/* - Controllers/* - AdyenPayment.php - + . *.js diff --git a/plugin.xml b/plugin.xml index 3d3b0c02..0558ccc2 100644 --- a/plugin.xml +++ b/plugin.xml @@ -5,7 +5,7 @@ - 1.4.1 + 1.5.0 Adyen Adyen https://adyen.com @@ -17,10 +17,39 @@ - - Release 🎉 - ]]> + 1.4.1 release + 1.4.1 release + + + + Fixes: + Removed customer ID from shopperinfo payload + Changed order completed state + Improvements to error handling on test API button + Improve exception logging + Yandex logo + Refund using original PSP + + Features: + offer_closed notification handling + Event for order restore + Payment methods cache + Live/Test config values + + + Fixes: + Removed customer ID from shopperinfo payload + Changed order completed state + Improvements to error handling on test API button + Improve exception logging + Yandex logo + Refund using original PSP + + Features: + offer_closed notification handling + Event for order restore + Payment methods cache + Live/Test config values - \ No newline at end of file + diff --git a/ruleset.xml b/ruleset.xml deleted file mode 100644 index 01729796..00000000 --- a/ruleset.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - PSR-2 standards - - - *.js - -