From 73c2341b2d56ead6619d3338321a8ce611138501 Mon Sep 17 00:00:00 2001 From: Ivascu Madalin Date: Mon, 27 Mar 2023 14:49:19 +0300 Subject: [PATCH 1/5] Develop (#17) * repo init - sample method issuers * composer.json deps * BP-1375 Retrieve extra information for payment method (#1) * BP-1375 Retrive extra information for payment method & BP-1376 setPaymentMethodOnCart support * removed fields info, declared schema for additional payment input * BP-1377 GraphQL - placeOrder method support for simple redirect methods * remove debug statements Co-authored-by: Ivascu Madalin * Bp 1383 graphql front end support for idin (#2) * BP-1383 GraphQL - front end support for IDIN * correctly get idin status * change Phtase class to __() function Co-authored-by: Ivascu Madalin * Bp 1378 graphql placeorder method support for inline methods (#3) * BP-1378 GraphQL - placeOrder method support for inline methods * don't need redirect url to qr code display page * forward any query parameters to the process route * remove the process interface Co-authored-by: Ivascu Madalin * Added functionality for giftcard group transactions (#8) Co-authored-by: Ivascu Madalin * Make sure Available buttons can be counted (#7) * BP-1508 Update Readme.md file Update the Readme file. * BP-1508 Update Readme.md file (add icons/images) Add icons/images to the Readme.md file. * Completely headless payments (#9) * Completely headless payments * changed migration name & updated readme Co-authored-by: Ivascu Madalin * Update README.md add notice Add a notice and changed some letters to capital letters. * remove old method of getting order status * Added voucher mutation * Update composer with license and version * add contributing page --------- Co-authored-by: Florinel Chis Co-authored-by: Ivascu Madalin Co-authored-by: Peter Koppenaal <32506814+peterkoppenaal@users.noreply.github.com> Co-authored-by: Rene <105488705+Buckaroo-Rene@users.noreply.github.com> Co-authored-by: Rens Gerritsen <59445921+Buckaroo-Rens@users.noreply.github.com> Co-authored-by: Andrei Mihalescu --- CONTRIBUTING.md | 24 ++ Model/AdditionalDataProvider.php | 62 ++++ Model/Payment/Method/AbstractConfig.php | 45 +++ Model/Payment/Method/Config/Afterpay.php | 48 +++ Model/Payment/Method/Config/Afterpay2.php | 43 +++ Model/Payment/Method/Config/Afterpay20.php | 40 +++ Model/Payment/Method/Config/Applepay.php | 90 ++++++ Model/Payment/Method/Config/Billink.php | 39 +++ Model/Payment/Method/Config/Creditcard.php | 51 ++++ Model/Payment/Method/Config/Creditcards.php | 51 ++++ Model/Payment/Method/Config/Emandate.php | 44 +++ Model/Payment/Method/Config/Giftcards.php | 59 ++++ Model/Payment/Method/Config/Ideal.php | 48 +++ .../Payment/Method/Config/IdealProcessing.php | 48 +++ Model/Payment/Method/Config/Mrcash.php | 44 +++ Model/Payment/Method/ConfigFactory.php | 66 ++++ .../Payment/Method/ConfigFactoryException.php | 27 ++ Plugin/AdditionalDataProviderPool.php | 51 ++++ README.md | 134 ++++++-- Resolver/AbstractCartResolver.php | 66 ++++ Resolver/Cart/AdditionalData.php | 58 ++++ Resolver/Cart/OrderOutput.php | 107 +++++++ Resolver/Cart/ProcessTransactionOutput.php | 199 ++++++++++++ Resolver/Cart/SetReturnUrl.php | 90 ++++++ Resolver/Giftcard/Amount.php | 38 +++ Resolver/Giftcard/AvailablePaymentMethods.php | 113 +++++++ Resolver/Giftcard/Base.php | 47 +++ Resolver/Giftcard/Currency.php | 38 +++ Resolver/Giftcard/Name.php | 41 +++ Resolver/Giftcard/TransactionId.php | 38 +++ Resolver/GiftcardTransactionListResolver.php | 149 +++++++++ Resolver/GiftcardTransactionResolver.php | 149 +++++++++ Resolver/IdinOutputResolver.php | 109 +++++++ Resolver/IdinResolver.php | 106 +++++++ Resolver/VoucherTransactionResolver.php | 140 +++++++++ composer.json | 37 +++ etc/di.xml | 44 +++ etc/graphql/di.xml | 30 ++ etc/module.xml | 9 + etc/schema.graphqls | 285 ++++++++++++++++++ registration.php | 8 + 41 files changed, 2897 insertions(+), 18 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 Model/AdditionalDataProvider.php create mode 100644 Model/Payment/Method/AbstractConfig.php create mode 100644 Model/Payment/Method/Config/Afterpay.php create mode 100644 Model/Payment/Method/Config/Afterpay2.php create mode 100644 Model/Payment/Method/Config/Afterpay20.php create mode 100644 Model/Payment/Method/Config/Applepay.php create mode 100644 Model/Payment/Method/Config/Billink.php create mode 100644 Model/Payment/Method/Config/Creditcard.php create mode 100644 Model/Payment/Method/Config/Creditcards.php create mode 100644 Model/Payment/Method/Config/Emandate.php create mode 100644 Model/Payment/Method/Config/Giftcards.php create mode 100644 Model/Payment/Method/Config/Ideal.php create mode 100644 Model/Payment/Method/Config/IdealProcessing.php create mode 100644 Model/Payment/Method/Config/Mrcash.php create mode 100644 Model/Payment/Method/ConfigFactory.php create mode 100644 Model/Payment/Method/ConfigFactoryException.php create mode 100644 Plugin/AdditionalDataProviderPool.php create mode 100644 Resolver/AbstractCartResolver.php create mode 100644 Resolver/Cart/AdditionalData.php create mode 100644 Resolver/Cart/OrderOutput.php create mode 100644 Resolver/Cart/ProcessTransactionOutput.php create mode 100644 Resolver/Cart/SetReturnUrl.php create mode 100644 Resolver/Giftcard/Amount.php create mode 100644 Resolver/Giftcard/AvailablePaymentMethods.php create mode 100644 Resolver/Giftcard/Base.php create mode 100644 Resolver/Giftcard/Currency.php create mode 100644 Resolver/Giftcard/Name.php create mode 100644 Resolver/Giftcard/TransactionId.php create mode 100644 Resolver/GiftcardTransactionListResolver.php create mode 100644 Resolver/GiftcardTransactionResolver.php create mode 100644 Resolver/IdinOutputResolver.php create mode 100644 Resolver/IdinResolver.php create mode 100644 Resolver/VoucherTransactionResolver.php create mode 100644 composer.json create mode 100644 etc/di.xml create mode 100644 etc/graphql/di.xml create mode 100644 etc/module.xml create mode 100644 etc/schema.graphqls create mode 100644 registration.php diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..f15ce5e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,24 @@ +# Contribution Guidelines + +### Repository setup: +- Fork the repository to your account. +- More details about [how to fork a repo](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) can be found [here](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo). + +### Making changes: +- Create a branch from the develop branch. +- The name of the branch should be something like: `feature/GITHUB-ISSUE-ID-slug` (eg: `feature/50-configprovider-update`) +- Your code changes should follow the [Magento2 coding standard](https://github.com/magento/magento-coding-standard). +- Including unit tests is encouraged. + +### Pull Request: +- Open the PR to develop branch. +- If there is no issue referenced, add a description about the problem and the way it is being solved. +- Allow edits from maintainers. + + +### Contribution to refactoring: + - The branch should be created from refactoring. + - Your code changes should follow the [Magento2 coding standard](https://github.com/magento/magento-coding-standard). + - Include unit tests. + - Open the Pull Request. + - Check that git workflows checks have passed. \ No newline at end of file diff --git a/Model/AdditionalDataProvider.php b/Model/AdditionalDataProvider.php new file mode 100644 index 0000000..5d96bf4 --- /dev/null +++ b/Model/AdditionalDataProvider.php @@ -0,0 +1,62 @@ +fieldListFactory = $fieldListFactory; + } + /** + * Return Additional Data, + * set a flag so we know the payment originated from graphql + * + * @param array $args + * @return array + */ + public function getData(array $args): array + { + $args[self::PAYMENT_FROM] = 'graphQl'; + + if (isset($args[AdditionalDataProviderPool::PROVIDER_KEY][$args['code']])) { + + $additionalArgs = $args[AdditionalDataProviderPool::PROVIDER_KEY][$args['code']]; + unset($args[AdditionalDataProviderPool::PROVIDER_KEY]); + + return array_merge($args, $additionalArgs); + } + + return $args; + } +} diff --git a/Model/Payment/Method/AbstractConfig.php b/Model/Payment/Method/AbstractConfig.php new file mode 100644 index 0000000..71e33f1 --- /dev/null +++ b/Model/Payment/Method/AbstractConfig.php @@ -0,0 +1,45 @@ +configProvider = $configProvider; + } + /** + * Get payment method configuration + * + * @return array + */ + public function getConfig() + { + return []; + } +} \ No newline at end of file diff --git a/Model/Payment/Method/Config/Afterpay.php b/Model/Payment/Method/Config/Afterpay.php new file mode 100644 index 0000000..d151b9e --- /dev/null +++ b/Model/Payment/Method/Config/Afterpay.php @@ -0,0 +1,48 @@ +"businessMethod", + "value" => $this->configProvider->getBusiness() + ], + [ + "key"=>"paymentMethod", + "value" => $this->configProvider->getPaymentMethod() + ] + ]; + } +} \ No newline at end of file diff --git a/Model/Payment/Method/Config/Afterpay2.php b/Model/Payment/Method/Config/Afterpay2.php new file mode 100644 index 0000000..d4687b8 --- /dev/null +++ b/Model/Payment/Method/Config/Afterpay2.php @@ -0,0 +1,43 @@ +"businessMethod", + "value" => $this->configProvider->getBusiness() + ], + [ + "key"=>"paymentMethod", + "value" => $this->configProvider->getPaymentMethod() + ] + ]; + } +} \ No newline at end of file diff --git a/Model/Payment/Method/Config/Afterpay20.php b/Model/Payment/Method/Config/Afterpay20.php new file mode 100644 index 0000000..12ab20b --- /dev/null +++ b/Model/Payment/Method/Config/Afterpay20.php @@ -0,0 +1,40 @@ +"is_b2b", + "value" => $this->configProvider->getCustomerType() !== AfterpayCustomerType::CUSTOMER_TYPE_B2C + ] + ]; + } +} \ No newline at end of file diff --git a/Model/Payment/Method/Config/Applepay.php b/Model/Payment/Method/Config/Applepay.php new file mode 100644 index 0000000..837345c --- /dev/null +++ b/Model/Payment/Method/Config/Applepay.php @@ -0,0 +1,90 @@ + "storeName", + "value" => $this->getConfigValue('storeName') + ], + [ + "key" => "currency", + "value" => $this->getConfigValue('currency') + ], + [ + "key" => "cultureCode", + "value" => $this->getConfigValue('cultureCode') + ], + [ + "key" => "country", + "value" => $this->getConfigValue('country') + ], + [ + "key" => "guid", + "value" => $this->getConfigValue('guid') + ], + [ + "key" => "buttonStyle", + "value" => $this->getConfigValue('buttonStyle') + ], + [ + "key" => "dontAskBillingInfoInCheckout", + "value" => $this->getConfigValue('dontAskBillingInfoInCheckout') + ], + [ + "key" => "availableButtons", + "value" => $this->getAvailableButtons() + ] + + ]; + } + + protected function getConfigValue($key) + { + return $this->configProvider->getConfig()['payment']['buckaroo']['applepay'][$key]; + } + + /** + * Get list of available buttons + * + * @return string + */ + protected function getAvailableButtons() + { + $result = ''; + $availableButtons = $this->getConfigValue('availableButtons'); + if (is_countable($availableButtons) && count($availableButtons)) { + $result = implode(",", $availableButtons); + } + + return $result; + } +} diff --git a/Model/Payment/Method/Config/Billink.php b/Model/Payment/Method/Config/Billink.php new file mode 100644 index 0000000..2f48f9c --- /dev/null +++ b/Model/Payment/Method/Config/Billink.php @@ -0,0 +1,39 @@ +"b2b", + "value" => (int)$this->configProvider->getConfig()['payment']['buckaroo']['billink']['b2b'] + ], + ]; + } +} \ No newline at end of file diff --git a/Model/Payment/Method/Config/Creditcard.php b/Model/Payment/Method/Config/Creditcard.php new file mode 100644 index 0000000..849fd02 --- /dev/null +++ b/Model/Payment/Method/Config/Creditcard.php @@ -0,0 +1,51 @@ +"cards", + "values" => $this->getConfigValue('cards') + ], + [ + "key"=>"selectionType", + "value" => $this->getConfigValue('selectionType') + ], + [ + "key"=>"paymentFlow", + "value" => $this->getConfigValue('paymentFlow') + ] + ]; + } + protected function getConfigValue($key) + { + return $this->configProvider->getConfig()['payment']['buckaroo']['creditcard'][$key]; + } +} \ No newline at end of file diff --git a/Model/Payment/Method/Config/Creditcards.php b/Model/Payment/Method/Config/Creditcards.php new file mode 100644 index 0000000..5e3b309 --- /dev/null +++ b/Model/Payment/Method/Config/Creditcards.php @@ -0,0 +1,51 @@ +"creditcards", + "values" => $this->getConfigValue('creditcards') + ], + [ + "key"=>"defaultCardImage", + "value" => $this->getConfigValue('defaultCardImage') + ], + [ + "key"=>"useCardDesign", + "value" => $this->getConfigValue('useCardDesign') + ] + ]; + } + protected function getConfigValue($key) + { + return $this->configProvider->getConfig()['payment']['buckaroo']['creditcards'][$key]; + } +} \ No newline at end of file diff --git a/Model/Payment/Method/Config/Emandate.php b/Model/Payment/Method/Config/Emandate.php new file mode 100644 index 0000000..dd9ec13 --- /dev/null +++ b/Model/Payment/Method/Config/Emandate.php @@ -0,0 +1,44 @@ + "banks", + "values" => $this->getConfigValue('banks') + ] + ]; + } + protected function getConfigValue($key) + { + return $this->configProvider->getConfig()['payment']['buckaroo']['emandate'][$key]; + } +} diff --git a/Model/Payment/Method/Config/Giftcards.php b/Model/Payment/Method/Config/Giftcards.php new file mode 100644 index 0000000..37c7943 --- /dev/null +++ b/Model/Payment/Method/Config/Giftcards.php @@ -0,0 +1,59 @@ +"groupGiftcards", + "value" => $this->getConfigValue('groupGiftcards') + ], + [ + "key"=>"availableGiftcards", + "values" => $this->getAvailableGiftcards() + ], + + ]; + } + protected function getConfigValue($key) + { + return $this->configProvider->getConfig()['payment']['buckaroo'][$key]; + } + public function getAvailableGiftcards() + { + return array_map( + function($giftcard) { + $giftcard['name'] = $giftcard['title']; + $giftcard['img'] = $giftcard['logo'] != false ? $giftcard['logo'] : null; + return $giftcard; + }, + $this->getConfigValue('avaibleGiftcards') + ); + } +} \ No newline at end of file diff --git a/Model/Payment/Method/Config/Ideal.php b/Model/Payment/Method/Config/Ideal.php new file mode 100644 index 0000000..bcb1657 --- /dev/null +++ b/Model/Payment/Method/Config/Ideal.php @@ -0,0 +1,48 @@ + "selectionType", + "value" => $this->getConfigValue('selectionType') + ], + [ + "key" => "banks", + "values" => $this->getConfigValue('banks') + ] + ]; + } + protected function getConfigValue($key) + { + return $this->configProvider->getConfig()['payment']['buckaroo']['ideal'][$key]; + } +} diff --git a/Model/Payment/Method/Config/IdealProcessing.php b/Model/Payment/Method/Config/IdealProcessing.php new file mode 100644 index 0000000..0a37a6d --- /dev/null +++ b/Model/Payment/Method/Config/IdealProcessing.php @@ -0,0 +1,48 @@ + "selectionType", + "value" => $this->getConfigValue('selectionType') + ], + [ + "key" => "banks", + "values" => $this->getConfigValue('banks') + ] + ]; + } + protected function getConfigValue($key) + { + return $this->configProvider->getConfig()['payment']['buckaroo']['idealprocessing'][$key]; + } +} diff --git a/Model/Payment/Method/Config/Mrcash.php b/Model/Payment/Method/Config/Mrcash.php new file mode 100644 index 0000000..290f228 --- /dev/null +++ b/Model/Payment/Method/Config/Mrcash.php @@ -0,0 +1,44 @@ + "useClientSide", + "value" => $this->getConfigValue('useClientSide') + ] + ]; + } + protected function getConfigValue($key) + { + return $this->configProvider->getConfig()['payment']['buckaroo']['mrcash'][$key]; + } +} diff --git a/Model/Payment/Method/ConfigFactory.php b/Model/Payment/Method/ConfigFactory.php new file mode 100644 index 0000000..653d1ab --- /dev/null +++ b/Model/Payment/Method/ConfigFactory.php @@ -0,0 +1,66 @@ +configProviderMethodFactory = $configProviderMethodFactory; + $this->configProviders = $configProviders; + } + /** + * Create MethodList field + * + * @param string $methodCode + * + * @return AbstractConfig | null + * @throws ConfigFactoryException + */ + public function create(string $methodCode) + { + if (isset($this->configProviders[$methodCode])) { + try { + return new $this->configProviders[$methodCode]( + $this->configProviderMethodFactory->get($methodCode) + ); + } catch (\Throwable $th) { + throw new ConfigFactoryException($th->getMessage(), 0, $th); + } + } + } +} diff --git a/Model/Payment/Method/ConfigFactoryException.php b/Model/Payment/Method/ConfigFactoryException.php new file mode 100644 index 0000000..ad8a25d --- /dev/null +++ b/Model/Payment/Method/ConfigFactoryException.php @@ -0,0 +1,27 @@ +isBuckarooPayment($methodCode)) { + $methodCode = self::PROVIDER_KEY; + } + + return [$methodCode, $data]; + } + /** + * Is one of our payment methods + * + * @param string $methodCode + * + * @return boolean + */ + public function isBuckarooPayment($methodCode) + { + return strpos($methodCode, 'buckaroo_magento2') !== false; + } +} diff --git a/README.md b/README.md index e3c032b..5d69455 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,130 @@

- +

-# Buckaroo Magento 2 GraphQL extension +# Buckaroo Magento2 GraphQL extension +We created a additional GraphQL extension for our [Buckaroo Magento 2 Payments Plugin](https://github.com/buckaroo-it/Magento2).
+This plugin is needed for our [Hÿva React checkout extension](https://github.com/buckaroo-it/Magento2_Hyva).
-## Installation -``` +What is GraphQL?
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools. + +### Index +- [Installation](#installation) +- [Requirements](#requirements) +- [Additional information](#additional-information) +- [Contribute](#contribute) +- [Versioning](#versioning) +- [Additional information](#additional-information) +--- -``` -## Usage -### General information -- ### Requirements To use the plugin you must use: -- Magento Open Source version 2.3.x & 2.4.x -- Buckaroo Magento 2 Payment module 1.39.0 or greater +- Magento Open Source version 2.4.x +- Buckaroo Magento 2 Payment module 1.43.0 or higher. + +## Installation + - Install the module composer by running `composer require buckaroo/module-magento2graphql` + - Enable the module by running `php bin/magento module:enable Buckaroo_Magento2Graphql` + - Apply database updates by running `php bin/magento setup:upgrade` + - Flush the cache by running `php bin/magento cache:flush` + +## Usage -### Configuration -- +### Example requests +- Get the available payments methods with additional data for gateways: +```graphql +query { + cart(cart_id: "{ CART_ID }") { + available_payment_methods { + code + title + buckaroo_additional { + key + values { + name + code + img + } + value + } + } + } +} +``` + +- Place order request example: In order to place a order you will need to the following 3 steps: + - Set the payment method on the card with the required additional parameters using the default `setPaymentMethodOnCart` and the `buckaroo_additional` property + - Set the return url using our custom migration `setBuckarooReturnUrl` required in order for the payment engine to redirect back to your application after the payment was completed/canceled/failed + - Finally execute the the default `placeOrder` that will return a redirect url for the payment engine to complete the payment + +For iDEAL we have the following example: +```graphql + mutation doBuckarooPayment( + $cartId: String! + $returnUrl: String! + $methodCode: String! +) { + setPaymentMethodOnCart( + input: { + cart_id: $cartId + payment_method: { + code: $methodCode + buckaroo_additional: { buckaroo_magento2_ideal: { issuer: "ABNANL2A" } } + } + } + ) { + cart { + items { + product { + name + sku + } + } + } + } + setBuckarooReturnUrl(input: { return_url: $returnUrl, cart_id: $cartId }) { + success + } + placeOrder(input: { cart_id: $cartId }) { + order { + order_number + buckaroo_additional { + redirect + transaction_id + data { + key + value + } + } + } + } +} + +``` +After this migration is performed you will need to store the buckaroo `transaction_id` and redirect the user to complete the payment + +In order to get the payment status after the user is redirected back we will use our custom migration `buckarooPaymentTransactionStatus` that will need the stored `transaction_id` + +```graphql +mutation buckarooPaymentTransactionStatus(input: { transaction_id: "E397CF4C24E64AA299F45246F9906F45" }) { + payment_status, + status_code +} +``` ### Additional information -For more information on Second Chance please visit: -https://support.buckaroo.nl/categorieen/plugins/magento-2 +- **Support:** https://support.buckaroo.eu/contact +- **Contact:** [support@buckaroo.nl](mailto:support@buckaroo.nl) or [+31 (0)30 711 50 50](tel:+310307115050) -## Contribute -See [Contribution Guidelines](CONTRIBUTING.md) +### Contribute +We really appreciate it when developers contribute to improve the Buckaroo plugins. +If you want to contribute as well, then please follow our [Contribution Guidelines](CONTRIBUTING.md). -## Support: +### Versioning +

+ +

-https://support.buckaroo.nl/contact +Please note:
+This file has been prepared with the greatest possible care and is subject to language and/or spelling errors. diff --git a/Resolver/AbstractCartResolver.php b/Resolver/AbstractCartResolver.php new file mode 100644 index 0000000..024096d --- /dev/null +++ b/Resolver/AbstractCartResolver.php @@ -0,0 +1,66 @@ +getCartForUser = $getCartForUser; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + if (!(empty($args['cart_id']) || empty($args['input']['cart_id']))) { + throw new GraphQlInputException( + __('Required parameter "cart_id" is missing') + ); + } + + return []; + } + protected function getQuote(string $maskedQuoteId, ContextInterface $context) + { + // Shopping Cart validation + return $this->getCartForUser->execute( + $maskedQuoteId, + $context->getUserId(), + (int)$context->getExtensionAttributes()->getStore()->getId() + ); + } +} diff --git a/Resolver/Cart/AdditionalData.php b/Resolver/Cart/AdditionalData.php new file mode 100644 index 0000000..9e4a588 --- /dev/null +++ b/Resolver/Cart/AdditionalData.php @@ -0,0 +1,58 @@ +fieldListFactory = $fieldListFactory; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + + $configClass = $this->getConfigClass($value['code']); + + if ($configClass !== null) { + return $configClass->getConfig(); + } + return []; + } + /** + * Get config class for method + * + * @param string $methodCode + * + * @return AbstractConfig|null + */ + protected function getConfigClass($methodCode) + { + try { + return $this->fieldListFactory->create($methodCode); + } catch (\Throwable $th) { + throw new GraphQlInputException( + __('Failed to retrieve additional buckaroo info for ' . $methodCode), + $th + ); + } + } +} diff --git a/Resolver/Cart/OrderOutput.php b/Resolver/Cart/OrderOutput.php new file mode 100644 index 0000000..4b1dc8d --- /dev/null +++ b/Resolver/Cart/OrderOutput.php @@ -0,0 +1,107 @@ +registry = $registry; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + return [ + "redirect" => $this->getRedirect(), + "data" => $this->getAdditionalOutputData(), + "transaction_id" => $this->getTransactionId() + ]; + } + + /** + * Get it for transaction + * + * @return string|null + */ + protected function getTransactionId() + { + $response = $this->getResponse(); + + if (isset($response->Key) && !empty($response->Key)) { + return $response->Key; + } + } + /** + * Get redirect url + * + * @return string|null + */ + protected function getRedirect() + { + $response = $this->getResponse(); + if ($response !== null && !empty($response->RequiredAction->RedirectURL)) { + return $response->RequiredAction->RedirectURL; + } + } + /** + * Get additional data from response + * + * @return array|null + */ + protected function getAdditionalOutputData() + { + + $response = $this->getResponse(); + if ( + $response !== null && + isset($response->Services) && + isset($response->Services->Service) && + is_array($response->Services->Service->ResponseParameter) && + count($response->Services->Service->ResponseParameter) + ) { + return $this->formatAdditionalOutput($response->Services->Service->ResponseParameter); + } + } + /** + * Format data in the graphQl format + * + * @param array $data + * + * @return array + */ + private function formatAdditionalOutput($data) + { + $additionalData = []; + if (count($data)) { + foreach ($data as $item) { + if (isset($item->Name) && isset($item->_)) { + $additionalData[] = [ + "key" => $item->Name, + "value" => $item->_ + ]; + } + } + } + return $additionalData; + } + /** + * Get payment response + * + * @return stdClass|null + */ + private function getResponse() + { + if ($this->registry && $this->registry->registry("buckaroo_response")) { + return $this->registry->registry("buckaroo_response")[0]; + } + } +} diff --git a/Resolver/Cart/ProcessTransactionOutput.php b/Resolver/Cart/ProcessTransactionOutput.php new file mode 100644 index 0000000..e5e88b3 --- /dev/null +++ b/Resolver/Cart/ProcessTransactionOutput.php @@ -0,0 +1,199 @@ +logger = $logger; + $this->processResponse = $processResponse; + $this->client = $client; + $this->transactionResponseInterfaceFactory = $transactionResponseInterfaceFactory; + $this->accountConfig = $accountConfig; + $this->transactionCollection = $transactionCollection; + $this->encryptor = $encryptor; + } + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + try { + + $order = $this->getOrder( + $args['input']['transaction_id'] + ); + + if ($order === null) { + throw new GraphQlInputException( + __("Cannot find order based on transaction_id `{$args['input']['transaction_id']}`") + ); + } + + if ($context->getUserId() !== (int)$order->getCustomerId()) { + throw new GraphQlAuthorizationException( + __('The current user cannot perform operations on this order') + ); + } + + return $this->processResponse->process( + $this->doRequest( + $args['input']['transaction_id'], + ), + $order + ); + } catch (GraphQlAuthorizationException $e) { + $this->logger->addDebug((string)$e); + throw $e; + } catch (GraphQlInputException $e) { + $this->logger->addDebug((string)$e); + throw $e; + } catch (\Throwable $th) { + $this->logger->addDebug((string)$th); + throw new GraphQlInputException( + __('Unknown buckaroo error occurred') + ); + } + } + + + /** + * Get order by transaction id + * + * @param string $transaction_id + * + * @return \Magento\Sales\Model\Order + */ + protected function getOrder(string $transaction_id) + { + /** @var \Magento\Sales\Model\Order\Payment\Transaction */ + $transaction = $this->transactionCollection + ->addFieldToFilter( + 'txn_id', + ['eq' => $transaction_id] + ) + ->getFirstItem(); + + if ($transaction->getTxnId() !== null) { + return $transaction->getOrder(); + } + } + + /** + * Do buckaroo status request for transaction + * + * @param string $transaction_id + * + * @return \Buckaroo\Magento2\Api\TransactionResponseInterface + */ + protected function doRequest(string $transaction_id) + { + $active = $this->accountConfig->getActive(); + $mode = ($active == \Buckaroo\Magento2\Helper\Data::MODE_LIVE) ? + \Buckaroo\Magento2\Helper\Data::MODE_LIVE : \Buckaroo\Magento2\Helper\Data::MODE_TEST; + + $this->client->setSecretKey( + $this->encryptor->decrypt( + $this->accountConfig->getSecretKey() + ) + ); + $this->client->setWebsiteKey( + $this->encryptor->decrypt( + $this->accountConfig->getMerchantKey() + ) + ); + + $data = $this->client->doStatusRequest($transaction_id, $mode); + if ($data === null) { + throw new GraphQlNoSuchEntityException( + __('Unable to get order details') + ); + } + return $this->transactionResponseInterfaceFactory->create( + ["data" => $data] + ); + } +} diff --git a/Resolver/Cart/SetReturnUrl.php b/Resolver/Cart/SetReturnUrl.php new file mode 100644 index 0000000..ca6db25 --- /dev/null +++ b/Resolver/Cart/SetReturnUrl.php @@ -0,0 +1,90 @@ +logger = $logger; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + + + parent::resolve($field, $context, $info, $value, $args); + + if (empty($args['input']['return_url'])) { + throw new GraphQlInputException( + __('Required parameter "return_url" is missing') + ); + } + + $returnUrl = $args['input']['return_url']; + $cartId = $args['input']['cart_id']; + if ( + filter_var($returnUrl, FILTER_VALIDATE_URL) === false || + !in_array(parse_url($returnUrl, PHP_URL_SCHEME), ['http', 'https']) + ) { + throw new GraphQlInputException( + __('A valid "return_url" is required ') + ); + } + + try { + $quote = $this->getQuote($cartId, $context); + $quote->getPayment()->setAdditionalInformation(self::ADDITIONAL_RETURN_URL, "{$returnUrl}/{$cartId}"); + } catch (\Throwable $th) { + $this->logger->addDebug((string)$th); + throw new GraphQlInputException( + __('Unknown buckaroo error occurred') + ); + } + + return [ + "success" => true + ]; + } +} diff --git a/Resolver/Giftcard/Amount.php b/Resolver/Giftcard/Amount.php new file mode 100644 index 0000000..0ce8eaf --- /dev/null +++ b/Resolver/Giftcard/Amount.php @@ -0,0 +1,38 @@ +getField('amount', $value); + } + +} diff --git a/Resolver/Giftcard/AvailablePaymentMethods.php b/Resolver/Giftcard/AvailablePaymentMethods.php new file mode 100644 index 0000000..a12a091 --- /dev/null +++ b/Resolver/Giftcard/AvailablePaymentMethods.php @@ -0,0 +1,113 @@ +informationManagement = $informationManagement; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + if (!isset($value['quote'])) { + throw new LocalizedException(__('"quote" value should be specified')); + } + + $cart = $value['quote']; + return $this->getPaymentMethodsData($cart, $value['already_paid']); + } + + /** + * Collect and return information about available payment methods, + * return only methods that can do a pay reminder + * @param CartInterface $cart + * @return array + */ + private function getPaymentMethodsData(CartInterface $cart, float $alreadyPaid): array + { + $isGroupTransaction = $alreadyPaid > 0; + + $notAvailable = [ + 'buckaroo_magento2_billink', + 'buckaroo_magento2_payperemail', + 'buckaroo_magento2_paylink', + 'buckaroo_magento2_sepadirectdebit', + 'buckaroo_magento2_transfer', + 'buckaroo_magento2_klarnakp', + 'buckaroo_magento2_klarnain', + 'buckaroo_magento2_emandate', + 'buckaroo_magento2_applepay', + 'buckaroo_magento2_capayablein3', + 'buckaroo_magento2_capayablepostpay', + 'buckaroo_magento2_pospayment', + 'buckaroo_magento2_tinka' + ]; + + $paymentInformation = $this->informationManagement->getPaymentInformation($cart->getId()); + $paymentMethods = $paymentInformation->getPaymentMethods(); + + $paymentMethodsData = []; + foreach ($paymentMethods as $paymentMethod) { + + $paymentMethodCode = $paymentMethod->getCode(); + if ( + !$isGroupTransaction || ( + $isGroupTransaction && + $this->isMethodBuckaroo($paymentMethodCode) && + !in_array($paymentMethodCode, $notAvailable) + ) + ) { + $paymentMethodsData[] = [ + 'title' => $paymentMethod->getTitle(), + 'code' => $paymentMethodCode, + ]; + } + } + return $paymentMethodsData; + } + + public function isMethodBuckaroo(string $paymentMethodCode) + { + return strpos($paymentMethodCode, 'buckaroo_magento2_') !== false; + } +} diff --git a/Resolver/Giftcard/Base.php b/Resolver/Giftcard/Base.php new file mode 100644 index 0000000..646d0bb --- /dev/null +++ b/Resolver/Giftcard/Base.php @@ -0,0 +1,47 @@ +getData($key); + } + +} diff --git a/Resolver/Giftcard/Currency.php b/Resolver/Giftcard/Currency.php new file mode 100644 index 0000000..3be8d14 --- /dev/null +++ b/Resolver/Giftcard/Currency.php @@ -0,0 +1,38 @@ +getField('currency', $value); + } + +} diff --git a/Resolver/Giftcard/Name.php b/Resolver/Giftcard/Name.php new file mode 100644 index 0000000..73a1e0b --- /dev/null +++ b/Resolver/Giftcard/Name.php @@ -0,0 +1,41 @@ +getField('label', $value); + if ($name === null) { + return __('Buckaroo Voucher'); + } + return $name; + } +} diff --git a/Resolver/Giftcard/TransactionId.php b/Resolver/Giftcard/TransactionId.php new file mode 100644 index 0000000..8074064 --- /dev/null +++ b/Resolver/Giftcard/TransactionId.php @@ -0,0 +1,38 @@ +getField('transaction_id', $value); + } + +} diff --git a/Resolver/GiftcardTransactionListResolver.php b/Resolver/GiftcardTransactionListResolver.php new file mode 100644 index 0000000..3f5a97e --- /dev/null +++ b/Resolver/GiftcardTransactionListResolver.php @@ -0,0 +1,149 @@ +logger = $logger; + $this->groupTransaction = $groupTransaction; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + parent::resolve($field, $context, $info, $value, $args); + + try { + $quote = $this->getQuote($args['cart_id'], $context); + return $this->getResponse( + $quote + ); + } catch (LocalizedException $e) { + $this->logger->addDebug((string)$e); + throw $e; + } catch (ApiException $e) { + $this->logger->addDebug((string)$e); + throw new GraphQlInputException( + __($e->getMessage()) + ); + } catch (\Throwable $th) { + $this->logger->addDebug((string)$th); + throw new GraphQlInputException( + __('Unknown buckaroo error occurred') + ); + } + } + + protected function getResponse(Quote $quote) + { + return [ + 'remainder_amount' => $this->getRemainderAmount($quote), + 'already_paid' => $this->getAlreadyPaid($quote), + 'transactions' => $this->getTransactions($quote), + 'quote' => $quote + ]; + } + /** + * Get RemainderAmount + * + * @api + * @return float + */ + protected function getRemainderAmount(Quote $quote) + { + return $quote->getGrandTotal() - $this->getAlreadyPaid($quote); + } + /** + * Get AlreadyPaid + * + * @api + * @return float + */ + protected function getAlreadyPaid(Quote $quote) + { + return $this->groupTransaction->getGroupTransactionAmount( + $quote->getReservedOrderId() + ); + } + /** + * Get the list of transactions for this cart + * + * @param string $cartId + * @return array + */ + protected function getTransactions(Quote $quote) + { + return $this->formatFound( + $this->groupTransaction->getActiveItemsWithName( + $quote->getReservedOrderId() + ) + ); + } + + /** + * Format data for json response + * + * @param array $collection + * + * @return array + */ + protected function formatFound(array $collection) + { + return array_map(function ($item) { + return [ + 'model' => $item + ]; + }, $collection); + } +} diff --git a/Resolver/GiftcardTransactionResolver.php b/Resolver/GiftcardTransactionResolver.php new file mode 100644 index 0000000..119b580 --- /dev/null +++ b/Resolver/GiftcardTransactionResolver.php @@ -0,0 +1,149 @@ +logger = $logger; + $this->giftcardRequest = $giftcardRequest; + $this->giftcardResponse = $giftcardResponse; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + parent::resolve($field, $context, $info, $value, $args); + + if (!$this->argumentExists($args, 'card_number')) { + throw new GraphQlInputException(__('Parameter `card_number` is required')); + } + + if (!$this->argumentExists($args, 'card_pin')) { + throw new GraphQlInputException(__('Parameter `card_pin` is required')); + } + + if (!$this->argumentExists($args, 'giftcard_id')) { + throw new GraphQlInputException(__('Parameter `giftcard_id` is required')); + } + + try { + $quote = $this->getQuote($args['input']['cart_id'], $context); + return $this->getResponse( + $quote, + $this->build($quote, $args)->send() + ); + } catch (LocalizedException $e) { + $this->logger->addDebug((string)$e); + throw $e; + } catch (ApiException $e) { + $this->logger->addDebug((string)$e); + throw $e; + } catch (\Throwable $th) { + $this->logger->addDebug((string)$th); + throw new GraphQlInputException( + __('Unknown buckaroo error occurred') + ); + } + } + + protected function getResponse(Quote $quote, $response) + { + $this->giftcardResponse->set($response, $quote); + + if ($this->giftcardResponse->getErrorMessage() !== null) { + throw new ApiException($this->giftcardResponse->getErrorMessage()); + } + return [ + 'remainder_amount' => $this->giftcardResponse->getRemainderAmount(), + 'already_paid' => $this->giftcardResponse->getAlreadyPaid($quote), + 'transaction' => [ + 'model' => $this->giftcardResponse->getCreatedTransaction() + ], + 'quote' => $quote + ]; + } + /** + * Build giftcard request + * + * @param Quote $quote + * @param array $args + * + * @return GiftcardRequest + */ + protected function build(Quote $quote, array $args) + { + return $this->giftcardRequest + ->setCardId($args['input']['giftcard_id']) + ->setCardNumber($args['input']['card_number']) + ->setPin($args['input']['card_pin']) + ->setQuote($quote); + } + + protected function argumentExists($args, $name) + { + if (!isset($args['input'])) { + return false; + } + return isset($args['input'][$name]) && + is_string($args['input'][$name]) && + strlen(trim($args['input'][$name])) > 0; + } +} diff --git a/Resolver/IdinOutputResolver.php b/Resolver/IdinOutputResolver.php new file mode 100644 index 0000000..a7a786c --- /dev/null +++ b/Resolver/IdinOutputResolver.php @@ -0,0 +1,109 @@ +transactionBuilder = $transactionBuilderFactory->get('idin'); + $this->gateway = $gateway; + $this->logger = $logger; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + if (!(isset($args['input']) && isset($args['input']['issuer']))) { + throw new GraphQlInputException( + __('A idin issuer is required') + ); + } + try { + $response = $this->sendIdinRequest($args['input']['issuer']); + } catch (\Throwable $th) { + $this->logger->addDebug((string)$th); + throw new GraphQlInputException( + __('Unknown buckaroo error occurred') + ); + } + + if (isset($response->RequiredAction) && isset($response->RequiredAction->RedirectURL)) { + return ['redirect' => $response->RequiredAction->RedirectURL]; + } else { + throw new GraphQlInputException( + __('Unfortunately iDIN not verified!') + ); + } + } + /** + * Send idin request + * + * @param string $issuer + * + * @return mixed $response + * @throws \Exception + */ + protected function sendIdinRequest($issuer) + { + $transaction = $this->transactionBuilder + ->setIssuer($issuer) + ->build(); + + return $this->gateway + ->setMode( + $this->transactionBuilder->getMode() + ) + ->authorize($transaction)[0]; + } +} diff --git a/Resolver/IdinResolver.php b/Resolver/IdinResolver.php new file mode 100644 index 0000000..0789a1b --- /dev/null +++ b/Resolver/IdinResolver.php @@ -0,0 +1,106 @@ +idinConfig = $idinConfig; + $this->customerRepository = $customerRepository; + $this->logger = $logger; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + parent::resolve($field, $context, $info, $value, $args); + + try { + $idin = $this->idinConfig->getIdinStatus( + $this->getQuote($args['cart_id'], $context), + $this->getCustomer($context->getUserId()) + ); + } catch (LocalizedException $e) { + throw $e; + } catch (\Throwable $th) { + $this->logger->addDebug($th); + throw new GraphQlInputException( + __('Unknown buckaroo error occurred') + ); + } + return [ + 'issuers' => $this->idinConfig->getIssuers(), + 'active' => $idin['active'], + 'verified' => $idin['verified'] + ]; + } + /** + * Get customer by id + * + * @param mixed $customerId + * + * @return CustomerInterface|null + */ + public function getCustomer($customerId) + { + if (empty($customerId)) { + return; + } + return $this->customerRepository->getById($customerId); + } +} diff --git a/Resolver/VoucherTransactionResolver.php b/Resolver/VoucherTransactionResolver.php new file mode 100644 index 0000000..bc7ca9d --- /dev/null +++ b/Resolver/VoucherTransactionResolver.php @@ -0,0 +1,140 @@ +logger = $logger; + $this->voucherRequest = $voucherRequest; + $this->giftcardResponse = $giftcardResponse; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + parent::resolve($field, $context, $info, $value, $args); + + if (!$this->argumentExists($args, 'voucher_code')) { + throw new GraphQlInputException(__('Parameter `voucher_code` is required')); + } + + try { + $quote = $this->getQuote($args['input']['cart_id'], $context); + return $this->getResponse( + $quote, + $this->build($quote, $args)->send() + ); + } catch (LocalizedException $e) { + $this->logger->addDebug((string)$e); + throw $e; + } catch (ApiException $e) { + $this->logger->addDebug((string)$e); + throw new GraphQlInputException( + __($e->getMessage()) + ); + } catch (\Throwable $th) { + $this->logger->addDebug((string)$th); + throw new GraphQlInputException( + __('Unknown buckaroo error occurred') + ); + } + } + + protected function getResponse(Quote $quote, $response) + { + $this->giftcardResponse->set($response, $quote); + + if ($this->giftcardResponse->getErrorMessage() !== null) { + throw new ApiException($this->giftcardResponse->getErrorMessage()); + } + return [ + 'remainder_amount' => $this->giftcardResponse->getRemainderAmount(), + 'already_paid' => $this->giftcardResponse->getAlreadyPaid($quote), + 'transaction' => [ + 'model' => $this->giftcardResponse->getCreatedTransaction() + ], + 'quote' => $quote + ]; + } + /** + * Build giftcard request + * + * @param array $args + * + * @return GiftcardRequest + */ + protected function build(Quote $quote, array $args) + { + return $this->voucherRequest + ->setVoucherCode($args['input']['voucher_code']) + ->setQuote($quote); + } + + protected function argumentExists($args, $name) + { + if (!isset($args['input'])) { + return false; + } + return isset($args['input'][$name]) && + is_string($args['input'][$name]) && + strlen(trim($args['input'][$name])) > 0; + } +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..c4d0199 --- /dev/null +++ b/composer.json @@ -0,0 +1,37 @@ +{ + "name": "buckaroo/magento2graphql", + "description": "Buckaroo Magento2 GraphQL Support", + "type": "magento2-module", + "license": "CC-BY-NC-ND-3.0", + "authors": [ + { + "name": "Buckaroo", + "email": "support@buckaroo.nl", + "homepage": "https://www.buckaroo.nl" + }, + { + "name": "Florinel Chis", + "email": "florinel.chis@gmail.com" + } + ], + "support": { + "email": "support@buckaroo.nl", + "issues": "https://support.buckaroo.nl/contact", + "wiki": "https://support.buckaroo.nl", + "docs": "https://support.buckaroo.nl" + }, + "homepage": "https://www.buckaroo.nl", + "version" : "1.0.0", + "minimum-stability": "stable", + "require": { + "buckaroo/magento2": "~1.44" + }, + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Buckaroo\\Magento2Graphql\\": "" + } + } +} \ No newline at end of file diff --git a/etc/di.xml b/etc/di.xml new file mode 100644 index 0000000..ebc3503 --- /dev/null +++ b/etc/di.xml @@ -0,0 +1,44 @@ + + + + + + + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\Afterpay + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\Afterpay2 + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\Afterpay20 + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\Applepay + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\Billink + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\Creditcard + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\Creditcards + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\Giftcards + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\Ideal + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\IdealProcessing + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\Mrcash + Buckaroo\Magento2Graphql\Model\Payment\Method\Config\Emandate + + + + + + + \ No newline at end of file diff --git a/etc/graphql/di.xml b/etc/graphql/di.xml new file mode 100644 index 0000000..b073c5d --- /dev/null +++ b/etc/graphql/di.xml @@ -0,0 +1,30 @@ + + + + + + + Buckaroo\Magento2Graphql\Model\AdditionalDataProvider + + + + diff --git a/etc/module.xml b/etc/module.xml new file mode 100644 index 0000000..73ec216 --- /dev/null +++ b/etc/module.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/etc/schema.graphqls b/etc/schema.graphqls new file mode 100644 index 0000000..e776f2b --- /dev/null +++ b/etc/schema.graphqls @@ -0,0 +1,285 @@ +#Queries + +type Query { + getBuckarooIdin (cart_id: String!): BuckarooIdin @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\IdinResolver") + @doc(description: "Get iDIN info for this session") + + getBuckarooGiftcardTransactions (cart_id: String!): BuckarooGiftcardTransactions @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\GiftcardTransactionListResolver") + @doc(description: "Get giftcard transactions") +} + +#Mutations + +type Mutation { + verifyBuckarooIdin (input: BuckarooIdinInput!): BuckarooIdinOutput @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\IdinOutputResolver") + @doc(description: "Verify customer/session age") + + buckarooPaymentTransactionStatus( + input: BuckarooPaymentTransactionInput! + ): BuckarooPaymentTransactionOutput @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Cart\\ProcessTransactionOutput") + + setBuckarooReturnUrl( + input: BuckarooReturnUrlInput! + ): BuckarooReturnUrl @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Cart\\SetReturnUrl") + + buckarooProcessGiftcardTransaction( + input: BuckarooProcessGiftcardTransactionInput + ): BuckarooProcessGiftcardTransactionOutput @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\GiftcardTransactionResolver") + + buckarooProcessVoucherTransaction( + input: BuckarooProcessVoucherTransactionInput + ): BuckarooProcessGiftcardTransactionOutput @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\VoucherTransactionResolver") +} +input BuckarooReturnUrlInput { + return_url: String! @doc(description: "Link to the success/failed order page"), + cart_id: String! @doc(description: "Cart id") +} +type BuckarooReturnUrl { + success:Boolean +} + +input BuckarooProcessVoucherTransactionInput { + cart_id: String! @doc(description: "Cart id") + voucher_code: String! @doc(description: "Voucher code") +} + +input BuckarooProcessGiftcardTransactionInput { + cart_id: String! @doc(description: "Cart id") + giftcard_id: String! @doc(description: "Giftcard id") + card_number: String! @doc(description: "Giftcard number") + card_pin: String! @doc(description: "Giftcard pin") +} + +type BuckarooGiftcardTransactions { + remainder_amount: Float!, + already_paid: Float!, + transactions: [GiftcardTransaction], + available_payment_methods:[GiftcardAvailableMethods] @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Giftcard\\AvailablePaymentMethods") +} + +type BuckarooProcessGiftcardTransactionOutput { + remainder_amount: Float!, + already_paid: Float!, + transaction: GiftcardTransaction!, + available_payment_methods:[GiftcardAvailableMethods] @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Giftcard\\AvailablePaymentMethods") +} + +type GiftcardAvailableMethods { + title: String!, + code: String! +} +type GiftcardTransaction { + amount: Float! @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Giftcard\\Amount") + currency: String! @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Giftcard\\Currency") + name: String! @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Giftcard\\Name") + transaction_id: String! @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Giftcard\\TransactionId") +} + + +input BuckarooPaymentTransactionInput { + transaction_id: String! @doc(description: "Buckaroo transaction id") +} + +type BuckarooPaymentTransactionOutput { + payment_status: String!, + status_code: Int! +} + +# Overrides +type AvailablePaymentMethod { + buckaroo_additional: [BuckarooAdditionalData] + @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Cart\\AdditionalData") + @doc(description: "Additional buckaroo data for this payment method") +} +input PaymentMethodInput { + buckaroo_additional: BuckarooAdditionalInput +} + +type Order { + buckaroo_additional: BuckarooOrderOutput + @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Cart\\OrderOutput") +} + +# Buckaroo +#Payment input + +#Global + +input BuckarooAdditionalInput { + buckaroo_magento2_afterpay: BuckarooAfterpay + buckaroo_magento2_afterpay2: BuckarooAfterpay + buckaroo_magento2_afterpay20: BuckarooAfterpay20 + buckaroo_magento2_applepay: BuckarooApplepayInput + buckaroo_magento2_billink: BuckarooBillinkInput + buckaroo_magento2_capayablein3: BuckarooIn3Input + buckaroo_magento2_creditcard: BuckarooCreditcardInput + buckaroo_magento2_creditcards: BuckarooCreditcardsInput + buckaroo_magento2_emandate: BuckarooEmandateInput + buckaroo_magento2_giftcards: BuckarooGiftcardsInput + buckaroo_magento2_giropay: BuckarooGiropayInput + buckaroo_magento2_ideal: BuckarooIdealInput + buckaroo_magento2_idealprocessing: BuckarooIdealInput + buckaroo_magento2_mrcash: BuckarooMrcashInput + buckaroo_magento2_paylink: BuckarooPayLinkInput + buckaroo_magento2_payperemail: BuckarooPayPerEmailInput + buckaroo_magento2_sepadirectdebit: BuckarooSepaDirectDebitInput + buckaroo_magento2_tinka: BuckarooTinkaInput, + buckaroo_magento2_klarna: BuckarooKlarnaInput, + buckaroo_magento2_klarnain: BuckarooKlarnaInput +} + +input BuckarooKlarnaInput { + customer_gender: String! @doc(description: "Customer gender") +} + +input BuckarooAfterpay { + termsCondition: String! @doc(description: "Customer is required to accept the terms and conditions") + customer_billingName: String! @doc(description: "Customer billing name") + selectedBusiness: String! @doc(description: "Business methods that will be used 1 for B2C, 2 for B2B") + customer_iban: String! @doc(description: "Customer IBAN required for B2C (selectedBusiness = 1)") + customer_DoB: String! @doc(description: "Customer date of birth format `d/m/Y`") + customer_telephone: String @doc(description: "Customer phone number") + customer_identificationNumber: String @doc(description: "Customer identification number required if billing country is finland (FI).") + COCNumber: String @doc(description: "Customer COC number required for B2B (selectedBusiness = 2)") + CompanyName: String @doc(description: "Company name required for B2B (selectedBusiness = 2)") +} + +input BuckarooAfterpay20 { + termsCondition: String! @doc(description: "Customer is required to accept the terms and conditions") + customer_billingName: String! @doc(description: "Customer billing name") + customer_DoB: String! @doc(description: "Customer date of birth format `d/m/Y`") + customer_telephone: String @doc(description: "Customer phone number") + customer_identificationNumber: String @doc(description: "Customer identification number required if billing country is finland (FI).") + customer_coc: String @doc(description: "Customer COC number required for B2B") +} +#Applepay +input BuckarooApplepayInput { + applepayTransaction: String @doc(description: "Transaction data received from Buckaroo JS SDK") + billingContact: String @doc(description: "Customer full name received from Buckaroo JS SDK") +} + +#Billink +input BuckarooBillinkInput { + customer_billingName: String! @doc(description: "Customer billing name") + customer_gender: String! @doc(description: "Customer gender 1 for 'male' 2 for 'female'") + customer_chamberOfCommerce: String @doc(description: "Customer Chamber of commerce number required for B2B") + customer_VATNumber: String @doc(description: "Customer VAT number required for B2B") + customer_DoB: String! @doc(description: "Customer date of birth format `d/m/Y`") + customer_telephone: String @doc(description: "Customer phone number") + termsCondition: String! @doc(description: "Customer is required to accept the terms and conditions") +} + + +input BuckarooIn3Input { + customer_billingName: String! @doc(description: "Customer billing name") + customer_DoB: String! @doc(description: "Customer date of birth format `d/m/Y`") +} + +#Creditcard +input BuckarooCreditcardInput { + card_type: String @doc(description: "Valid card type") +} + +#Creditcards +input BuckarooCreditcardsInput { + customer_encrypteddata: String! @doc(description: "Encrypted client data using the buckaroo JS SDK") + customer_creditcardcompany: String @doc(description: "Valid card type") +} + +#Emandate +input BuckarooEmandateInput { + issuer: String! @doc(description: "Valid bank issuer") +} + +#Giftcards +input BuckarooGiftcardsInput { + giftcard_method: String! @doc(description: "Valid giftcard method") +} +#Giropay +input BuckarooGiropayInput { + customer_bic: String! @doc(description: "Customer BIC") +} +#Ideal +input BuckarooIdealInput { + issuer: String! @doc(description: "Valid bank issuer") +} +#Mrcash +input BuckarooMrcashInput { + client_side_mode: String! @doc(description: "Type of request `cc` for client side, `mobile` for mobile app/QR Code") + customer_encrypteddata: String @doc(description: "Encrypted client data using the buckaroo JS SDK") +} + +#PayLink +input BuckarooPayLinkInput { + customer_gender: String! @doc(description: "Customer gender 1 for 'male' 2 for 'female'") + customer_billingFirstName: String! @doc(description: "Customer first name") + customer_billingLastName: String! @doc(description: "Customer last name") + customer_email: String! @doc(description: "A valid customer email address") +} + +#PayPerEmail +input BuckarooPayPerEmailInput { + customer_gender: String! @doc(description: "Customer gender 1 for 'male' 2 for 'female'") + customer_billingFirstName: String! @doc(description: "Customer first name") + customer_billingLastName: String! @doc(description: "Customer last name") + customer_email: String! @doc(description: "A valid customer email address") +} + +#SepaDirectDebit +input BuckarooSepaDirectDebitInput { + customer_bic: String @doc(description: "Customer BIC") + customer_iban: String! @doc(description: "Customer BIC") + customer_account_name: String! @doc(description: "Customer account name") +} + +#Tinka +input BuckarooTinkaInput { + customer_billingName: String! @doc(description: "Customer first name") + customer_DoB: String! @doc(description: "Customer date of birth format `d/m/Y`") +} + +#Order output +type BuckarooOrderOutput { + redirect: String @doc(description: "Url required for completing the payment") + data: [BuckarooAdditionalOutputData] @doc(description: "Additional fields required for inline payments") + transaction_id: String @doc(description: "Buckaroo transaction id") +} + +type BuckarooAdditionalOutputData { + key: String! + value: String! +} + +#Method additional data +type BuckarooAdditionalData { + key: String! + values: [BuckarooMultipleValues] @doc(description: "Field values") + value: String @doc(description: "Field value") +} +type BuckarooMultipleValues { + name: String! + code: String! + img: String +} + +#idin + +type BuckarooIdin { + issuers: [BuckarooIdinIssuers]! @doc(description: "List of issuers available for iDIN verification") + active: Boolean! @doc(description: "iDIN is active or not") + verified: Boolean! @doc(description: "Age is verified for this customer/session") + +} +type BuckarooIdinIssuers { + name: String! @doc(description: "Issuer name") + code: String! @doc(description: "Issuer code required for age verification") +} + + +input BuckarooIdinInput { + issuer: String! @doc(description: "Issuer code required for age verification") +} + +type BuckarooIdinOutput { + redirect: String! @doc(description: "Url required for completion of age verification") +} diff --git a/registration.php b/registration.php new file mode 100644 index 0000000..af3b91b --- /dev/null +++ b/registration.php @@ -0,0 +1,8 @@ + Date: Fri, 5 Apr 2024 08:06:23 +0200 Subject: [PATCH 2/5] Add protected constructor class variable (#23) --- Resolver/Cart/OrderOutput.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Resolver/Cart/OrderOutput.php b/Resolver/Cart/OrderOutput.php index 4b1dc8d..65c0f75 100644 --- a/Resolver/Cart/OrderOutput.php +++ b/Resolver/Cart/OrderOutput.php @@ -12,6 +12,7 @@ */ class OrderOutput implements ResolverInterface { + protected Registry $registry; public function __construct(Registry $registry) { From f57c5bfd12e285a3df83d25be2ba5a908dc97456 Mon Sep 17 00:00:00 2001 From: Sander Date: Wed, 27 Nov 2024 11:14:26 +0100 Subject: [PATCH 3/5] BP-3649-Refactor return URL and add Cancel and Failed URL --- Model/AdditionalDataProvider.php | 25 +++ Model/Payment/Method/AbstractMethodPlugin.php | 54 +++++ Model/Payment/Method/Config/ReturnUrl.php | 27 +++ Plugin/OrderTransactionBuilderPlugin.php | 185 ++++++++++++++++++ Resolver/Cart/SetCancelUrl.php | 90 +++++++++ Resolver/Cart/SetErrorUrl.php | 90 +++++++++ Resolver/Cart/SetRejectUrl.php | 90 +++++++++ Resolver/Cart/SetReturnUrl.php | 2 +- etc/graphql/di.xml | 12 ++ etc/schema.graphqls | 44 ++++- 10 files changed, 616 insertions(+), 3 deletions(-) create mode 100644 Model/Payment/Method/AbstractMethodPlugin.php create mode 100644 Model/Payment/Method/Config/ReturnUrl.php create mode 100644 Plugin/OrderTransactionBuilderPlugin.php create mode 100644 Resolver/Cart/SetCancelUrl.php create mode 100644 Resolver/Cart/SetErrorUrl.php create mode 100644 Resolver/Cart/SetRejectUrl.php diff --git a/Model/AdditionalDataProvider.php b/Model/AdditionalDataProvider.php index 5d96bf4..7c6054b 100644 --- a/Model/AdditionalDataProvider.php +++ b/Model/AdditionalDataProvider.php @@ -21,6 +21,7 @@ namespace Buckaroo\Magento2Graphql\Model; +use Buckaroo\Magento2\Gateway\Http\TransactionBuilder\AbstractTransactionBuilder; use Buckaroo\Magento2Graphql\Plugin\AdditionalDataProviderPool; use Buckaroo\Magento2Graphql\Model\Payment\Method\ConfigFactory; use Magento\QuoteGraphQl\Model\Cart\Payment\AdditionalDataProviderInterface; @@ -59,4 +60,28 @@ public function getData(array $args): array return $args; } + + /** + * @param AdditionalDataProvider $subject + * @param array $result + * @param array $args + * @return array + * @suppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetData(AdditionalDataProvider $subject, array $result, array $args): array + { + if (isset($args['buckaroo_additional']['return_url'])) { + $result[AbstractTransactionBuilder::ADDITIONAL_RETURN_URL] = $args['buckaroo_additional']['return_url']; + } + if (isset($args['buckaroo_additional']['cancel_url'])) { + $result[AbstractTransactionBuilder::ADDITIONAL_CANCEL_URL] = $args['buckaroo_additional']['cancel_url']; + } + if (isset($args['buckaroo_additional']['error_url'])) { + $result[AbstractTransactionBuilder::ADDITIONAL_ERROR_URL] = $args['buckaroo_additional']['error_url']; + } + if (isset($args['buckaroo_additional']['reject_url'])) { + $result[AbstractTransactionBuilder::ADDITIONAL_REJECT_URL] = $args['buckaroo_additional']['reject_url']; + } + return $result; + } } diff --git a/Model/Payment/Method/AbstractMethodPlugin.php b/Model/Payment/Method/AbstractMethodPlugin.php new file mode 100644 index 0000000..36b3c1a --- /dev/null +++ b/Model/Payment/Method/AbstractMethodPlugin.php @@ -0,0 +1,54 @@ +getAdditionalData(); + + if (isset($additionalSkip['buckaroo_return_url'])) { + $subject->getInfoInstance()->setAdditionalInformation( + 'buckaroo_return_url', + $additionalSkip['buckaroo_return_url'] + ); + } + if (isset($additionalSkip['buckaroo_cancel_url'])) { + $subject->getInfoInstance()->setAdditionalInformation( + 'buckaroo_cancel_url', + $additionalSkip['buckaroo_cancel_url'] + ); + } + if (isset($additionalSkip['buckaroo_error_url'])) { + $subject->getInfoInstance()->setAdditionalInformation( + 'buckaroo_error_url', + $additionalSkip['buckaroo_error_url'] + ); + } + if (isset($additionalSkip['buckaroo_reject_url'])) { + $subject->getInfoInstance()->setAdditionalInformation( + 'buckaroo_reject_url', + $additionalSkip['buckaroo_reject_url'] + ); + } + return $result; + } +} diff --git a/Model/Payment/Method/Config/ReturnUrl.php b/Model/Payment/Method/Config/ReturnUrl.php new file mode 100644 index 0000000..5402748 --- /dev/null +++ b/Model/Payment/Method/Config/ReturnUrl.php @@ -0,0 +1,27 @@ +returnUrl = $scopeConfig->getValue( + 'payment/buckaroo/return_url', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + + // Or you can set a default URL if not configured + if (!$this->returnUrl) { + $this->returnUrl = "https://default-return-url.com"; + } + } + + public function getReturnUrl() + { + return $this->returnUrl; + } +} \ No newline at end of file diff --git a/Plugin/OrderTransactionBuilderPlugin.php b/Plugin/OrderTransactionBuilderPlugin.php new file mode 100644 index 0000000..d5f42dd --- /dev/null +++ b/Plugin/OrderTransactionBuilderPlugin.php @@ -0,0 +1,185 @@ +getReturnUrl($subject); + return $returnUrl . '?' . http_build_query([ + 'orderId' => $subject->getOrder()->getIncrementId(), + ]); + } + + /** + * When a specific returnURl is set on the payment, use that one. + * Otherwise, use the default return url. + * + * @param OrderTransactionBuilder $subject + * @return string + */ + protected function getReturnUrl(OrderTransactionBuilder $subject): string + { + $payment = $subject->getOrder()->getPayment(); + $additionalInfo = $payment->getAdditionalInformation(); + if (isset($additionalInfo[AbstractTransactionBuilder::ADDITIONAL_RETURN_URL])) { + return $additionalInfo[AbstractTransactionBuilder::ADDITIONAL_RETURN_URL]; + } + + return $this->getDefaultUrl(); + + } + /** + * Overwrite the return url to include the order_id and maskedId, + * There is an issue with `setReturnUrl` mutation not working, and we don't want to do extra mutations anyway. + * + * @param OrderTransactionBuilder $subject + * @param string $result + * @return string + * @throws Exception + * @suppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetCancelUrl( + OrderTransactionBuilder $subject, + string $result + ): string { + $cancelUrl = $this->getCancelUrl($subject); + return $cancelUrl . '?' . http_build_query([ + 'orderId' => $subject->getOrder()->getIncrementId(), + ]); + } + + /** + * When a specific returnURl is set on the payment, use that one. + * Otherwise, use the default return url. + * + * @param OrderTransactionBuilder $subject + * @return string + */ + protected function getCancelUrl(OrderTransactionBuilder $subject): string + { + $payment = $subject->getOrder()->getPayment(); + $additionalInfo = $payment->getAdditionalInformation(); + if (isset($additionalInfo[AbstractTransactionBuilder::ADDITIONAL_CANCEL_URL])) { + return $additionalInfo[AbstractTransactionBuilder::ADDITIONAL_CANCEL_URL]; + } + + return $this->getDefaultUrl(); + } + + /** + * Overwrite the return url to include the order_id and maskedId, + * There is an issue with `setReturnUrl` mutation not working, and we don't want to do extra mutations anyway. + * + * @param OrderTransactionBuilder $subject + * @param string $result + * @return string + * @throws Exception + * @suppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetErrorUrl( + OrderTransactionBuilder $subject, + string $result + ): string { + $errorUrl = $this->getErrorUrl($subject); + return $errorUrl . '?' . http_build_query([ + 'orderId' => $subject->getOrder()->getIncrementId(), + ]); + } + + /** + * When a specific returnURl is set on the payment, use that one. + * Otherwise, use the default return url. + * + * @param OrderTransactionBuilder $subject + * @return string + */ + protected function getErrorUrl(OrderTransactionBuilder $subject): string + { + $payment = $subject->getOrder()->getPayment(); + $additionalInfo = $payment->getAdditionalInformation(); + if (isset($additionalInfo[AbstractTransactionBuilder::ADDITIONAL_ERROR_URL])) { + return $additionalInfo[AbstractTransactionBuilder::ADDITIONAL_ERROR_URL]; + } + + return $this->getDefaultUrl(); + } + + /** + * Overwrite the return url to include the order_id and maskedId, + * There is an issue with `setReturnUrl` mutation not working, and we don't want to do extra mutations anyway. + * + * @param OrderTransactionBuilder $subject + * @param string $result + * @return string + * @throws Exception + * @suppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetRejectUrl( + OrderTransactionBuilder $subject, + string $result + ): string { + $rejectUrl = $this->getRejectUrl($subject); + return $rejectUrl . '?' . http_build_query([ + 'orderId' => $subject->getOrder()->getIncrementId(), + ]); + } + + /** + * When a specific returnURl is set on the payment, use that one. + * Otherwise, use the default return url. + * + * @param OrderTransactionBuilder $subject + * @return string + */ + protected function getRejectUrl(OrderTransactionBuilder $subject): string + { + $payment = $subject->getOrder()->getPayment(); + $additionalInfo = $payment->getAdditionalInformation(); + if (isset($additionalInfo[AbstractTransactionBuilder::ADDITIONAL_REJECT_URL])) { + return $additionalInfo[AbstractTransactionBuilder::ADDITIONAL_REJECT_URL]; + } + + return $this->getDefaultUrl(); + } + + protected function getDefaultUrl(){ + $returnUrl = $this->scopeConfig->getValue('web/secure/frontend_base_link_url'); + try { + /** @var Account $accountConfig */ + $accountConfig = $this->configProviderFactory->get('account'); + $returnUrl .= $accountConfig->getSuccessRedirect(); + } catch (Exception $e) { + $returnUrl .= self::DEFAULT_REDIRECT_PATH; + } + return $returnUrl; + } +} diff --git a/Resolver/Cart/SetCancelUrl.php b/Resolver/Cart/SetCancelUrl.php new file mode 100644 index 0000000..880cd58 --- /dev/null +++ b/Resolver/Cart/SetCancelUrl.php @@ -0,0 +1,90 @@ +logger = $logger; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + + + parent::resolve($field, $context, $info, $value, $args); + + if (empty($args['input']['cancel_url'])) { + throw new GraphQlInputException( + __('Required parameter "cancel_url" is missing') + ); + } + + $cancelUrl = $args['input']['cancel_url']; + $cartId = $args['input']['cart_id']; + if ( + filter_var($cancelUrl, FILTER_VALIDATE_URL) === false || + !in_array(parse_url($cancelUrl, PHP_URL_SCHEME), ['http', 'https']) + ) { + throw new GraphQlInputException( + __('A valid "cancel_url" is required ') + ); + } + + try { + $quote = $this->getQuote($cartId, $context); + $quote->getPayment()->setAdditionalInformation(self::ADDITIONAL_CANCEL_URL, "{$cancelUrl}/{$cartId}"); + } catch (\Throwable $th) { + $this->logger->addDebug((string)$th); + throw new GraphQlInputException( + __('Unknown buckaroo error occurred') + ); + } + + return [ + "success" => true + ]; + } +} diff --git a/Resolver/Cart/SetErrorUrl.php b/Resolver/Cart/SetErrorUrl.php new file mode 100644 index 0000000..272bf54 --- /dev/null +++ b/Resolver/Cart/SetErrorUrl.php @@ -0,0 +1,90 @@ +logger = $logger; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + + + parent::resolve($field, $context, $info, $value, $args); + + if (empty($args['input']['error_url'])) { + throw new GraphQlInputException( + __('Required parameter "error_url" is missing') + ); + } + + $errorUrl = $args['input']['error_url']; + $cartId = $args['input']['cart_id']; + if ( + filter_var($errorUrl, FILTER_VALIDATE_URL) === false || + !in_array(parse_url($errorUrl, PHP_URL_SCHEME), ['http', 'https']) + ) { + throw new GraphQlInputException( + __('A valid "error_url" is required ') + ); + } + + try { + $quote = $this->getQuote($cartId, $context); + $quote->getPayment()->setAdditionalInformation(self::ADDITIONAL_ERROR_URL, "{$errorUrl}/{$cartId}"); + } catch (\Throwable $th) { + $this->logger->addDebug((string)$th); + throw new GraphQlInputException( + __('Unknown buckaroo error occurred') + ); + } + + return [ + "success" => true + ]; + } +} diff --git a/Resolver/Cart/SetRejectUrl.php b/Resolver/Cart/SetRejectUrl.php new file mode 100644 index 0000000..dad1320 --- /dev/null +++ b/Resolver/Cart/SetRejectUrl.php @@ -0,0 +1,90 @@ +logger = $logger; + } + + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + + + parent::resolve($field, $context, $info, $value, $args); + + if (empty($args['input']['reject_url'])) { + throw new GraphQlInputException( + __('Required parameter "reject_url" is missing') + ); + } + + $rejectUrl = $args['input']['reject_url']; + $cartId = $args['input']['cart_id']; + if ( + filter_var($rejectUrl, FILTER_VALIDATE_URL) === false || + !in_array(parse_url($rejectUrl, PHP_URL_SCHEME), ['http', 'https']) + ) { + throw new GraphQlInputException( + __('A valid "reject_url" is required ') + ); + } + + try { + $quote = $this->getQuote($cartId, $context); + $quote->getPayment()->setAdditionalInformation(self::ADDITIONAL_REJECT_URL, "{$rejectUrl}/{$cartId}"); + } catch (\Throwable $th) { + $this->logger->addDebug((string)$th); + throw new GraphQlInputException( + __('Unknown buckaroo error occurred') + ); + } + + return [ + "success" => true + ]; + } +} diff --git a/Resolver/Cart/SetReturnUrl.php b/Resolver/Cart/SetReturnUrl.php index ca6db25..6c98f1c 100644 --- a/Resolver/Cart/SetReturnUrl.php +++ b/Resolver/Cart/SetReturnUrl.php @@ -87,4 +87,4 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value "success" => true ]; } -} +} \ No newline at end of file diff --git a/etc/graphql/di.xml b/etc/graphql/di.xml index b073c5d..e5601f2 100644 --- a/etc/graphql/di.xml +++ b/etc/graphql/di.xml @@ -27,4 +27,16 @@ + + + + + + + + + diff --git a/etc/schema.graphqls b/etc/schema.graphqls index e776f2b..25ed5d8 100644 --- a/etc/schema.graphqls +++ b/etc/schema.graphqls @@ -22,6 +22,18 @@ type Mutation { input: BuckarooReturnUrlInput! ): BuckarooReturnUrl @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Cart\\SetReturnUrl") + setBuckarooCancelUrl( + input: BuckarooCancelUrlInput! + ): BuckarooCancelUrl @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Cart\\SetCancelUrl") + + setBuckarooErrorUrl( + input: BuckarooErrorUrlInput! + ): BuckarooErrorUrl @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Cart\\SetErrorUrl") + + setBuckarooRejectUrl( + input: BuckarooRejectUrlInput! + ): BuckarooRejectUrl @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\Cart\\SetRejectUrl") + buckarooProcessGiftcardTransaction( input: BuckarooProcessGiftcardTransactionInput ): BuckarooProcessGiftcardTransactionOutput @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\GiftcardTransactionResolver") @@ -31,13 +43,37 @@ type Mutation { ): BuckarooProcessGiftcardTransactionOutput @resolver(class: "Buckaroo\\Magento2Graphql\\Resolver\\VoucherTransactionResolver") } input BuckarooReturnUrlInput { - return_url: String! @doc(description: "Link to the success/failed order page"), + return_url: String! @doc(description: "Link to the success order page"), cart_id: String! @doc(description: "Cart id") } type BuckarooReturnUrl { success:Boolean } +input BuckarooCancelUrlInput { + cancel_url: String! @doc(description: "Link to the page after a cancellation"), + cart_id: String! @doc(description: "Cart id") +} +type BuckarooCancelUrl { + success:Boolean +} + +input BuckarooErrorUrlInput { + error_url: String! @doc(description: "Link to the page when an error occurs"), + cart_id: String! @doc(description: "Cart id") +} +type BuckarooErrorUrl { + success:Boolean +} + +input BuckarooRejectUrlInput { + reject_url: String! @doc(description: "Link to the page when the transaction gets rejected"), + cart_id: String! @doc(description: "Cart id") +} +type BuckarooRejectUrl { + success:Boolean +} + input BuckarooProcessVoucherTransactionInput { cart_id: String! @doc(description: "Cart id") voucher_code: String! @doc(description: "Voucher code") @@ -125,7 +161,11 @@ input BuckarooAdditionalInput { buckaroo_magento2_sepadirectdebit: BuckarooSepaDirectDebitInput buckaroo_magento2_tinka: BuckarooTinkaInput, buckaroo_magento2_klarna: BuckarooKlarnaInput, - buckaroo_magento2_klarnain: BuckarooKlarnaInput + buckaroo_magento2_klarnain: BuckarooKlarnaInput, + return_url: String @doc(description: "The URL to which the customer will be redirected after the payment has been completed. without query params") + cancel_url: String @doc(description: "The URL to which the customer will be redirected after the payment has been cancelled. without query params"), + error_url: String @doc(description: "The URL to which the customer will be redirected after the payment failed with due to an error. without query params"), + reject_url: String @doc(description: "The URL to which the customer will be redirected after the payment has been rejected. without query params"), } input BuckarooKlarnaInput { From 85631341caf3c1e186c2a662621cd0d2d27f98d4 Mon Sep 17 00:00:00 2001 From: Sander Date: Wed, 27 Nov 2024 13:22:01 +0100 Subject: [PATCH 4/5] BP-3649-Refactor return URL and add Cancel and Failed URL --- Plugin/FixSession.php | 69 +++++++++++++++++++++++++++++++++++++++++++ README.md | 5 ++++ etc/graphql/di.xml | 3 ++ 3 files changed, 77 insertions(+) create mode 100644 Plugin/FixSession.php diff --git a/Plugin/FixSession.php b/Plugin/FixSession.php new file mode 100644 index 0000000..613dbc5 --- /dev/null +++ b/Plugin/FixSession.php @@ -0,0 +1,69 @@ +header = $header; + $this->logger = $logger; + $this->sessionManager = $sessionManager; + } + + public function beforeSetPublicCookie( + PhpCookieManager $subject, + $name, + $value, + PublicCookieMetadata $metadata = null + ) + { + if ($metadata && method_exists($metadata, 'getSameSite') && ($name == $this->sessionManager->getName())) { + if ($metadata->getSameSite() != 'None') { + $metadata->setSecure(true); + $metadata->setSameSite('None'); + } + } + return [$name, $value, $metadata]; + } +} \ No newline at end of file diff --git a/README.md b/README.md index 4d28f11..676fea9 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,11 @@ mutation buckarooPaymentTransactionStatus(input: { transaction_id: "E397CF4C24E6 We really appreciate it when developers contribute to improve the Buckaroo plugins. If you want to contribute as well, then please follow our [Contribution Guidelines](CONTRIBUTING.md). +### Community is the :green_heart: of open source +Developing beautiful products is not possible without the input of a community. We thank everyone who actively contributes to this. + +[![florinel-chis's avatar](https://github.com/florinel-chis.png?size=50)](https://github.com/florinel-chis) [![peterkoppenaal's avatar](https://github.com/peterkoppenaal.png?size=50)](https://github.com/peterkoppenaal) [![serpentscode's avatar](https://github.com/serpentscode.png?size=50)](https://github.com/serpentscode) [![paales's avatar](https://github.com/paales.png?size=50)](https://github.com/paales) [![raoulguillermo's avatar](https://github.com/raoulguillermo.png?size=50)](https://github.com/raoulguillermo) + ### Versioning

diff --git a/etc/graphql/di.xml b/etc/graphql/di.xml index e5601f2..7e0276e 100644 --- a/etc/graphql/di.xml +++ b/etc/graphql/di.xml @@ -27,6 +27,9 @@ + + + From 1f82f7f40535ca97c3fe18c4b7d7bc24581a64ae Mon Sep 17 00:00:00 2001 From: Sander Date: Wed, 27 Nov 2024 13:27:51 +0100 Subject: [PATCH 5/5] BP-3649-Refactor return URL and add Cancel and Failed URL --- Plugin/FixSession.php | 17 +++-- README.md | 82 ++++++++++++------------- Resolver/VoucherTransactionResolver.php | 2 +- 3 files changed, 49 insertions(+), 52 deletions(-) diff --git a/Plugin/FixSession.php b/Plugin/FixSession.php index 613dbc5..f22d89a 100644 --- a/Plugin/FixSession.php +++ b/Plugin/FixSession.php @@ -17,7 +17,6 @@ * @copyright Copyright (c) Buckaroo B.V. * @license https://tldrlegal.com/license/mit-license */ - namespace Buckaroo\Magento2Graphql\Plugin; use Magento\Framework\HTTP\Header; @@ -41,23 +40,21 @@ class FixSession protected $sessionManager; public function __construct( - Header $header, - Log $logger, + Header $header, + Log $logger, SessionManager $sessionManager - ) - { + ) { $this->header = $header; $this->logger = $logger; $this->sessionManager = $sessionManager; } public function beforeSetPublicCookie( - PhpCookieManager $subject, - $name, - $value, + PhpCookieManager $subject, + $name, + $value, PublicCookieMetadata $metadata = null - ) - { + ) { if ($metadata && method_exists($metadata, 'getSameSite') && ($name == $this->sessionManager->getName())) { if ($metadata->getSameSite() != 'None') { $metadata->setSecure(true); diff --git a/README.md b/README.md index 676fea9..3fd81e4 100644 --- a/README.md +++ b/README.md @@ -19,15 +19,15 @@ This plugin is needed for our [Hÿva React checkout extension](https://github.co ### Requirements -To use the plugin you must use: +To use the plugin you must use: - Magento Open Source version 2.4.x - Buckaroo Magento 2 Payment module 1.43.0 or higher. ## Installation - - Install the module composer by running the following command: `composer require buckaroo/magento2graphql` - - Enable the module by running the following command: `php bin/magento module:enable Buckaroo_Magento2Graphql` - - Apply database updates by running the following command: `php bin/magento setup:upgrade` - - Flush the cache by running the following command: `php bin/magento cache:flush` +- Install the module composer by running the following command: `composer require buckaroo/magento2graphql` +- Enable the module by running the following command: `php bin/magento module:enable Buckaroo_Magento2Graphql` +- Apply database updates by running the following command: `php bin/magento setup:upgrade` +- Flush the cache by running the following command: `php bin/magento cache:flush` ## Usage @@ -36,21 +36,21 @@ To use the plugin you must use: - Get the available payments methods with additional data for gateways: ```graphql query { - cart(cart_id: "{ CART_ID }") { - available_payment_methods { - code - title - buckaroo_additional { - key - values { - name - code - img - } - value - } + cart(cart_id: "{ CART_ID }") { + available_payment_methods { + code + title + buckaroo_additional { + key + values { + name + code + img } + value + } } + } } ``` @@ -111,29 +111,29 @@ In order to get the payment status after the user is redirected back we will use ```graphql mutation buckarooPaymentTransactionStatus(input: { transaction_id: "E397CF4C24E64AA299F45246F9906F45" }) { - payment_status, - status_code +payment_status, +status_code } ``` - Get the available payments methods with additional data for gateways: ```graphql query { - cart(cart_id: "{ CART_ID }") { - available_payment_methods { - code - title - buckaroo_additional { - key - values { - name - code - img - } - value - } + cart(cart_id: "{ CART_ID }") { + available_payment_methods { + code + title + buckaroo_additional { + key + values { + name + code + img } + value + } } + } } ``` @@ -192,8 +192,8 @@ In order to get the payment status after the user is redirected back we will use ```graphql mutation buckarooPaymentTransactionStatus(input: { transaction_id: "E397CF4C24E64AA299F45246F9906F45" }) { - payment_status, - status_code +payment_status, +status_code } ``` ### Additional information @@ -204,15 +204,15 @@ mutation buckarooPaymentTransactionStatus(input: { transaction_id: "E397CF4C24E6 We really appreciate it when developers contribute to improve the Buckaroo plugins. If you want to contribute as well, then please follow our [Contribution Guidelines](CONTRIBUTING.md). -### Community is the :green_heart: of open source -Developing beautiful products is not possible without the input of a community. We thank everyone who actively contributes to this. - -[![florinel-chis's avatar](https://github.com/florinel-chis.png?size=50)](https://github.com/florinel-chis) [![peterkoppenaal's avatar](https://github.com/peterkoppenaal.png?size=50)](https://github.com/peterkoppenaal) [![serpentscode's avatar](https://github.com/serpentscode.png?size=50)](https://github.com/serpentscode) [![paales's avatar](https://github.com/paales.png?size=50)](https://github.com/paales) [![raoulguillermo's avatar](https://github.com/raoulguillermo.png?size=50)](https://github.com/raoulguillermo) +> ### Community is the :green_heart: of open source +> Developing beautiful products is not possible without the input of a community. We thank everyone who actively contributes to this. +> +> [![florinel-chis's avatar](https://github.com/florinel-chis.png?size=50)](https://github.com/florinel-chis) [![peterkoppenaal's avatar](https://github.com/peterkoppenaal.png?size=50)](https://github.com/peterkoppenaal) [![serpentscode's avatar](https://github.com/serpentscode.png?size=50)](https://github.com/serpentscode) [![paales's avatar](https://github.com/paales.png?size=50)](https://github.com/paales) [![raoulguillermo's avatar](https://github.com/raoulguillermo.png?size=50)](https://github.com/raoulguillermo) -### Versioning +### Versioning

Please note:
-This file has been prepared with the greatest possible care and is subject to language and/or spelling errors. +This file has been prepared with the greatest possible care and is subject to language and/or spelling errors. \ No newline at end of file diff --git a/Resolver/VoucherTransactionResolver.php b/Resolver/VoucherTransactionResolver.php index bc7ca9d..0a7859d 100644 --- a/Resolver/VoucherTransactionResolver.php +++ b/Resolver/VoucherTransactionResolver.php @@ -137,4 +137,4 @@ protected function argumentExists($args, $name) is_string($args['input'][$name]) && strlen(trim($args['input'][$name])) > 0; } -} +} \ No newline at end of file