diff --git a/.well-known/apple-LIVE-merchantid-domain-association b/.well-known/apple-LIVE-merchantid-domain-association new file mode 100644 index 000000000..7668e4310 --- /dev/null +++ b/.well-known/apple-LIVE-merchantid-domain-association @@ -0,0 +1 @@ +7B227073704964223A2246354246304143324336314131413238313043373531453439333444414433384346393037313041303935303844314133453241383436314141363232414145222C2276657273696F6E223A312C22637265617465644F6E223A313731353230343037313232362C227369676E6174757265223A223330383030363039326138363438383666373064303130373032613038303330383030323031303133313064333030623036303936303836343830313635303330343032303133303830303630393261383634383836663730643031303730313030303061303830333038323033653333303832303338386130303330323031303230323038313636333463386230653330353731373330306130363038326138363438636533643034303330323330376133313265333032633036303335353034303330633235343137303730366336353230343137303730366336393633363137343639366636653230343936653734363536373732363137343639366636653230343334313230326432303437333333313236333032343036303335353034306230633164343137303730366336353230343336353732373436393636363936333631373436393666366532303431373537343638366637323639373437393331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333031653137306433323334333033343332333933313337333433373332333735613137306433323339333033343332333833313337333433373332333635613330356633313235333032333036303335353034303330633163363536333633326437333664373032643632373236663662363537323264373336393637366535663535343333343264353035323466343433313134333031323036303335353034306230633062363934663533323035333739373337343635366437333331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333035393330313330363037326138363438636533643032303130363038326138363438636533643033303130373033343230303034633231353737656465626436633762323231386636386464373039306131323138646337623062643666326332383364383436303935643934616634613534313162383334323065643831316633343037653833333331663163353463336637656233323230643662616435643465666634393238393839336537633066313361333832303231313330383230323064333030633036303335353164313330313031666630343032333030303330316630363033353531643233303431383330313638303134323366323439633434663933653465663237653663346636323836633366613262626664326534623330343530363038326230363031303530353037303130313034333933303337333033353036303832623036303130353035303733303031383632393638373437343730336132663266366636333733373032653631373037303663363532653633366636643266366636333733373033303334326436313730373036633635363136393633363133333330333233303832303131643036303335353164323030343832303131343330383230313130333038323031306330363039326138363438383666373633363430353031333038316665333038316333303630383262303630313035303530373032303233303831623630633831623335323635366336393631366536333635323036663665323037343638363937333230363336353732373436393636363936333631373436353230363237393230363136653739323037303631373237343739323036313733373337353664363537333230363136333633363537303734363136653633363532303666363632303734363836353230373436383635366532303631373037303663363936333631363236633635323037333734363136653634363137323634323037343635373236643733323036313665363432303633366636653634363937343639366636653733323036663636323037353733363532633230363336353732373436393636363936333631373436353230373036663663363936333739323036313665363432303633363537323734363936363639363336313734363936663665323037303732363136333734363936333635323037333734363137343635366436353665373437333265333033363036303832623036303130353035303730323031313632613638373437343730336132663266373737373737326536313730373036633635326536333666366432663633363537323734363936363639363336313734363536313735373436383666373236393734373932663330333430363033353531643166303432643330326233303239613032376130323538363233363837343734373033613266326636333732366332653631373037303663363532653633366636643266363137303730366336353631363936333631333332653633373236633330316430363033353531643065303431363034313439343537646236666435373438313836383938393736326637653537383530376537396235383234333030653036303335353164306630313031666630343034303330323037383033303066303630393261383634383836663736333634303631643034303230353030333030613036303832613836343863653364303430333032303334393030333034363032323130306336663032336362323631346262333033383838613136323938336531613933663130353666353066613738636462396261346361323431636331346532356530323231303062653363643064666431363234376636343934343735333830653964343463323238613130383930613361316463373234623862346362383838393831386263333038323032656533303832303237356130303330323031303230323038343936643266626633613938646139373330306130363038326138363438636533643034303330323330363733313162333031393036303335353034303330633132343137303730366336353230353236663666373432303433343132303264323034373333333132363330323430363033353530343062306331643431373037303663363532303433363537323734363936363639363336313734363936663665323034313735373436383666373236393734373933313133333031313036303335353034306130633061343137303730366336353230343936653633326533313062333030393036303335353034303631333032353535333330316531373064333133343330333533303336333233333334333633333330356131373064333233393330333533303336333233333334333633333330356133303761333132653330326330363033353530343033306332353431373037303663363532303431373037303663363936333631373436393666366532303439366537343635363737323631373436393666366532303433343132303264323034373333333132363330323430363033353530343062306331643431373037303663363532303433363537323734363936363639363336313734363936663665323034313735373436383666373236393734373933313133333031313036303335353034306130633061343137303730366336353230343936653633326533313062333030393036303335353034303631333032353535333330353933303133303630373261383634386365336430323031303630383261383634386365336430333031303730333432303030346630313731313834313964373634383564353161356532353831303737366538383061326566646537626165346465303864666334623933653133333536643536363562333561653232643039373736306432323465376262613038666437363137636538386362373662623636373062656338653832393834666635343435613338316637333038316634333034363036303832623036303130353035303730313031303433613330333833303336303630383262303630313035303530373330303138363261363837343734373033613266326636663633373337303265363137303730366336353265363336663664326636663633373337303330333432643631373037303663363537323666366637343633363136373333333031643036303335353164306530343136303431343233663234396334346639336534656632376536633466363238366333666132626266643265346233303066303630333535316431333031303166663034303533303033303130316666333031663036303335353164323330343138333031363830313462626230646561313538333338383961613438613939646562656264656261666461636232346162333033373036303335353164316630343330333032653330326361303261613032383836323636383734373437303361326632663633373236633265363137303730366336353265363336663664326636313730373036633635373236663666373436333631363733333265363337323663333030653036303335353164306630313031666630343034303330323031303633303130303630613261383634383836663736333634303630323065303430323035303033303061303630383261383634386365336430343033303230333637303033303634303233303361636637323833353131363939623138366662333563333536636136326266663431376564643930663735346461323865626566313963383135653432623738396638393866373962353939663938643534313064386639646539633266653032333033323264643534343231623061333035373736633564663333383362393036376664313737633263323136643936346663363732363938323132366635346638376137643162393963623962303938393231363130363939306630393932316430303030333138323031383833303832303138343032303130313330383138363330376133313265333032633036303335353034303330633235343137303730366336353230343137303730366336393633363137343639366636653230343936653734363536373732363137343639366636653230343334313230326432303437333333313236333032343036303335353034306230633164343137303730366336353230343336353732373436393636363936333631373436393666366532303431373537343638366637323639373437393331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533303230383136363334633862306533303537313733303062303630393630383634383031363530333034303230316130383139333330313830363039326138363438383666373064303130393033333130623036303932613836343838366637306430313037303133303163303630393261383634383836663730643031303930353331306631373064333233343330333533303338333233313333333433333331356133303238303630393261383634383836663730643031303933343331316233303139333030623036303936303836343830313635303330343032303161313061303630383261383634386365336430343033303233303266303630393261383634383836663730643031303930343331323230343230353936643939343335373738303366313137346361653066633761343164383634653964366266336535363638646164356563393334303937313439633762623330306130363038326138363438636533643034303330323034343733303435303232313030383565623363643837343731346466343461333830373838643439626537656630303630643765313236633966653638663261333336386363623233373363643032323035366535336363363330376433393561643465663532376234333531323462616636653761383537363030616463376135343561333862613039376139643734303030303030303030303030227D \ No newline at end of file diff --git a/.well-known/apple-SANDBOX-merchantid-domain-association b/.well-known/apple-SANDBOX-merchantid-domain-association new file mode 100644 index 000000000..976bc9863 --- /dev/null +++ b/.well-known/apple-SANDBOX-merchantid-domain-association @@ -0,0 +1 @@ +7B227073704964223A2241443631324543383841333039314132314539434132433035304439454130353741414535444341304542413237424243333838463239344231353534434233222C2276657273696F6E223A312C22637265617465644F6E223A313731353237313630333931352C227369676E6174757265223A223330383030363039326138363438383666373064303130373032613038303330383030323031303133313064333030623036303936303836343830313635303330343032303133303830303630393261383634383836663730643031303730313030303061303830333038323033653333303832303338386130303330323031303230323038313636333463386230653330353731373330306130363038326138363438636533643034303330323330376133313265333032633036303335353034303330633235343137303730366336353230343137303730366336393633363137343639366636653230343936653734363536373732363137343639366636653230343334313230326432303437333333313236333032343036303335353034306230633164343137303730366336353230343336353732373436393636363936333631373436393666366532303431373537343638366637323639373437393331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333031653137306433323334333033343332333933313337333433373332333735613137306433323339333033343332333833313337333433373332333635613330356633313235333032333036303335353034303330633163363536333633326437333664373032643632373236663662363537323264373336393637366535663535343333343264353035323466343433313134333031323036303335353034306230633062363934663533323035333739373337343635366437333331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333035393330313330363037326138363438636533643032303130363038326138363438636533643033303130373033343230303034633231353737656465626436633762323231386636386464373039306131323138646337623062643666326332383364383436303935643934616634613534313162383334323065643831316633343037653833333331663163353463336637656233323230643662616435643465666634393238393839336537633066313361333832303231313330383230323064333030633036303335353164313330313031666630343032333030303330316630363033353531643233303431383330313638303134323366323439633434663933653465663237653663346636323836633366613262626664326534623330343530363038326230363031303530353037303130313034333933303337333033353036303832623036303130353035303733303031383632393638373437343730336132663266366636333733373032653631373037303663363532653633366636643266366636333733373033303334326436313730373036633635363136393633363133333330333233303832303131643036303335353164323030343832303131343330383230313130333038323031306330363039326138363438383666373633363430353031333038316665333038316333303630383262303630313035303530373032303233303831623630633831623335323635366336393631366536333635323036663665323037343638363937333230363336353732373436393636363936333631373436353230363237393230363136653739323037303631373237343739323036313733373337353664363537333230363136333633363537303734363136653633363532303666363632303734363836353230373436383635366532303631373037303663363936333631363236633635323037333734363136653634363137323634323037343635373236643733323036313665363432303633366636653634363937343639366636653733323036663636323037353733363532633230363336353732373436393636363936333631373436353230373036663663363936333739323036313665363432303633363537323734363936363639363336313734363936663665323037303732363136333734363936333635323037333734363137343635366436353665373437333265333033363036303832623036303130353035303730323031313632613638373437343730336132663266373737373737326536313730373036633635326536333666366432663633363537323734363936363639363336313734363536313735373436383666373236393734373932663330333430363033353531643166303432643330326233303239613032376130323538363233363837343734373033613266326636333732366332653631373037303663363532653633366636643266363137303730366336353631363936333631333332653633373236633330316430363033353531643065303431363034313439343537646236666435373438313836383938393736326637653537383530376537396235383234333030653036303335353164306630313031666630343034303330323037383033303066303630393261383634383836663736333634303631643034303230353030333030613036303832613836343863653364303430333032303334393030333034363032323130306336663032336362323631346262333033383838613136323938336531613933663130353666353066613738636462396261346361323431636331346532356530323231303062653363643064666431363234376636343934343735333830653964343463323238613130383930613361316463373234623862346362383838393831386263333038323032656533303832303237356130303330323031303230323038343936643266626633613938646139373330306130363038326138363438636533643034303330323330363733313162333031393036303335353034303330633132343137303730366336353230353236663666373432303433343132303264323034373333333132363330323430363033353530343062306331643431373037303663363532303433363537323734363936363639363336313734363936663665323034313735373436383666373236393734373933313133333031313036303335353034306130633061343137303730366336353230343936653633326533313062333030393036303335353034303631333032353535333330316531373064333133343330333533303336333233333334333633333330356131373064333233393330333533303336333233333334333633333330356133303761333132653330326330363033353530343033306332353431373037303663363532303431373037303663363936333631373436393666366532303439366537343635363737323631373436393666366532303433343132303264323034373333333132363330323430363033353530343062306331643431373037303663363532303433363537323734363936363639363336313734363936663665323034313735373436383666373236393734373933313133333031313036303335353034306130633061343137303730366336353230343936653633326533313062333030393036303335353034303631333032353535333330353933303133303630373261383634386365336430323031303630383261383634386365336430333031303730333432303030346630313731313834313964373634383564353161356532353831303737366538383061326566646537626165346465303864666334623933653133333536643536363562333561653232643039373736306432323465376262613038666437363137636538386362373662623636373062656338653832393834666635343435613338316637333038316634333034363036303832623036303130353035303730313031303433613330333833303336303630383262303630313035303530373330303138363261363837343734373033613266326636663633373337303265363137303730366336353265363336663664326636663633373337303330333432643631373037303663363537323666366637343633363136373333333031643036303335353164306530343136303431343233663234396334346639336534656632376536633466363238366333666132626266643265346233303066303630333535316431333031303166663034303533303033303130316666333031663036303335353164323330343138333031363830313462626230646561313538333338383961613438613939646562656264656261666461636232346162333033373036303335353164316630343330333032653330326361303261613032383836323636383734373437303361326632663633373236633265363137303730366336353265363336663664326636313730373036633635373236663666373436333631363733333265363337323663333030653036303335353164306630313031666630343034303330323031303633303130303630613261383634383836663736333634303630323065303430323035303033303061303630383261383634386365336430343033303230333637303033303634303233303361636637323833353131363939623138366662333563333536636136326266663431376564643930663735346461323865626566313963383135653432623738396638393866373962353939663938643534313064386639646539633266653032333033323264643534343231623061333035373736633564663333383362393036376664313737633263323136643936346663363732363938323132366635346638376137643162393963623962303938393231363130363939306630393932316430303030333138323031383833303832303138343032303130313330383138363330376133313265333032633036303335353034303330633235343137303730366336353230343137303730366336393633363137343639366636653230343936653734363536373732363137343639366636653230343334313230326432303437333333313236333032343036303335353034306230633164343137303730366336353230343336353732373436393636363936333631373436393666366532303431373537343638366637323639373437393331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533303230383136363334633862306533303537313733303062303630393630383634383031363530333034303230316130383139333330313830363039326138363438383666373064303130393033333130623036303932613836343838366637306430313037303133303163303630393261383634383836663730643031303930353331306631373064333233343330333533303339333133363332333033303333356133303238303630393261383634383836663730643031303933343331316233303139333030623036303936303836343830313635303330343032303161313061303630383261383634386365336430343033303233303266303630393261383634383836663730643031303930343331323230343230633364366466616634636131326539643331666630363161636563303536613232653131386261333262633934346664323166336231373838363634646634363330306130363038326138363438636533643034303330323034343733303435303232313030633961346263306665316537366332356636343136303264306238313462363666643264376534623263636537343138633132343532313866356230353963363032323036623632373361383536363830633738313064303131333538666463383563633764303730656531393736333234316537356336636237353732326164303930303030303030303030303030227D \ No newline at end of file diff --git a/.well-known/index.php b/.well-known/index.php new file mode 100644 index 000000000..296d682e8 --- /dev/null +++ b/.well-known/index.php @@ -0,0 +1,28 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +header('Location: ../'); +exit; diff --git a/config.xml b/config.xml index da679e8ac..d1014d29f 100644 --- a/config.xml +++ b/config.xml @@ -2,7 +2,7 @@ ps_checkout - + diff --git a/config/common.yml b/config/common.yml index 58383c151..013d923e1 100644 --- a/config/common.yml +++ b/config/common.yml @@ -88,6 +88,7 @@ services: PrestaShop\Module\PrestashopCheckout\PayPal\OAuth\Query\GetPayPalGetUserIdTokenQuery: 'PrestaShop\Module\PrestashopCheckout\PayPal\OAuth\Query\GetPayPalGetUserIdTokenQueryHandler' PrestaShop\Module\PrestashopCheckout\PayPal\Order\Command\SavePayPalOrderCommand: 'PrestaShop\Module\PrestashopCheckout\PayPal\Order\CommandHandler\SavePayPalOrderCommandHandler' PrestaShop\Module\PrestashopCheckout\PayPal\GooglePay\Query\GetGooglePayTransactionInfoQuery: 'PrestaShop\Module\PrestashopCheckout\PayPal\GooglePay\Query\GetGooglePayTransactionInfoQueryHandler' + PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Query\GetApplePayPaymentRequestQuery: 'PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Query\GetApplePayPaymentRequestQueryHandler' PrestaShop\Module\PrestashopCheckout\Event\SymfonyEventDispatcherFactory: class: 'PrestaShop\Module\PrestashopCheckout\Event\SymfonyEventDispatcherFactory' @@ -479,3 +480,9 @@ services: public: true arguments: - '@PrestaShop\Module\PrestashopCheckout\Translations\Translations' + + PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Builder\ApplePayPaymentRequestBuilder: + class: 'PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Builder\ApplePayPaymentRequestBuilder' + public: true + arguments: + - '@PrestaShop\Module\PrestashopCheckout\Translations\Translations' diff --git a/config/query-handlers.yml b/config/query-handlers.yml index 8997caaa4..4984dceaa 100644 --- a/config/query-handlers.yml +++ b/config/query-handlers.yml @@ -86,3 +86,9 @@ services: public: true arguments: - '@PrestaShop\Module\PrestashopCheckout\PayPal\GooglePay\Builder\GooglePayTransactionInfoBuilder' + + PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Query\GetApplePayPaymentRequestQueryHandler: + class: 'PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Query\GetApplePayPaymentRequestQueryHandler' + public: true + arguments: + - '@PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Builder\ApplePayPaymentRequestBuilder' diff --git a/controllers/front/applepay.php b/controllers/front/applepay.php new file mode 100644 index 000000000..f74fea18c --- /dev/null +++ b/controllers/front/applepay.php @@ -0,0 +1,115 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +use PrestaShop\Module\PrestashopCheckout\Cart\Exception\CartException; +use PrestaShop\Module\PrestashopCheckout\Cart\ValueObject\CartId; +use PrestaShop\Module\PrestashopCheckout\CommandBus\CommandBusInterface; +use PrestaShop\Module\PrestashopCheckout\Controller\AbstractFrontController; +use PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Query\GetApplePayPaymentRequestQuery; +use PrestaShop\Module\PrestashopCheckout\PayPal\PayPalConfiguration; + +/** + * This controller receive ajax call on customer click on a payment button + */ +class Ps_CheckoutApplepayModuleFrontController extends AbstractFrontController +{ + /** + * @var Ps_checkout + */ + public $module; + + /** + * @var CommandBusInterface + */ + private $commandBus; + + /** + * @see FrontController::postProcess() + */ + public function postProcess() + { + try { + $action = ''; + $bodyContent = file_get_contents('php://input'); + + if (!empty($bodyContent)) { + $bodyValues = json_decode($bodyContent, true); + $action = $bodyValues['action']; + } + + if (empty($action)) { + $getParam = Tools::getValue('action'); + if ($getParam === 'getDomainAssociation') { + $action = $getParam; + } + } + + $this->commandBus = $this->module->getService('ps_checkout.bus.command'); + + switch ($action) { + case 'getPaymentRequest': + $this->getPaymentRequest(); + break; + case 'getDomainAssociation': + /** + * @var PayPalConfiguration $payPalConfiguration + */ + $payPalConfiguration = $this->module->getService(PayPalConfiguration::class); + $environment = $payPalConfiguration->getPaymentMode(); + $associationFile = _PS_MODULE_DIR_ . "ps_checkout/.well-known/apple-$environment-merchantid-domain-association"; + if (file_exists($associationFile)) { + if (!headers_sent()) { + ob_end_clean(); + header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0'); + header('X-Robots-Tag: noindex, nofollow'); + header_remove('Last-Modified'); + header('Content-Type: text/plain', true, 200); + } + echo file_get_contents($associationFile); + exit; + } else { + $this->exitWithExceptionMessage(new Exception('File not found', 404)); + } + break; + default: + $this->exitWithExceptionMessage(new Exception('Invalid request', 400)); + } + } catch (Exception $exception) { + $this->exitWithExceptionMessage($exception); + } + } + + /** + * @return void + * + * @throws CartException + */ + private function getPaymentRequest() + { + $cartId = new CartId($this->context->cart->id); + $query = new GetApplePayPaymentRequestQuery($cartId); + $paymentRequest = $this->commandBus->handle($query); + + $this->exitWithResponse([ + 'httpCode' => 200, + 'body' => $paymentRequest->getPayload()->toArray(), + ]); + } +} diff --git a/ps_checkout.php b/ps_checkout.php index 498ee83ba..400dbab29 100755 --- a/ps_checkout.php +++ b/ps_checkout.php @@ -46,6 +46,7 @@ class Ps_checkout extends PaymentModule 'actionObjectOrderPaymentUpdateAfter', 'displayPaymentReturn', 'displayOrderDetail', + 'moduleRoutes' ]; /** @@ -106,6 +107,8 @@ class Ps_checkout extends PaymentModule 'PS_CHECKOUT_DISPLAY_LOGO_PRODUCT' => '1', 'PS_CHECKOUT_DISPLAY_LOGO_CART' => '1', 'PS_CHECKOUT_HOSTED_FIELDS_CONTINGENCIES' => 'SCA_WHEN_REQUIRED', + 'PS_CHECKOUT_DOMAIN_REGISTERED_SANDBOX' => false, + 'PS_CHECKOUT_DOMAIN_REGISTERED_LIVE' => false, ]; public $confirmUninstall; @@ -113,7 +116,7 @@ class Ps_checkout extends PaymentModule // Needed in order to retrieve the module version easier (in api call headers) than instanciate // the module each time to get the version - const VERSION = '8.4.1.0'; + const VERSION = '8.4.2.0'; const INTEGRATION_DATE = '2024-04-01'; @@ -134,7 +137,7 @@ public function __construct() // We cannot use the const VERSION because the const is not computed by addons marketplace // when the zip is uploaded - $this->version = '8.4.1.0'; + $this->version = '8.4.2.0'; $this->author = 'PrestaShop'; $this->currencies = true; $this->currencies_mode = 'checkbox'; @@ -1042,6 +1045,7 @@ public function hookActionFrontControllerSetMedia() $this->name . 'VaultUrl' => $this->context->link->getModuleLink($this->name, 'vault', [], true), $this->name . 'PaymentUrl' => $this->context->link->getModuleLink($this->name, 'payment', [], true), $this->name . 'GooglePayUrl' => $this->context->link->getModuleLink($this->name, 'googlepay', [], true), + $this->name . 'ApplePayUrl' => $this->context->link->getModuleLink($this->name, 'applepay', [], true), $this->name . 'CheckoutUrl' => $this->getCheckoutPageUrl(), $this->name . 'ConfirmUrl' => $this->context->link->getPageLink('order-confirmation', true, (int) $this->context->language->id), $this->name . 'PayPalSdkConfig' => $payPalSdkConfigurationBuilder->buildConfiguration(), @@ -1098,6 +1102,9 @@ public function hookActionFrontControllerSetMedia() 'express-button.checkout.express-checkout' => $this->l('Express Checkout'), 'error.paypal-sdk' => $this->l('No PayPal Javascript SDK Instance'), 'error.google-pay-sdk' => $this->l('No Google Pay Javascript SDK Instance'), + 'error.google-pay.transaction-info' => $this->l('An error occurred fetching Google Pay transaction info'), + 'error.apple-pay-sdk' => $this->l('No Apple Pay Javascript SDK Instance'), + 'error.apple-pay.payment-request' => $this->l('An error occurred fetching Apple Pay payment request'), 'checkout.payment.others.link.label' => $this->l('Other payment methods'), 'checkout.payment.others.confirm.button.label' => $this->l('I confirm my order'), 'checkout.form.error.label' => $this->l('There was an error during the payment. Please try again or contact the support.'), @@ -1785,4 +1792,20 @@ public function hookDisplayOrderDetail(array $params) return $this->display(__FILE__, 'views/templates/hook/displayOrderDetail.tpl'); } + + public function hookModuleRoutes() + { + return [ + 'ps_checkout_applepay' => [ + 'rule' => '.well-known/apple-developer-merchantid-domain-association', + 'keywords' => [], + 'controller' => 'applepay', + 'params' => [ + 'fc' => 'module', + 'module' => 'ps_checkout', + 'action' => 'getDomainAssociation' + ], + ] + ]; + } } diff --git a/src/FundingSource/FundingSourceCollectionBuilder.php b/src/FundingSource/FundingSourceCollectionBuilder.php index 96dcbe195..a97fb3344 100644 --- a/src/FundingSource/FundingSourceCollectionBuilder.php +++ b/src/FundingSource/FundingSourceCollectionBuilder.php @@ -113,6 +113,12 @@ public function create() $googlePay->setIsEnabled($this->configuration->isEnabled('google_pay')); $googlePay->setCountries($this->eligibilityConstraint->getCountries('google_pay')); - return [$paypal, $paylater, $card, $bancontact, $eps, $giropay, $ideal, $mybank, $p24, $blik, $googlePay]; + // Apple pay + $applePay = new FundingSourceEntity('apple_pay'); + $applePay->setPosition($this->configuration->getPosition('apple_pay', 12)); + $applePay->setIsEnabled($this->configuration->isEnabled('apple_pay')); + $applePay->setCountries($this->eligibilityConstraint->getCountries('apple_pay')); + + return [$paypal, $paylater, $card, $bancontact, $eps, $giropay, $ideal, $mybank, $p24, $blik, $googlePay, $applePay]; } } diff --git a/src/FundingSource/FundingSourceConfiguration.php b/src/FundingSource/FundingSourceConfiguration.php index 01a25b409..e16033be2 100644 --- a/src/FundingSource/FundingSourceConfiguration.php +++ b/src/FundingSource/FundingSourceConfiguration.php @@ -67,6 +67,6 @@ public function isEnabled($fundingSourceName) return (bool) $fundingSource['active']; } - return true; + return false; } } diff --git a/src/FundingSource/FundingSourceEligibilityConstraint.php b/src/FundingSource/FundingSourceEligibilityConstraint.php index e107f518f..de29a6d48 100644 --- a/src/FundingSource/FundingSourceEligibilityConstraint.php +++ b/src/FundingSource/FundingSourceEligibilityConstraint.php @@ -42,6 +42,7 @@ public function getCountries($fundingSourceName) 'p24' => ['PL'], 'paylater' => ['FR', 'GB', 'US', 'ES', 'IT'], 'google_pay' => ['AU', 'AT', 'BE', 'BG', 'CA', 'CN', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HU', 'IE', 'IT', 'LV', 'LI', 'LT', 'LU', 'MK', 'MT', 'NL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'GB', 'US'], + 'apple_pay' => ['AU', 'AT', 'BE', 'BG', 'CA', 'CN', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HU', 'IE', 'IT', 'LV', 'LI', 'LT', 'LU', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'GB', 'US'], ]; return $countries[$fundingSourceName]; @@ -58,6 +59,7 @@ public function getCurrencies($fundingSourceName) { $currencies = [ 'google_pay' => ['AUD', 'BRL', 'CAD', 'CHF', 'CZK', 'DKK', 'EUR', 'GBP', 'HKD', 'HUF', 'ILS', 'JPY', 'MXN', 'NOK', 'NZD', 'PHP', 'PLN', 'SEK', 'SGD', 'THB', 'TWD', 'USD'], + 'apple_pay' => ['AUD', 'BRL', 'CAD', 'CHF', 'CZK', 'DKK', 'EUR', 'GBP', 'HKD', 'HUF', 'ILS', 'JPY', 'MXN', 'NOK', 'NZD', 'PHP', 'PLN', 'SEK', 'SGD', 'THB', 'TWD', 'USD'], ]; return $currencies[$fundingSourceName]; diff --git a/src/FundingSource/FundingSourcePresenter.php b/src/FundingSource/FundingSourcePresenter.php index d6902b3ca..4e91198b1 100644 --- a/src/FundingSource/FundingSourcePresenter.php +++ b/src/FundingSource/FundingSourcePresenter.php @@ -73,7 +73,7 @@ public function present($entity, $isAdmin) $entity->getIsToggleable(), null, null, - $name === 'google_pay' ? $this->paymentMethodLogoProvider->getLogoByPaymentSource([$name => []]) : null + in_array($name, ['google_pay', 'apple_pay']) ? $this->paymentMethodLogoProvider->getLogoByPaymentSource([$name => []]) : null ); } diff --git a/src/FundingSource/FundingSourceTranslationProvider.php b/src/FundingSource/FundingSourceTranslationProvider.php index 9b85066f9..9b1a8f08e 100644 --- a/src/FundingSource/FundingSourceTranslationProvider.php +++ b/src/FundingSource/FundingSourceTranslationProvider.php @@ -65,6 +65,7 @@ public function __construct(Module $module) 'mercadopago' => 'Mercado Pago', 'sepa' => 'SEPA', 'google_pay' => 'Google Pay', + 'apple_pay' => 'Apple Pay', 'token' => $module->l('Pay with %s', 'fundingsourcetranslationprovider'), ]; diff --git a/src/PayPal/ApplePay/Builder/ApplePayPaymentRequestBuilder.php b/src/PayPal/ApplePay/Builder/ApplePayPaymentRequestBuilder.php new file mode 100644 index 000000000..8a92eb432 --- /dev/null +++ b/src/PayPal/ApplePay/Builder/ApplePayPaymentRequestBuilder.php @@ -0,0 +1,81 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Builder; + +use PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\DTO\ApplePayLineItem; +use PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\DTO\ApplePayPaymentRequest; +use PrestaShop\Module\PrestashopCheckout\Translations\Translations; + +class ApplePayPaymentRequestBuilder +{ + /** + * @var Translations + */ + private $translations; + + public function __construct(Translations $translations) + { + $this->translations = current($translations->getTranslations())['apple_pay']; + } + + /** + * @return ApplePayPaymentRequest + */ + public function buildMinimalPaymentRequestFromPayPalPayload($payload) + { + $paymentRequest = new ApplePayPaymentRequest(); + + $total = new ApplePayLineItem(); + $total->setAmount($payload['amount']['value']) + ->setLabel($this->translations['total']); + + $paymentRequest->setCurrencyCode($payload['amount']['currency_code']) + ->setTotal($total); + + return $paymentRequest; + } + + /** + * Get decimal to round correspondent to the payment currency used + * Advise from PayPal: Always round to 2 decimals except for HUF, JPY and TWD + * currencies which require a round with 0 decimal + * + * @return int + */ + private function getNbDecimalToRound($currencyIsoCode) + { + if (in_array($currencyIsoCode, ['HUF', 'JPY', 'TWD'], true)) { + return 0; + } + + return 2; + } + + /** + * @param float|int|string $amount + * + * @return string + */ + private function formatAmount($amount, $currencyIsoCode) + { + return sprintf("%01.{$this->getNbDecimalToRound($currencyIsoCode)}F", $amount); + } +} diff --git a/src/PayPal/ApplePay/Builder/index.php b/src/PayPal/ApplePay/Builder/index.php new file mode 100644 index 000000000..296d682e8 --- /dev/null +++ b/src/PayPal/ApplePay/Builder/index.php @@ -0,0 +1,28 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +header('Location: ../'); +exit; diff --git a/src/PayPal/ApplePay/DTO/ApplePayLineItem.php b/src/PayPal/ApplePay/DTO/ApplePayLineItem.php new file mode 100644 index 000000000..e8a4408c6 --- /dev/null +++ b/src/PayPal/ApplePay/DTO/ApplePayLineItem.php @@ -0,0 +1,297 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\DTO; + +use DateTime; + +class ApplePayLineItem +{ + const TYPE_PENDING = 'pending'; + const TYPE_FINAL = 'final'; + const PAYMENT_TIMING_IMMEDIATE = 'immediate'; + const PAYMENT_TIMING_RECURRING = 'recurring'; + const PAYMENT_TIMING_DEFERRED = 'deferred'; + const PAYMENT_TIMING_AUTOMATIC_RELOAD = 'automaticReload'; + const RECURRING_PAYMENT_INTERVAL_UNIT_DAY = 'day'; + const RECURRING_PAYMENT_INTERVAL_UNIT_WEEK = 'week'; + const RECURRING_PAYMENT_INTERVAL_UNIT_MONTH = 'month'; + const RECURRING_PAYMENT_INTERVAL_UNIT_YEAR = 'year'; + + /** + * @var self::TYPE_PENDING|self::TYPE_FINAL + */ + private $type = self::TYPE_FINAL; + /** + * @var string + */ + private $label; + /** + * @var string + */ + private $amount; + /** + * @var self::PAYMENT_TIMING_IMMEDIATE|self::PAYMENT_TIMING_RECURRING|self::PAYMENT_TIMING_DEFERRED|self::PAYMENT_TIMING_AUTOMATIC_RELOAD + */ + private $paymentTiming; + /** + * @var DateTime|null + */ + private $recurringPaymentStartDate = null; + /** + * @var self::RECURRING_PAYMENT_INTERVAL_UNIT_DAY|self::RECURRING_PAYMENT_INTERVAL_UNIT_WEEK|self::RECURRING_PAYMENT_INTERVAL_UNIT_MONTH|self::RECURRING_PAYMENT_INTERVAL_UNIT_YEAR + */ + private $recurringPaymentIntervalUnit; + /** + * @var int + */ + private $recurringPaymentIntervalCount; + /** + * @var DateTime|null + */ + private $recurringPaymentEndDate = null; + /** + * @var DateTime|null + */ + private $deferredPaymentDate = null; + /** + * @var string + */ + private $automaticReloadPaymentThresholdAmount; + + /** + * @param self::TYPE_PENDING|self::TYPE_FINAL $type + * + * @return ApplePayLineItem + */ + public function setType($type) + { + $this->type = $type; + + return $this; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @param string $label + * + * @return ApplePayLineItem + */ + public function setLabel($label) + { + $this->label = $label; + + return $this; + } + + /** + * @return string + */ + public function getLabel() + { + return $this->label; + } + + /** + * @param string $amount + * + * @return ApplePayLineItem + */ + public function setAmount($amount) + { + $this->amount = $amount; + + return $this; + } + + /** + * @return string + */ + public function getAmount() + { + return $this->amount; + } + + /** + * @param self::PAYMENT_TIMING_IMMEDIATE|self::PAYMENT_TIMING_RECURRING|self::PAYMENT_TIMING_DEFERRED|self::PAYMENT_TIMING_AUTOMATIC_RELOAD $paymentTiming + * + * @return ApplePayLineItem + */ + public function setPaymentTiming($paymentTiming) + { + $this->paymentTiming = $paymentTiming; + + return $this; + } + + /** + * @return string + */ + public function getPaymentTiming() + { + return $this->paymentTiming; + } + + /** + * @param DateTime $recurringPaymentStartDate + * + * @return ApplePayLineItem + */ + public function setRecurringPaymentStartDate($recurringPaymentStartDate) + { + $this->recurringPaymentStartDate = $recurringPaymentStartDate; + + return $this; + } + + /** + * @return DateTime + */ + public function getRecurringPaymentStartDate() + { + return $this->recurringPaymentStartDate; + } + + /** + * @param self::RECURRING_PAYMENT_INTERVAL_UNIT_DAY|self::RECURRING_PAYMENT_INTERVAL_UNIT_WEEK|self::RECURRING_PAYMENT_INTERVAL_UNIT_MONTH|self::RECURRING_PAYMENT_INTERVAL_UNIT_YEAR $recurringPaymentIntervalUnit + * + * @return ApplePayLineItem + */ + public function setRecurringPaymentIntervalUnit($recurringPaymentIntervalUnit) + { + $this->recurringPaymentIntervalUnit = $recurringPaymentIntervalUnit; + + return $this; + } + + /** + * @return string + */ + public function getRecurringPaymentIntervalUnit() + { + return $this->recurringPaymentIntervalUnit; + } + + /** + * @param int $recurringPaymentIntervalCount + * + * @return ApplePayLineItem + */ + public function setRecurringPaymentIntervalCount($recurringPaymentIntervalCount) + { + $this->recurringPaymentIntervalCount = $recurringPaymentIntervalCount; + + return $this; + } + + /** + * @return int + */ + public function getRecurringPaymentIntervalCount() + { + return $this->recurringPaymentIntervalCount; + } + + /** + * @param DateTime $recurringPaymentEndDate + * + * @return ApplePayLineItem + */ + public function setRecurringPaymentEndDate($recurringPaymentEndDate) + { + $this->recurringPaymentEndDate = $recurringPaymentEndDate; + + return $this; + } + + /** + * @return DateTime + */ + public function getRecurringPaymentEndDate() + { + return $this->recurringPaymentEndDate; + } + + /** + * @param DateTime $deferredPaymentDate + * + * @return ApplePayLineItem + */ + public function setDeferredPaymentDate($deferredPaymentDate) + { + $this->deferredPaymentDate = $deferredPaymentDate; + + return $this; + } + + /** + * @return DateTime + */ + public function getDeferredPaymentDate() + { + return $this->deferredPaymentDate; + } + + /** + * @param string $automaticReloadPaymentThresholdAmount + * + * @return ApplePayLineItem + */ + public function setAutomaticReloadPaymentThresholdAmount($automaticReloadPaymentThresholdAmount) + { + $this->automaticReloadPaymentThresholdAmount = $automaticReloadPaymentThresholdAmount; + + return $this; + } + + /** + * @return string + */ + public function getAutomaticReloadPaymentThresholdAmount() + { + return $this->automaticReloadPaymentThresholdAmount; + } + + /** + * @return array + */ + public function toArray() + { + return array_filter([ + 'type' => $this->type, + 'label' => $this->label, + 'amount' => $this->amount, + 'paymentTiming' => $this->paymentTiming, + 'recurringPaymentStartDate' => $this->recurringPaymentStartDate ? $this->recurringPaymentStartDate->format(DateTime::ATOM) : null, + 'recurringPaymentIntervalUnit' => $this->recurringPaymentIntervalUnit, + 'recurringPaymentIntervalCount' => $this->recurringPaymentIntervalCount, + 'recurringPaymentEndDate' => $this->recurringPaymentEndDate ? $this->recurringPaymentEndDate->format(DateTime::ATOM) : null, + 'deferredPaymentDate' => $this->deferredPaymentDate ? $this->deferredPaymentDate->format(DateTime::ATOM) : null, + 'automaticReloadPaymentThresholdAmount' => $this->automaticReloadPaymentThresholdAmount, + ]); + } +} diff --git a/src/PayPal/ApplePay/DTO/ApplePayPaymentContact.php b/src/PayPal/ApplePay/DTO/ApplePayPaymentContact.php new file mode 100644 index 000000000..66346cb3c --- /dev/null +++ b/src/PayPal/ApplePay/DTO/ApplePayPaymentContact.php @@ -0,0 +1,384 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\DTO; + +class ApplePayPaymentContact +{ + /** + * @var string + */ + private $phoneNumber; + /** + * @var string + */ + private $emailAddress; + /** + * @var string + */ + private $givenName; + /** + * @var string + */ + private $familyName; + /** + * @var string + */ + private $phoneticGivenName; + /** + * @var string + */ + private $phoneticFamilyName; + /** + * @var array + */ + private $addressLines = []; + /** + * @var string + */ + private $subLocality; + /** + * @var string + */ + private $locality; + /** + * @var string + */ + private $postalCode; + /** + * @var string + */ + private $subAdministrativeArea; + /** + * @var string + */ + private $administrativeArea; + /** + * @var string + */ + private $country; + /** + * @var string + */ + private $countryCode; + + /** + * @return string + */ + public function getPhoneNumber() + { + return $this->phoneNumber; + } + + /** + * @param string $phoneNumber + * + * @return $this + */ + public function setPhoneNumber($phoneNumber) + { + $this->phoneNumber = $phoneNumber; + + return $this; + } + + /** + * @return string + */ + public function getEmailAddress() + { + return $this->emailAddress; + } + + /** + * @param string $emailAddress + * + * @return $this + */ + public function setEmailAddress($emailAddress) + { + $this->emailAddress = $emailAddress; + + return $this; + } + + /** + * @return string + */ + public function getGivenName() + { + return $this->givenName; + } + + /** + * @param string $givenName + * + * @return $this + */ + public function setGivenName($givenName) + { + $this->givenName = $givenName; + + return $this; + } + + /** + * @return string + */ + public function getFamilyName() + { + return $this->familyName; + } + + /** + * @param string $familyName + * + * @return $this + */ + public function setFamilyName($familyName) + { + $this->familyName = $familyName; + + return $this; + } + + /** + * @return string + */ + public function getPhoneticGivenName() + { + return $this->phoneticGivenName; + } + + /** + * @param string $phoneticGivenName + * + * @return $this + */ + public function setPhoneticGivenName($phoneticGivenName) + { + $this->phoneticGivenName = $phoneticGivenName; + + return $this; + } + + /** + * @return string + */ + public function getPhoneticFamilyName() + { + return $this->phoneticFamilyName; + } + + /** + * @param string $phoneticFamilyName + * + * @return $this + */ + public function setPhoneticFamilyName($phoneticFamilyName) + { + $this->phoneticFamilyName = $phoneticFamilyName; + + return $this; + } + + /** + * @return array + */ + public function getAddressLines() + { + return $this->addressLines; + } + + /** + * @param array $addressLines + * + * @return $this + */ + public function setAddressLines(array $addressLines) + { + $this->addressLines = $addressLines; + + return $this; + } + + /** + * @return string + */ + public function getSubLocality() + { + return $this->subLocality; + } + + /** + * @param string $subLocality + * + * @return $this + */ + public function setSubLocality($subLocality) + { + $this->subLocality = $subLocality; + + return $this; + } + + /** + * @return string + */ + public function getLocality() + { + return $this->locality; + } + + /** + * @param string $locality + * + * @return $this + */ + public function setLocality($locality) + { + $this->locality = $locality; + + return $this; + } + + /** + * @return string + */ + public function getPostalCode() + { + return $this->postalCode; + } + + /** + * @param string $postalCode + * + * @return $this + */ + public function setPostalCode($postalCode) + { + $this->postalCode = $postalCode; + + return $this; + } + + /** + * @return string + */ + public function getSubAdministrativeArea() + { + return $this->subAdministrativeArea; + } + + /** + * @param string $subAdministrativeArea + * + * @return $this + */ + public function setSubAdministrativeArea($subAdministrativeArea) + { + $this->subAdministrativeArea = $subAdministrativeArea; + + return $this; + } + + /** + * @return string + */ + public function getAdministrativeArea() + { + return $this->administrativeArea; + } + + /** + * @param string $administrativeArea + * + * @return $this + */ + public function setAdministrativeArea($administrativeArea) + { + $this->administrativeArea = $administrativeArea; + + return $this; + } + + /** + * @return string + */ + public function getCountry() + { + return $this->country; + } + + /** + * @param string $country + * + * @return $this + */ + public function setCountry($country) + { + $this->country = $country; + + return $this; + } + + /** + * @return string + */ + public function getCountryCode() + { + return $this->countryCode; + } + + /** + * @param string $countryCode + * + * @return $this + */ + public function setCountryCode($countryCode) + { + $this->countryCode = $countryCode; + + return $this; + } + + /** + * @return array + */ + public function toArray() + { + return array_filter([ + 'phoneNumber' => $this->phoneNumber, + 'emailAddress' => $this->emailAddress, + 'givenName' => $this->givenName, + 'familyName' => $this->familyName, + 'phoneticGivenName' => $this->phoneticGivenName, + 'phoneticFamilyName' => $this->phoneticFamilyName, + 'addressLines' => $this->addressLines, + 'subLocality' => $this->subLocality, + 'locality' => $this->locality, + 'postalCode' => $this->postalCode, + 'subAdministrativeArea' => $this->subAdministrativeArea, + 'administrativeArea' => $this->administrativeArea, + 'country' => $this->country, + 'countryCode' => $this->countryCode, + ]); + } +} diff --git a/src/PayPal/ApplePay/DTO/ApplePayPaymentRequest.php b/src/PayPal/ApplePay/DTO/ApplePayPaymentRequest.php new file mode 100644 index 000000000..952a38318 --- /dev/null +++ b/src/PayPal/ApplePay/DTO/ApplePayPaymentRequest.php @@ -0,0 +1,187 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\DTO; + +class ApplePayPaymentRequest +{ + /** + * @var string + */ + private $countryCode; + /** + * @var string + */ + private $currencyCode; + /** + * @var ApplePayLineItem|null + */ + private $total = null; + /** + * @var ApplePayLineItem[] + */ + private $lineItems = []; + + /** + * @var ApplePayPaymentContact|null + */ + private $shippingContact = null; + /** + * @var ApplePayPaymentContact|null + */ + private $billingContact = null; + + /** + * @return string + */ + public function getCurrencyCode() + { + return $this->currencyCode; + } + + /** + * @param string $currencyCode + * + * @return ApplePayPaymentRequest + */ + public function setCurrencyCode($currencyCode) + { + $this->currencyCode = $currencyCode; + + return $this; + } + + /** + * @return string + */ + public function getCountryCode() + { + return $this->countryCode; + } + + /** + * @param string $countryCode + * + * @return ApplePayPaymentRequest + */ + public function setCountryCode($countryCode) + { + $this->countryCode = $countryCode; + + return $this; + } + + /** + * @return ApplePayLineItem + */ + public function getTotal() + { + return $this->total; + } + + /** + * @param ApplePayLineItem $total + * + * @return ApplePayPaymentRequest + */ + public function setTotal($total) + { + $this->total = $total; + + return $this; + } + + /** + * @return ApplePayLineItem[] + */ + public function getLineItems() + { + return $this->lineItems; + } + + /** + * @param ApplePayLineItem[] $lineItems + * + * @return ApplePayPaymentRequest + */ + public function setLineItems($lineItems) + { + $this->lineItems = $lineItems; + + return $this; + } + + /** + * @return ApplePayPaymentContact + */ + public function getShippingContact() + { + return $this->shippingContact; + } + + /** + * @param ApplePayPaymentContact $shippingContact + * + * @return ApplePayPaymentRequest + */ + public function setShippingContact($shippingContact) + { + $this->shippingContact = $shippingContact; + + return $this; + } + + /** + * @return ApplePayPaymentContact + */ + public function getBillingContact() + { + return $this->billingContact; + } + + /** + * @param ApplePayPaymentContact $billingContact + * + * @return ApplePayPaymentRequest + */ + public function setBillingContact($billingContact) + { + $this->billingContact = $billingContact; + + return $this; + } + + /** + * @return array + */ + public function toArray() + { + return array_filter([ + 'countryCode' => $this->countryCode, + 'currencyCode' => $this->currencyCode, + 'total' => $this->total ? $this->total->toArray() : null, + 'lineItems' => array_map(function (ApplePayLineItem $lineItem) { + return $lineItem->toArray(); + }, $this->lineItems), + 'shippingContact' => $this->shippingContact ? $this->shippingContact->toArray() : null, + 'billingContact' => $this->billingContact ? $this->billingContact->toArray() : null, + ]); + } +} diff --git a/src/PayPal/ApplePay/DTO/index.php b/src/PayPal/ApplePay/DTO/index.php new file mode 100644 index 000000000..296d682e8 --- /dev/null +++ b/src/PayPal/ApplePay/DTO/index.php @@ -0,0 +1,28 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +header('Location: ../'); +exit; diff --git a/src/PayPal/ApplePay/Query/GetApplePayPaymentRequestQuery.php b/src/PayPal/ApplePay/Query/GetApplePayPaymentRequestQuery.php new file mode 100644 index 000000000..c28ec9536 --- /dev/null +++ b/src/PayPal/ApplePay/Query/GetApplePayPaymentRequestQuery.php @@ -0,0 +1,44 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Query; + +use PrestaShop\Module\PrestashopCheckout\Cart\ValueObject\CartId; + +class GetApplePayPaymentRequestQuery +{ + /** + * @var CartId + */ + private $cartId; + + public function __construct(CartId $cartId) + { + $this->cartId = $cartId; + } + + /** + * @return CartId + */ + public function getCartId() + { + return $this->cartId; + } +} diff --git a/src/PayPal/ApplePay/Query/GetApplePayPaymentRequestQueryHandler.php b/src/PayPal/ApplePay/Query/GetApplePayPaymentRequestQueryHandler.php new file mode 100644 index 000000000..9e6207f59 --- /dev/null +++ b/src/PayPal/ApplePay/Query/GetApplePayPaymentRequestQueryHandler.php @@ -0,0 +1,60 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Query; + +use PrestaShop\Module\PrestashopCheckout\Builder\Payload\OrderPayloadBuilder; +use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; +use PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Builder\ApplePayPaymentRequestBuilder; +use PrestaShop\Module\PrestashopCheckout\Presenter\Cart\CartPresenter; + +class GetApplePayPaymentRequestQueryHandler +{ + /** + * @var ApplePayPaymentRequestBuilder + */ + private $builder; + + public function __construct(ApplePayPaymentRequestBuilder $builder) + { + $this->builder = $builder; + } + + /** + * @param GetApplePayPaymentRequestQuery $query + * + * @return GetApplePayPaymentRequestQueryResult + * + * @throws PsCheckoutException + */ + public function handle(GetApplePayPaymentRequestQuery $query) + { + $cartPresenter = new CartPresenter(); + $cart = $cartPresenter->present(); + $orderPayloadBuilder = new OrderPayloadBuilder($cart); + + $orderPayloadBuilder->buildFullPayload(); + $payload = $orderPayloadBuilder->presentPayload()->getArray(); + + $paymentRequest = $this->builder->buildMinimalPaymentRequestFromPayPalPayload($payload); + + return new GetApplePayPaymentRequestQueryResult($paymentRequest); + } +} diff --git a/src/PayPal/ApplePay/Query/GetApplePayPaymentRequestQueryResult.php b/src/PayPal/ApplePay/Query/GetApplePayPaymentRequestQueryResult.php new file mode 100644 index 000000000..11dc197d4 --- /dev/null +++ b/src/PayPal/ApplePay/Query/GetApplePayPaymentRequestQueryResult.php @@ -0,0 +1,44 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +namespace PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\Query; + +use PrestaShop\Module\PrestashopCheckout\PayPal\ApplePay\DTO\ApplePayPaymentRequest; + +class GetApplePayPaymentRequestQueryResult +{ + /** + * @var ApplePayPaymentRequest + */ + private $payload; + + public function __construct(ApplePayPaymentRequest $payload) + { + $this->payload = $payload; + } + + /** + * @return ApplePayPaymentRequest + */ + public function getPayload() + { + return $this->payload; + } +} diff --git a/src/PayPal/ApplePay/Query/index.php b/src/PayPal/ApplePay/Query/index.php new file mode 100644 index 000000000..296d682e8 --- /dev/null +++ b/src/PayPal/ApplePay/Query/index.php @@ -0,0 +1,28 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +header('Location: ../'); +exit; diff --git a/src/PayPal/PayPalConfiguration.php b/src/PayPal/PayPalConfiguration.php index 6ce9e92cb..7148f029b 100644 --- a/src/PayPal/PayPalConfiguration.php +++ b/src/PayPal/PayPalConfiguration.php @@ -20,6 +20,7 @@ namespace PrestaShop\Module\PrestashopCheckout\PayPal; +use Crypto\MAC; use PrestaShop\Module\PrestashopCheckout\Configuration\PrestaShopConfiguration; use PrestaShop\Module\PrestashopCheckout\Exception\PsCheckoutException; use PrestaShop\Module\PrestashopCheckout\Repository\PayPalCodeRepository; @@ -51,6 +52,9 @@ class PayPalConfiguration const PS_CHECKOUT_VAULTING = 'PS_CHECKOUT_VAULTING'; const PS_CHECKOUT_GOOGLE_PAY = 'PS_CHECKOUT_GOOGLE_PAY'; + const PS_CHECKOUT_APPLE_PAY = 'PS_CHECKOUT_APPLE_PAY'; + const PS_CHECKOUT_DOMAIN_REGISTERED_SANDBOX = 'PS_CHECKOUT_DOMAIN_REGISTERED_SANDBOX'; + const PS_CHECKOUT_DOMAIN_REGISTERED_LIVE = 'PS_CHECKOUT_DOMAIN_REGISTERED_LIVE'; /** * @var PrestaShopConfiguration @@ -448,4 +452,14 @@ public function isGooglePayEligible() { return (bool) $this->configuration->get(static::PS_CHECKOUT_GOOGLE_PAY); } + + public function isApplePayEligible() + { + return (bool) $this->configuration->get(static::PS_CHECKOUT_APPLE_PAY); + } + + public function isApplePayDomainRegistered() + { + return (bool) $this->configuration->get($this->getPaymentMode() === Mode::SANDBOX ? static::PS_CHECKOUT_DOMAIN_REGISTERED_SANDBOX : static::PS_CHECKOUT_DOMAIN_REGISTERED_LIVE); + } } diff --git a/src/PayPal/Sdk/PayPalSdkConfigurationBuilder.php b/src/PayPal/Sdk/PayPalSdkConfigurationBuilder.php index 1042cb48d..5d08cc436 100644 --- a/src/PayPal/Sdk/PayPalSdkConfigurationBuilder.php +++ b/src/PayPal/Sdk/PayPalSdkConfigurationBuilder.php @@ -146,6 +146,10 @@ public function buildConfiguration() $components[] = 'googlepay'; } + if ($this->shouldIncludeApplePayComponent()) { + $components[] = 'applepay'; + } + $params = [ 'clientId' => $this->env->getPaypalClientId(), 'merchantId' => $this->configuration->getMerchantId(), @@ -497,4 +501,17 @@ private function shouldIncludeGooglePayComponent() && in_array($country, $this->fundingSourceEligibilityConstraint->getCountries('google_pay'), true) && in_array($context->currency->iso_code, $this->fundingSourceEligibilityConstraint->getCurrencies('google_pay'), true); } + + private function shouldIncludeApplePayComponent() + { + $context = \Context::getContext(); + $country = $this->getCountry(); + $fundingSource = $this->fundingSourceConfigurationRepository->get('apple_pay'); + + return $fundingSource && $fundingSource['active'] + && $this->configuration->isApplePayEligible() + && $this->configuration->isApplePayDomainRegistered() + && in_array($country, $this->fundingSourceEligibilityConstraint->getCountries('apple_pay'), true) + && in_array($context->currency->iso_code, $this->fundingSourceEligibilityConstraint->getCurrencies('apple_pay'), true); + } } diff --git a/src/Translations/Translations.php b/src/Translations/Translations.php index 0a81e47fe..ebd3a2619 100644 --- a/src/Translations/Translations.php +++ b/src/Translations/Translations.php @@ -545,6 +545,9 @@ public function getTranslations() 'handling' => $this->module->l('Handling', 'translations'), 'discount' => $this->module->l('Discount', 'translations'), ], + 'apple_pay' => [ + 'total' => $this->module->l('Total', 'translations'), + ], ]; return $translations; diff --git a/upgrade/upgrade-8.4.2.0.php b/upgrade/upgrade-8.4.2.0.php new file mode 100644 index 000000000..9ad49a21d --- /dev/null +++ b/upgrade/upgrade-8.4.2.0.php @@ -0,0 +1,66 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ +if (!defined('_PS_VERSION_')) { + exit; +} + +/** + * Update main function for module version 8.4.2.0 + * + * @param Ps_checkout $module + * + * @return bool + */ +function upgrade_module_8_4_2_0($module) +{ + try { + $module->registerHook('moduleRoutes'); + + $db = Db::getInstance(); + $shopsList = \Shop::getShops(false, null, true); + + foreach ($shopsList as $shopId) { + $hasFundingSourceApplePay = (bool) $db->getValue(' + SELECT 1 + FROM `' . _DB_PREFIX_ . 'pscheckout_funding_source` + WHERE `name` = "apple_pay" + AND `id_shop` = ' . (int) $shopId + ); + + if (!$hasFundingSourceApplePay) { + $db->insert( + 'pscheckout_funding_source', + [ + 'name' => 'apple_pay', + 'position' => 12, + 'active' => 0, + 'id_shop' => (int) $shopId, + ] + ); + } + } + } catch (Exception $exception) { + PrestaShopLogger::addLog($exception->getMessage(), 4, 1, 'Module', $module->id); + + return false; + } + + return true; +} diff --git a/views/img/apple_pay.svg b/views/img/apple_pay.svg new file mode 100644 index 000000000..0c6ecafef --- /dev/null +++ b/views/img/apple_pay.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +