Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support sale operation by Magento payment provider gateway #9

Merged
merged 3 commits into from
Jan 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions design-documents/Sale_Payment_Operation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
## Overview
[Magento payment provider gateway](https://devdocs.magento.com/guides/v2.2/payments-integrations/bk-payments-integrations.html) doesn't support `sale` payment operation out of the box like `authorize` or `capture` operations.

This operation is available for the majority of payment methods.

Now, each payment method should implement an own workaround for `sale` payment operation, because [Order\Payment](https://github.com/magento/magento2/blob/2.2-develop/app/code/Magento/Sales/Model/Order/Payment.php#L445) calls capture instead sale:

**Magento\Sales\Model\Order\Payment**
```php
protected function processAction($action, Order $order)
{
$totalDue = $order->getTotalDue();
$baseTotalDue = $order->getBaseTotalDue();

switch ($action) {
............................................................................
case \Magento\Payment\Model\Method\AbstractMethod::ACTION_AUTHORIZE_CAPTURE:
$this->setAmountAuthorized($totalDue);
$this->setBaseAmountAuthorized($baseTotalDue);
$this->capture(null);
break;
default:
break;
}
}
```
[This article](https://community.magento.com/t5/Magento-DevBlog/The-Magento-Sale-Payment-Operation/ba-p/67251) describes how to solve this problem in each particular case but doesn't solve the problem in general.

All payment integrations implement boilerplate code for `sale` operation:
![](sale_payment_operation_img/sale_operation_flow.png)

## Theory of Operation
For the current moment, we have next relations in order payment workflow.
![](sale_payment_operation_img/order_payment_current.png)

I propose to introduce `Magento\Payment\Model\SaleOperationInterface` and `Magento\Payment\Model\Method\Adapter` should implement this interface along with `Magento\Payment\Model\MethodInterface`.
```php
<?php
namespace Magento\Payment\Model;

/**
* Responsible for support of `sale` payment operation via Magento payment provider gateway.
*
* @api
*/
interface SaleOperationInterface
{
/**
* Checks `sale` payment operation availability.
*
* @return bool
*
*/
public function canSale(): bool;

/**
* Executes `sale` payment operation.
*
* @param InfoInterface $payment
* @param float $amount
* @return $this
*
*/
public function sale(InfoInterface $payment, float $amount);
}
```


`Magento\Sales\Model\Order\Payment\Operations\CaptureOperation` includes logic responsible for invoice creating and invoice processing.
Logic responsible for invoice processing should be extracted from `CaptureOperation` into separate command `Magento\Sales\Model\Order\Payment\Operations\ProcessInvoiceOperation`.

`SaleOperation` and `CaptureOperation` commands will use `ProcessInvoiceOperation` for invoice processing and calls to [Magento payment provider gateway](https://devdocs.magento.com/guides/v2.2/payments-integrations/bk-payments-integrations.html).
![](sale_payment_operation_img/order_payment_new.png)

`Order\Payment` will call `SaleOpertion` if `sale` operation is available for payment method. Otherway, `CaptureOperation` will be called for backward compatibility with existing payment integrations.

**Magento\Sales\Model\Order\Payment**
```php
<?php
protected function processAction($action, Order $order)
{
$totalDue = $order->getTotalDue();
$baseTotalDue = $order->getBaseTotalDue();

switch ($action) {
............................................................................
case \Magento\Payment\Model\Method\AbstractMethod::ACTION_AUTHORIZE_CAPTURE:
$this->setAmountAuthorized($totalDue);
$this->setBaseAmountAuthorized($baseTotalDue);
if ($this->canSale()) {
$this->saleOperation->sale($this);
} else {
$this->capture(null);
}
break;
default:
break;
}
}

/**
* Check sale operation availability for payment method.
*
* @return bool
*/
private function canSale(): bool
{
$method = $this->getMethodInstance();
return $method instanceof SaleOperationInterface && $method->canSale();
}
```

## Payment provider integration configuration
Payment integration should be based on [Magento payment provider gateway](https://devdocs.magento.com/guides/v2.2/payments-integrations/bk-payments-integrations.html).

Integrations based on deprecated `Magento\Payment\Model\Method\AbstractMethod` this solution doesn't support.

In `config.xml` `can_sale` option should be defined:

```xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
<default>
<payment>
<braintree>
......................
<can_sale>1</can_sale>
......................
</braintree>
</payment>
</default>
</config>
```
In `di.xml` `sale` command should be defined in `CommandPool`:
```xml
<!-- Commands infrastructure -->
<virtualType name="BraintreeCommandPool" type="Magento\Payment\Gateway\Command\CommandPool">
<arguments>
<argument name="commands" xsi:type="array">
...............................................................
<item name="sale" xsi:type="string">BraintreeSaleCommand</item>
...............................................................
</argument>
</arguments>
</virtualType>
```

## Backward compatibility
- New @api interface `SaleOperationInterface` should be introduced - **MINOR** change according to SemVer
- Two public methods should be added in `Magento\Payment\Model\Method\Adapter` @api class - *sale()* and *canSale()*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods will have implementation as far as I understand, if so - this will be minor change, otherwise it will be a major change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The base implementation of sale() and canSale() will be in Magento\Payment\Model\Method\Adapter as it is the main extension point for payment integrations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they will


I suppose these changes can be made in the scope of **2.3 release** publication.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.