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

Bug: Atome failed due to sub product amount zero #433

Merged
merged 9 commits into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from 8 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
19 changes: 10 additions & 9 deletions Gateway/Request/APMBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -375,16 +375,17 @@ private function getOrderItems($order)
$itemArray = [];
$items = $order->getItems();
$currency = $order->getCurrencyCode();
foreach ($items as $itemObject) {
$item = $itemObject->toArray();

foreach ($items as $item) {
$price = $item->getPrice();
if ((float) $price === 0.0) {
continue;
}
$itemArray[] = [
'sku' => $item['sku'],
'name' => $item['name'],
'amount' => $this->money->setAmountAndCurrency(
$item['base_original_price'],
$currency
)->toSubunit(),
'quantity' => $item['qty_ordered'],
'sku' => $item->getSku(),
'name' => $item->getName(),
'amount' => $this->money->setAmountAndCurrency($price, $currency)->toSubunit(),
'quantity' => $item->getQtyOrdered(),
];
}
return $itemArray;
Expand Down
13 changes: 9 additions & 4 deletions Gateway/Validator/APMRequestValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ public function build(array $buildSubject)
$paymentDataObject = SubjectReader::readPayment($buildSubject);
$order = $paymentDataObject->getOrder();
$paymentInfo = $paymentDataObject->getPayment();
$subTotal = $paymentInfo->getOrder()->getSubTotal();

switch ($paymentInfo->getMethod()) {
case Atome::CODE:
$this->validateAtomePhoneNumber($order, $paymentInfo);
$this->validateAtomeAmount($order);
$this->validateAtomePhoneNumber($paymentInfo);
$this->validateAtomeAmount($order, $subTotal);
break;
default:
break;
Expand All @@ -41,7 +42,7 @@ public function build(array $buildSubject)
*
* @return void
*/
private function validateAtomePhoneNumber($order, $info)
private function validateAtomePhoneNumber($info)
{
$number = $info->getAdditionalInformation(AtomeDataAssignObserver::PHONE_NUMBER);
$phonePattern = "/(\+)?([0-9]{10,13})/";
Expand All @@ -61,7 +62,7 @@ private function validateAtomePhoneNumber($order, $info)
*
* @return void
*/
private function validateAtomeAmount($order)
private function validateAtomeAmount($order, $subTotal)
{
$limits = [
'THB' => [
Expand All @@ -81,6 +82,10 @@ private function validateAtomeAmount($order)
$currency = strtoupper($order->getCurrencyCode());
$amount = $order->getGrandTotalAmount();

if ($subTotal === 0.0) {
throw new LocalizedException(__('Complimentary products cannot be billed'));
}

if (!isset($limits[$currency])) {
throw new LocalizedException(__('Currency not supported'));
}
Expand Down
4 changes: 4 additions & 0 deletions Test/Mock/InfoMock.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,8 @@ public function getMethod()
public function getPayment()
{
}

public function getOrder()
{
}
}
52 changes: 52 additions & 0 deletions Test/Mock/OrderMock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace Omise\Payment\Test\Mock;

use Magento\Payment\Gateway\Data\OrderAdapterInterface;

class OrderMock implements OrderAdapterInterface
{
public function getCurrencyCode()
{
}

public function getOrderIncrementId()
{
}

public function getCustomerId()
{
}

public function getBillingAddress()
{
}

public function getShippingAddress()
{
}

public function getStoreId()
{
}

public function getId()
{
}

public function getGrandTotalAmount()
{
}

public function getItems()
{
}

public function getRemoteIp()
{
}

public function getSubTotal()
{
}
}
59 changes: 29 additions & 30 deletions Test/Unit/APMRequestValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
use PHPUnit\Framework\TestCase;
use Omise\Payment\Model\Config\Atome;
use Omise\Payment\Test\Mock\InfoMock;
use Magento\Customer\Api\Data\AddressInterface;
use Omise\Payment\Test\Mock\OrderMock;
use Magento\Framework\Exception\LocalizedException;
use Magento\Payment\Gateway\Data\PaymentDataObject;
use Magento\Payment\Gateway\Data\OrderAdapterInterface;
use Omise\Payment\Gateway\Validator\APMRequestValidator;
use Magento\Payment\Gateway\Data\AddressAdapterInterface;
use Magento\Payment\Gateway\Data\PaymentDataObjectInterface;

class APMRequestValidatorTest extends TestCase
{
Expand All @@ -19,30 +19,42 @@ class APMRequestValidatorTest extends TestCase

private $addressMock;

private $paymentDataObject;
private $paymentDataObjectMock;

private $model;

protected function setUp(): void
{
$this->addressMock = $this->getMockBuilder(AddressInterface::class)->getMock();
$this->addressMock = $this->getMockBuilder(AddressAdapterInterface::class)->getMock();
$this->addressMock->method('getCountryId')->willReturn('TH');

$this->orderMock = $this->getMockBuilder(OrderAdapterInterface::class)
->getMockForAbstractClass();
$this->orderMock = $this->getMockBuilder(OrderMock::class)->getMock();
$this->orderMock->method('getShippingAddress')->willReturn($this->addressMock);

$this->infoMock = $this->getMockBuilder(InfoMock::class)->getMock();
$this->infoMock->method('getMethod')->willReturn(Atome::CODE);
$this->infoMock->method('getOrder')->willReturn($this->orderMock);

$this->paymentDataObject = new PaymentDataObject(
$this->orderMock,
$this->infoMock
);
$this->paymentDataObjectMock = $this->getMockBuilder(PaymentDataObjectInterface::class)->getMock();
$this->paymentDataObjectMock->method('getOrder')->willReturn($this->orderMock);
$this->paymentDataObjectMock->method('getPayment')->willReturn($this->infoMock);

$this->model = new APMRequestValidator();
}

/**
* @covers Omise\Payment\Gateway\Validator\APMRequestValidator
*/
public function testComplimentaryProducts()
{
$this->expectException(LocalizedException::class);
$this->expectExceptionMessage('Complimentary products cannot be billed');
$this->orderMock->method('getSubTotal')->willReturn(0.0);
$this->orderMock->method('getCurrencyCode')->willReturn("THB");
$this->infoMock->method('getAdditionalInformation')->willReturn('0987654321');
$this->model->build(['payment' => $this->paymentDataObjectMock]);
}

/**
* @covers Omise\Payment\Gateway\Validator\APMRequestValidator
*/
Expand All @@ -51,11 +63,8 @@ public function testCurrencyNotSupported()
$this->expectException(LocalizedException::class);
$this->expectExceptionMessage('Currency not supported');
$this->orderMock->method('getCurrencyCode')->willReturn("USD");
$this->orderMock->method('getGrandTotalAmount')->willReturn(100);
$this->infoMock->method('getAdditionalInformation')->willReturn('0987654321');
$this->model->build([
'payment' => $this->paymentDataObject,
]);
$this->model->build(['payment' => $this->paymentDataObjectMock]);
}

/**
Expand All @@ -68,9 +77,7 @@ public function testMinAmountShouldThrowError()
$this->orderMock->method('getCurrencyCode')->willReturn("THB");
$this->orderMock->method('getGrandTotalAmount')->willReturn(10);
$this->infoMock->method('getAdditionalInformation')->willReturn('0987654321');
$this->model->build([
'payment' => $this->paymentDataObject,
]);
$this->model->build(['payment' => $this->paymentDataObjectMock]);
}

/**
Expand All @@ -82,9 +89,7 @@ public function testValidAmountShouldNotThrowError()
$this->orderMock->method('getCurrencyCode')->willReturn("THB");
$this->orderMock->method('getGrandTotalAmount')->willReturn(20);
$this->infoMock->method('getAdditionalInformation')->willReturn('0987654321');
$this->model->build([
'payment' => $this->paymentDataObject,
]);
$this->model->build(['payment' => $this->paymentDataObjectMock]);
}

/**
Expand All @@ -97,9 +102,7 @@ public function testMaxAmountShouldThrowError()
$this->orderMock->method('getCurrencyCode')->willReturn("THB");
$this->orderMock->method('getGrandTotalAmount')->willReturn(200000);
$this->infoMock->method('getAdditionalInformation')->willReturn('0987654321');
$this->model->build([
'payment' => $this->paymentDataObject,
]);
$this->model->build(['payment' => $this->paymentDataObjectMock]);
}

/**
Expand All @@ -112,9 +115,7 @@ public function testInvalidAtomePhoneNumberValidation()
$this->infoMock->method('getAdditionalInformation')->willReturn('0987');
$this->orderMock->method('getCurrencyCode')->willReturn("THB");
$this->orderMock->method('getGrandTotalAmount')->willReturn(100);
$this->model->build([
'payment' => $this->paymentDataObject,
]);
$this->model->build(['payment' => $this->paymentDataObjectMock]);
}

/**
Expand All @@ -126,8 +127,6 @@ public function testValidAtomePhoneNumberValidation()
$this->infoMock->method('getAdditionalInformation')->willReturn('+66987654321');
$this->orderMock->method('getCurrencyCode')->willReturn("THB");
$this->orderMock->method('getGrandTotalAmount')->willReturn(100);
$this->model->build([
'payment' => $this->paymentDataObject,
]);
$this->model->build(['payment' => $this->paymentDataObjectMock]);
}
}
117 changes: 117 additions & 0 deletions Test/Unit/AtomeAPMBuilderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

namespace Omise\Payment\Test\Unit;

use PHPUnit\Framework\TestCase;
use Omise\Payment\Helper\OmiseMoney;
use Omise\Payment\Helper\OmiseHelper;
use Omise\Payment\Model\Capabilities;
use Omise\Payment\Model\Config\Atome;
use Omise\Payment\Test\Mock\InfoMock;
use Omise\Payment\Model\Config\Config;
use Omise\Payment\Helper\ReturnUrlHelper;
use Omise\Payment\Gateway\Request\APMBuilder;
use Magento\Sales\Api\Data\OrderItemInterface;
use Magento\Payment\Gateway\Data\PaymentDataObject;
use Magento\Payment\Gateway\Data\OrderAdapterInterface;
use Magento\Payment\Gateway\Data\AddressAdapterInterface;

class AtomeAPMBuilderTest extends TestCase
{
private $builder;
private $helper;
private $returnUrlHelper;
private $config;
private $capabilities;
private $orderMock;
private $infoMock;
private $addressMock;
private $itemMock;

protected function setUp(): void
{
$this->itemMock = $this->getMockBuilder(OrderItemInterface::class)->getMock();
$this->addressMock = $this->getMockBuilder(AddressAdapterInterface::class)->getMock();
$this->helper = $this->getMockBuilder(OmiseHelper::class)->disableOriginalConstructor()->getMock();
$this->returnUrlHelper = $this->getMockBuilder(ReturnUrlHelper::class)->disableOriginalConstructor()->getMock();
$this->config = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
$this->capabilities = $this->getMockBuilder(Capabilities::class)->disableOriginalConstructor()->getMock();
$this->orderMock = $this->getMockBuilder(OrderAdapterInterface::class)->getMock();
$this->orderMock->method('getShippingAddress')->willReturn($this->addressMock);
$this->orderMock->method('getItems')->willReturn([$this->itemMock]);
$this->orderMock->method('getCurrencyCode')->willReturn('THB');
$this->infoMock = $this->getMockBuilder(InfoMock::class)->getMock();
}

/**
* @covers Omise\Payment\Gateway\Request\APMBuilder
* @covers Omise\Payment\Model\Config\Atome
*/
public function testApmBuilderWithItemPriceZero()
{
$this->itemMock->method('getPrice')->willReturn(0.0);
$this->infoMock->method('getMethod')->willReturn(Atome::CODE);
$this->returnUrlHelper->method('create')->willReturn([
'url' => 'https://omise.co/complete',
'token' => '1234'
]);

$this->builder = new APMBuilder(
$this->helper,
$this->returnUrlHelper,
$this->config,
$this->capabilities,
new OmiseMoney(),
);

$result = $this->builder->build(['payment' => new PaymentDataObject(
$this->orderMock,
$this->infoMock
)]);

$this->assertEquals(0, count($result['source']['items']));
$this->assertEquals('atome', $result['source']['type']);
$this->assertEquals('https://omise.co/complete', $result['return_uri']);
}

/**
* @covers Omise\Payment\Gateway\Request\APMBuilder
* @covers Omise\Payment\Model\Config\Atome
* @covers Omise\Payment\Helper\OmiseMoney
*/
public function testApmBuilderWithItemPriceGreaterThanZero()
{
$this->itemMock->method('getPrice')->willReturn(100.0);
$this->infoMock->method('getMethod')->willReturn(Atome::CODE);
$this->returnUrlHelper->method('create')->willReturn([
'url' => 'https://omise.co/complete',
'token' => '1234'
]);

$this->builder = new APMBuilder(
$this->helper,
$this->returnUrlHelper,
$this->config,
$this->capabilities,
new OmiseMoney(),
);

$result = $this->builder->build(['payment' => new PaymentDataObject(
$this->orderMock,
$this->infoMock
)]);

$this->assertEquals(1, count($result['source']['items']));
$this->assertEquals('atome', $result['source']['type']);
$this->assertEquals('https://omise.co/complete', $result['return_uri']);
}

/**
* @covers Omise\Payment\Model\Config\Atome
*/
public function testConstants()
{
$this->assertEquals('omise_offsite_atome', Atome::CODE);
$this->assertEquals('atome', Atome::ID);
}
}
4 changes: 4 additions & 0 deletions i18n/ja_JP.csv
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@
"Card stolen or lost.", "このカードは紛失/盗難が報告されています"
"Payer did not take action before charge expiration.", "有効期限前に操作がありませんでした。"
"secure_form_banner_message", "<b>Opn Payments</b> : プラグインを最新バージョンにアップデートし、顧客情報の安全な管理に必要なSecure Formを有効にしてください。アップデート後、クレジットカードの決済フォームを再度カスタマイズする必要があります。<a target='blank' href='https://www.omise.co/magento-plugin'>Secure Formを有効にする方法はこちらをご確認ください。</a>"
"Complimentary products cannot be billed", "無償提供商品は課金の対象外です"
"Currency not supported", "サポートされていない通貨です",
"Amount must be greater than %1 %2", "金額は %1 %2を超える必要があります"
"Amount must be less than %1 %2", "金額は %1 %2を下回る必要があります"
4 changes: 4 additions & 0 deletions i18n/th_TH.csv
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@
"True Money Phone Number", "เบอร์โทรศัพท์ที่ใช้สมัครบัญชี TrueMoney Wallet"
"Use a new card", "ใช้บัตรใหม่"
"secure_form_banner_message", "<b>Opn Payments</b> : อัปเดตปลั๊กอินของคุณเป็นเวอร์ชันล่าสุดเพื่อเปิดใช้งาน Secure Form และมอบความปลอดภัยสูงสุดให้กับข้อมูลของลูกค้า โดยหลังจากทำการอัปเกรด คุณจะต้องปรับแต่งแบบฟอร์มการชำระเงินด้วยบัตรเครดิตใหม่อีกครั้ง <a target='blank' href='https://www.omise.co/magento-plugin'>เรียนรู้เพิ่มเติมเกี่ยวกับการเปิดใช้งาน Secure Form</a>"
"Complimentary products cannot be billed", "สินค้าที่ระลึกไม่สามารถเรียกเก็บเงินได้"
"Currency not supported", "ระบบไม่รองรับสกุลเงินนี้",
"Amount must be greater than %1 %2", "จำนวนเงินจะต้องมากกว่า %1 %2"
"Amount must be less than %1 %2", "จำนวนเงินจะต้องไม่เกิน %1 %2"
Binary file added view/frontend/web/images/atome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified view/frontend/web/images/touchngo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading