Skip to content

Commit

Permalink
Merge pull request #1064 from BearGroup/release/5.6.0
Browse files Browse the repository at this point in the history
Release/5.6.0
  • Loading branch information
Christian Zichichi authored Jul 22, 2021
2 parents 4cdd3e0 + 99024c2 commit 0dd3e82
Show file tree
Hide file tree
Showing 40 changed files with 423 additions and 76 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Change Log

## 5.6.0
* Changed the merchantReferenceId to be set on the charge permission after the order is completed
* Changed IPN handling so that it wouldn’t re-try capture on duplicate messages
* Changed flow so any changes at billing step route back to shipping details as address could have changed
* Fixed issue where only the first invoice created would capture payment
* Fixed issue where sometimes the payment method isn’t set on the payment if the PayNow button is used
* Fixed issue where the street on German addresses could get set twice
* Fixed issue with the mobile tooltip being truncated

## 5.5.1
* Add url to csp_whitelist.xml
* Fix issue with the payment method button and UK addresses
Expand Down
109 changes: 109 additions & 0 deletions Command/Sales/AmazonChargePermissionCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php
/**
* Copyright © Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

namespace Amazon\Pay\Command\Sales;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Magento\Sales\Api\Data\OrderInterface;

class AmazonChargePermissionCommand extends Command
{

const ORDER_ID = 'orderId';

/**
* @var \Magento\Framework\App\State $state
*/
private $state;

/**
* @var \Magento\Sales\Model\OrderRepository $orderRepository
*/
private $orderRepository;

/**
* @var \Amazon\Pay\Model\Adapter\AmazonPayAdapter $amazonAdapter
*/
private $amazonAdapter;

/**
* @var \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
*/
private $searchCriteriaBuilder;

public function __construct(
\Magento\Framework\App\State $state,
\Magento\Sales\Model\OrderRepository $orderRepository,
\Amazon\Pay\Model\Adapter\AmazonPayAdapter $amazonAdapter,
\Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
) {
$this->state = $state;
$this->orderRepository = $orderRepository;
$this->amazonAdapter = $amazonAdapter;
$this->searchCriteriaBuilder = $searchCriteriaBuilder;

parent::__construct();
}

protected function configure()
{
$this->setName('amazon:payment:sales:verify-charge-permission');
$this->addOption(
self::ORDER_ID,
null,
InputOption::VALUE_REQUIRED,
'OrderId'
);

parent::configure();
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$this->state->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML);

if ($orderId = $input->getOption(self::ORDER_ID)) {
$searchCriteria = $this->searchCriteriaBuilder
->addFilter(OrderInterface::INCREMENT_ID, $orderId)->create();

$orderResults = $this->orderRepository->getList($searchCriteria)->getItems();
if (empty($orderResults)) {
$output->writeln('<info>No order found for order number ' . $orderId . '</info>');
return;
}

$order = reset($orderResults);
$storeId = $order->getStoreId();
$chargePermissionId = $order->getPayment()->getAdditionalInformation('charge_permission_id');

try {
$resp = $this->amazonAdapter->getChargePermission($storeId, $chargePermissionId);
} catch (\Exception $ex) {
$output->writeLn('<error>Error retrieving charge permission from Amazon.</error>');
}

if (isset($resp['merchantMetadata']['merchantReferenceId'])) {
$referenceID = $resp['merchantMetadata']['merchantReferenceId'];
}

$verified = $referenceID == $orderId;
$output->writeln(var_export($verified));
}
}
}
5 changes: 3 additions & 2 deletions Domain/AmazonAddress.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,12 @@ public function shiftLines($times = 1)
{
while ($times > 0) {
$lines = $this->getData(AmazonAddressInterface::LINES);
$newlines = [];
$numberOfLines = count($lines);
for ($i = 1; $i <= $numberOfLines; $i++) {
$lines[$i] = isset($lines[$i + 1]) ? $lines[$i + 1] : '';
$newlines[$i] = isset($lines[$i + 1]) ? $lines[$i + 1] : '';
}
$this->setData(AmazonAddressInterface::LINES, $lines);
$this->setData(AmazonAddressInterface::LINES, $newlines);

$times--;
}
Expand Down
54 changes: 49 additions & 5 deletions Model/Adapter/AmazonPayAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ class AmazonPayAdapter
*/
private $amazonHelper;

/**
* @var \Magento\Framework\App\ProductMetadataInterface
*/
private $productMetadata;

/**
* @var \Amazon\Pay\Logger\Logger
*/
Expand All @@ -72,6 +77,7 @@ class AmazonPayAdapter
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Quote\Api\CartRepositoryInterface $quoteRepository
* @param \Amazon\Pay\Helper\Data $amazonHelper
* @param \Magento\Framework\App\ProductMetadataInterface $productMetadata
* @param \Amazon\Pay\Logger\Logger $logger
* @param \Magento\Framework\UrlInterface $url
* @param \Magento\Framework\App\Response\RedirectInterface $redirect
Expand All @@ -82,6 +88,7 @@ public function __construct(
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
\Amazon\Pay\Helper\Data $amazonHelper,
\Magento\Framework\App\ProductMetadataInterface $productMetadata,
\Amazon\Pay\Logger\Logger $logger,
\Magento\Framework\UrlInterface $url,
\Magento\Framework\App\Response\RedirectInterface $redirect
Expand All @@ -91,6 +98,7 @@ public function __construct(
$this->storeManager = $storeManager;
$this->quoteRepository = $quoteRepository;
$this->amazonHelper = $amazonHelper;
$this->productMetadata = $productMetadata;
$this->logger = $logger;
$this->url = $url;
$this->redirect = $redirect;
Expand All @@ -101,7 +109,11 @@ public function __construct(
*/
protected function getMerchantCustomInformation()
{
return sprintf('Magento Version: 2, Plugin Version: %s', $this->amazonHelper->getModuleVersion('Amazon_Pay'));
return sprintf(
'Magento Version: %s, Plugin Version: %s',
$this->productMetadata->getVersion(),
$this->amazonHelper->getModuleVersion('Amazon_Pay')
);
}

/**
Expand Down Expand Up @@ -170,7 +182,6 @@ public function updateCheckoutSession($quote, $checkoutSessionId, $paymentIntent
'chargeAmount' => $this->createPrice($quote->getGrandTotal(), $quote->getQuoteCurrencyCode()),
],
'merchantMetadata' => [
'merchantReferenceId' => $quote->getReservedOrderId(),
'merchantStoreName' => $this->amazonConfig->getStoreName(),
'customInformation' => $this->getMerchantCustomInformation(),
],
Expand Down Expand Up @@ -291,6 +302,37 @@ public function getChargePermission(int $storeId, string $chargePermissionId)
return $this->processResponse($response, __FUNCTION__);
}

/**
* @param int $storeId
* @param string $chargePermissionId
* @param array $data
* @return mixed
*/
public function updateChargePermission(int $storeId, string $chargePermissionId, array $data)
{
$payload = [
'merchantMetadata' => [
'merchantReferenceId' => $data['merchantReferenceId']
]
];

if (isset($data['merchantStoreName'])) {
$payload['merchantMetadata']['merchantStoreName'] = $data['merchantStoreName'];
}

if (isset($data['customInformation'])) {
$payload['merchantMetadata']['customInformation'] = $data['customInformation'];
}

if (isset($data['noteToBuyer'])) {
$payload['merchantMetadata']['noteToBuyer'] = $data['noteToBuyer'];
}

$response = $this->clientFactory->create($storeId)->updateChargePermission($chargePermissionId, $payload);

return $this->processResponse($response, __FUNCTION__);
}

/**
* Cancel charge
*
Expand Down Expand Up @@ -337,9 +379,7 @@ public function closeChargePermission($storeId, $chargePermissionId, $reason, $c
public function authorize($data)
{
$quote = $this->quoteRepository->get($data['quote_id']);
if (!empty($data['amazon_checkout_session_id'])) {
$response = $this->getCheckoutSession($quote->getStoreId(), $data['amazon_checkout_session_id']);
} elseif (!empty($data['charge_permission_id'])) {
if (!empty($data['charge_permission_id'])) {
$getChargePermissionResponse = $this->getChargePermission(
$quote->getStoreId(),
$data['charge_permission_id']
Expand All @@ -352,7 +392,11 @@ public function authorize($data)
$quote->getQuoteCurrencyCode(),
true
);
} else {
$this->logger->debug(__('Charge permission not in Chargeable state: ') . $data['charge_permission_id']);
}
} elseif (!empty($data['amazon_checkout_session_id'])) {
$response = $this->getCheckoutSession($quote->getStoreId(), $data['amazon_checkout_session_id']);
}

return $response;
Expand Down
9 changes: 8 additions & 1 deletion Model/AsyncManagement/Charge.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ public function processStateChange($chargeId)
$order = $this->loadOrder($chargeId);

if ($order) {
$invoice = $this->loadInvoice($chargeId, $order);
if ($invoice && $invoice->getState() != Order\Invoice::STATE_OPEN) {
// Could happen with duplicate IPN messages, don't want to try to capture unless not invoiced
$this->asyncLogger->info('Duplicate IPN received after capture for Order #' . $order->getIncrementId());
return true;
}

$charge = $this->amazonAdapter->getCharge($order->getStoreId(), $chargeId);

// Compare Charge State with Order State
Expand Down Expand Up @@ -278,7 +285,7 @@ public function capture($order, $chargeId, $chargeAmount)
$invoice = $this->invoiceService->prepareInvoice($order);
$invoice->register();
}

if ($invoice && ($invoice->canCapture() || $invoice->getOrder()->getStatus() == Order::STATE_PAYMENT_REVIEW)) {
$order = $invoice->getOrder();
$payment = $order->getPayment();
Expand Down
14 changes: 14 additions & 0 deletions Model/CheckoutSessionManagement.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
namespace Amazon\Pay\Model;

use Amazon\Pay\Api\Data\CheckoutSessionInterface;
use Amazon\Pay\Gateway\Config\Config;
use Amazon\Pay\Model\Config\Source\AuthorizationMode;
use Amazon\Pay\Model\Config\Source\PaymentAction;
use Amazon\Pay\Model\AsyncManagement;
Expand Down Expand Up @@ -583,6 +584,11 @@ public function completeCheckoutSession($amazonSessionId)
// can work as expected
$payment = $this->magentoCheckoutSession->getQuote()->getPayment();

// Some checkout flows (especially 3rd party) could get to this point without setting payment method
if (empty($payment->getMethod())) {
$payment->setMethod(Config::CODE);
}

// set amazon session id on payment object to be used in authorize
$payment->setAdditionalInformation('amazon_session_id', $amazonSessionId);

Expand Down Expand Up @@ -647,7 +653,15 @@ public function completeCheckoutSession($amazonSessionId)
}
$amazonCharge = $this->amazonAdapter->getCharge($cart->getStoreId(), $chargeId);

//Send merchantReferenceId to Amazon
$this->amazonAdapter->updateChargePermission(
$order->getStoreId(),
$amazonCharge['chargePermissionId'],
['merchantReferenceId' => $order->getIncrementId()]
);

$chargeState = $amazonCharge['statusDetails']['state'];

switch ($chargeState) {
case 'AuthorizationInitiated':
$payment->setIsTransactionClosed(false);
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ The following table provides an overview on which Git branch is compatible to wh
Magento Version | Github Branch | Latest release
---|---|---
2.2.6 - 2.2.11 (EOL) | [V2checkout-1.2.x](https://github.com/amzn/amazon-payments-magento-2-plugin/tree/V2checkout-1.2.x) | 1.20.0 (EOL)
2.3.0 - 2.4.x | [master](https://github.com/amzn/amazon-payments-magento-2-plugin/tree/master) | 5.5.1
2.3.0 - 2.4.x | [master](https://github.com/amzn/amazon-payments-magento-2-plugin/tree/master) | 5.6.0

## Release Notes
See [CHANGELOG.md](/CHANGELOG.md)
20 changes: 20 additions & 0 deletions Test/Mftf-23/ActionGroup/AmazonShipmentFormActionGroup.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">

<actionGroup name="AmazonShipmentFormActionGroup">
<fillField selector="{{StorefrontCheckoutCheckoutCustomerLoginSection.email}}" userInput="{{AmazonShippingFormData.email}}" stepKey="setCustomerEmail"/>
<fillField selector="{{AmazonFillShipmentFormSection.firstname}}" userInput="{{AmazonShippingFormData.fname}}" stepKey="SetCustomerFirstName"/>
<fillField selector="{{AmazonFillShipmentFormSection.lastname}}" userInput="{{AmazonShippingFormData.lname}}" stepKey="SetCustomerLastName"/>
<fillField selector="{{AmazonFillShipmentFormSection.street}}" userInput="{{AmazonShippingFormData.street}}" stepKey="SetCustomerStreetAddress"/>
<fillField selector="{{AmazonFillShipmentFormSection.city}}" userInput="{{AmazonShippingFormData.city}}" stepKey="SetCustomerCity"/>
<fillField selector="{{AmazonFillShipmentFormSection.postcode}}" userInput="{{AmazonShippingFormData.postcode}}" stepKey="SetCustomerZipCode"/>
<fillField selector="{{AmazonFillShipmentFormSection.telephone}}" userInput="{{AmazonShippingFormData.telephone}}" stepKey="SetCustomerPhoneNumber"/>
<click selector="{{AmazonFillShipmentFormSection.region}}" stepKey="clickToSetState"/>
<click selector="{{AmazonFillShipmentFormSection.state}}" stepKey="clickToChooseState"/>
<click selector="{{AmazonFillShipmentFormSection.next}}" stepKey="clickToSaveShippingInfo"/>
<waitForPageLoad time="5" stepKey="waitForReviewAndPaymentsPageIsLoaded"/>
<seeInCurrentUrl url="payment" stepKey="reviewAndPaymentIsShown"/>
</actionGroup>

</actionGroups>
15 changes: 15 additions & 0 deletions Test/Mftf-23/Data/AmazonShippingData.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd">

<entity name="AmazonShippingFormData" type="shipping">
<data key="email" unique="prefix">mail@gmail.com</data>
<data key="fname">firstname</data>
<data key="lname">lastname</data>
<data key="street">BirminghamStreet</data>
<data key="city">Birmingham</data>
<data key="postcode">35005</data>
<data key="telephone">222222222</data>
</entity>

</entities>
18 changes: 18 additions & 0 deletions Test/Mftf-23/Section/AmazonShippingSection.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd">

<!--Fill all required fields in shipping form-->
<section name="AmazonFillShipmentFormSection">
<element name="email" type="input" selector="#customer-email" />
<element name="firstname" type="input" selector="//input[@name='firstname']"/>
<element name="lastname" type="input" selector="//input[@name='lastname']"/>
<element name="street" type="input" selector="//input[contains(@name, 'street')]"/>
<element name="city" type="input" selector="//input[@name='city']"/>
<element name="postcode" type="input" selector="//input[@name='postcode']"/>
<element name="telephone" type="input" selector="//input[@name='telephone']"/>
<element name="region" type="button" selector="//*[@name='region_id']"/>
<element name="state" type="button" selector="//*[text()='Alabama']"/>
<element name="next" type="button" selector="//span[text()='Next']"/>
</section>
</sections>
3 changes: 1 addition & 2 deletions Test/Mftf-23/Test/AmazonCheckoutLoginTest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@

<!--Go to Amazon Pay from the checkout and login-->
<click selector="{{AmazonButtonSection.checkout}}" stepKey="clickAmazonButton"/>
<wait time="1" stepKey="allowPopupToOpen"/>
<switchToNextTab stepKey="switchToWindowLoginPopup"/>
<actionGroup ref="AmazonSwitchToPopupActionGroup" stepKey="allowPopupToOpen" />
<actionGroup ref="AmazonLoginActionGroup" stepKey="AmazonLoginActionGroup"/>
</test>
</tests>
Loading

0 comments on commit 0dd3e82

Please sign in to comment.