Skip to content

Commit d274eeb

Browse files
Merge pull request #22 from xendit/TPI-1481/ovo-new-flow
Implement new OVO flow
2 parents 4d4c4fd + 0757bef commit d274eeb

File tree

9 files changed

+201
-39
lines changed

9 files changed

+201
-39
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# CHANGELOG
22

3+
## 1.7.0 (2020-04-03)
4+
5+
Improvement:
6+
7+
- Change OVO flow to reduce timeout case
8+
39
## 1.6.2 (2020-02-24)
410

511
Bugfix:

Xendit/M2Invoice/Controller/Checkout/Notification.m22.php

+18-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,13 @@ public function execute()
8787
if ($isEwallet) {
8888
$temp = explode("-", $decodedPost['external_id']);
8989
$orderId = end($temp);
90-
$transactionId = $decodedPost['ewallet_transaction_id'];
90+
$transactionId = $decodedPost['id'];
91+
92+
// default code if API doesn't send failure_code
93+
$failureCode = 'UNKNOWN_ERROR';
94+
if (isset($decodedPost['failure_code'])) {
95+
$failureCode = $decodedPost['failure_code'];
96+
}
9197
}
9298
else {
9399
$orderId = $decodedPost['description'];
@@ -168,6 +174,7 @@ public function execute()
168174

169175
if ($isEwallet) {
170176
$payment->setAdditionalInformation('xendit_ewallet_id', $transactionId);
177+
$payment->save();
171178
}
172179

173180
$order->save();
@@ -187,6 +194,16 @@ public function execute()
187194
);
188195
$this->getCheckoutHelper()->restoreQuote(); //restore cart
189196

197+
if ($isEwallet) {
198+
$orderState = Order::STATE_CANCELED;
199+
$order->setState($orderState)
200+
->setStatus($orderState);
201+
$order->save();
202+
$payment = $order->getPayment();
203+
$payment->setAdditionalInformation('xendit_ewallet_failure_code', $failureCode);
204+
$payment->save();
205+
}
206+
190207
$result = $this->jsonResultFactory->create();
191208
$result->setData([
192209
'status' => __('FAILED'),

Xendit/M2Invoice/Controller/Checkout/Notification.m23.php

+18-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,13 @@ public function execute()
9797
if ($isEwallet) {
9898
$temp = explode("-", $decodedPost['external_id']);
9999
$orderId = end($temp);
100-
$transactionId = $decodedPost['ewallet_transaction_id'];
100+
$transactionId = $decodedPost['id'];
101+
102+
// default code if API doesn't send failure_code
103+
$failureCode = 'UNKNOWN_ERROR';
104+
if (isset($decodedPost['failure_code'])) {
105+
$failureCode = $decodedPost['failure_code'];
106+
}
101107
} else {
102108
$orderId = $decodedPost['description'];
103109
$transactionId = $decodedPost['id'];
@@ -175,6 +181,7 @@ public function execute()
175181

176182
if ($isEwallet) {
177183
$payment->setAdditionalInformation('xendit_ewallet_id', $transactionId);
184+
$payment->save();
178185
}
179186

180187
$order->save();
@@ -194,6 +201,16 @@ public function execute()
194201
);
195202
$this->getCheckoutHelper()->restoreQuote(); //restore cart
196203

204+
if ($isEwallet) {
205+
$orderState = Order::STATE_CANCELED;
206+
$order->setState($orderState)
207+
->setStatus($orderState);
208+
$order->save();
209+
$payment = $order->getPayment();
210+
$payment->setAdditionalInformation('xendit_ewallet_failure_code', $failureCode);
211+
$payment->save();
212+
}
213+
197214
$result = $this->jsonResultFactory->create();
198215
$result->setData([
199216
'status' => __('FAILED'),

Xendit/M2Invoice/Controller/Checkout/Redirect.php

+82-16
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@ public function execute()
1212
{
1313
try {
1414
$order = $this->getOrder();
15+
$orderId = $order->getRealOrderId();
1516
$payment = $order->getPayment();
17+
$this->getMessageManager()->getMessages(true);
18+
19+
$orderState = Order::STATE_PENDING_PAYMENT;
20+
$order->setState($orderState)
21+
->setStatus($orderState);
22+
$order->save();
1623

1724
if ($payment->getAdditionalInformation('xendit_redirect_url') !== null) {
1825
$redirectUrl = $payment->getAdditionalInformation('xendit_redirect_url');
@@ -40,21 +47,50 @@ public function execute()
4047
return $this->_redirect('checkout/onepage/success', [ '_secure'=> false ]);
4148
}
4249

43-
if ($payment->getAdditionalInformation('xendit_ewallet_id') !== null) {
44-
$this->getMessageManager()->addSuccessMessage(__("Your payment with Xendit is completed"));
45-
return $this->_redirect('checkout/onepage/success', [ '_secure'=> false ]);
50+
if ($payment->getAdditionalInformation('xendit_ovo_external_id') !== null) {
51+
$isSuccessful = false;
52+
$loopCondition = true;
53+
$startTime = time();
54+
while ($loopCondition && (time() - $startTime < 70)) {
55+
$order = $this->getOrderById($orderId);
56+
57+
if ($order->getState() !== Order::STATE_PENDING_PAYMENT) {
58+
$loopCondition = false;
59+
$isSuccessful = $order->getState() === Order::STATE_PROCESSING;
60+
}
61+
sleep(1);
62+
}
63+
64+
if ($order->getState() === Order::STATE_PENDING_PAYMENT) {
65+
$ewalletStatus = $this->getEwalletStatus('OVO', $payment->getAdditionalInformation('xendit_ovo_external_id'));
66+
67+
if ($ewalletStatus === 'COMPLETED') {
68+
$isSuccessful = true;
69+
}
70+
}
71+
72+
if ($isSuccessful) {
73+
$this->getMessageManager()->addSuccessMessage(__("Your payment with Xendit is completed"));
74+
return $this->_redirect('checkout/onepage/success', [ '_secure'=> false ]);
75+
} else {
76+
$payment = $order->getPayment();
77+
$failureCode = $payment->getAdditionalInformation('xendit_ewallet_failure_code');
78+
79+
if ($failureCode === null) {
80+
$failureCode = 'Payment is ' . $ewalletStatus;
81+
}
82+
83+
$this->getCheckoutHelper()->restoreQuote();
84+
return $this->redirectToCart($failureCode);
85+
}
4686
}
4787

4888
if ($payment->getAdditionalInformation('xendit_failure_reason') !== null) {
4989
$failureReason = $payment->getAdditionalInformation('xendit_failure_reason');
5090

5191
$this->cancelOrder($order, $failureReason);
5292

53-
$failureReasonInsight = $this->getDataHelper()->failureReasonInsight($failureReason);
54-
$this->getMessageManager()->addErrorMessage(__(
55-
$failureReasonInsight
56-
));
57-
return $this->_redirect('checkout/cart', [ '_secure'=> false ]);
93+
return $this->redirectToCart($failureReason);
5894
}
5995

6096
if ($payment->getAdditionalInformation('xendit_hosted_payment_id') !== null) {
@@ -76,20 +112,50 @@ public function execute()
76112

77113
$this->cancelOrder($order, 'No payment recorded');
78114

79-
$this->getMessageManager()->addErrorMessage(__(
80-
"There was an error in the Xendit payment. Failure reason: No payment recorded"
81-
));
82-
return $this->_redirect('checkout/cart', [ '_secure'=> false ]);
115+
return $this->redirectToCart("There was an error in the Xendit payment. Failure reason: Unexpected Error");
83116
} catch (\Exception $e) {
84117
$message = 'Exception caught on xendit/checkout/redirect: ' . $e->getMessage();
85118
$this->getLogDNA()->log(LogDNALevel::ERROR, $message);
86119

87120
$this->cancelOrder($order, $e->getMessage());
88121

89-
$this->getMessageManager()->addErrorMessage(__(
90-
"There was an error in the Xendit payment. Failure reason: Unexpected Error"
91-
));
92-
return $this->_redirect('checkout/cart', [ '_secure'=> false ]);
122+
return $this->redirectToCart("There was an error in the Xendit payment. Failure reason: Unexpected Error");
123+
}
124+
}
125+
126+
private function getEwalletStatus($ewalletType, $externalId)
127+
{
128+
$ewalletUrl = $this->getDataHelper()->getCheckoutUrl() . "/payment/xendit/ewallets?ewallet_type=".$ewalletType."&external_id=".$externalId;
129+
$ewalletMethod = \Zend\Http\Request::METHOD_GET;
130+
131+
try {
132+
$response = $this->getApiHelper()->request($ewalletUrl, $ewalletMethod);
133+
} catch (\Magento\Framework\Exception\LocalizedException $e) {
134+
throw new LocalizedException(
135+
new Phrase($e->getMessage())
136+
);
137+
}
138+
139+
if ($ewalletType == 'DANA') {
140+
$response['status'] = $response['payment_status'];
141+
}
142+
143+
$statusList = array("COMPLETED", "PAID", "SUCCESS_COMPLETED"); //OVO, DANA, LINKAJA
144+
if (in_array($response['status'], $statusList)) {
145+
return "COMPLETED";
93146
}
147+
148+
return $response['status'];
149+
}
150+
151+
private function redirectToCart($failureReason)
152+
{
153+
$failureReasonInsight = $this->getDataHelper()->failureReasonInsight($failureReason);
154+
$this->getMessageManager()->addErrorMessage(__(
155+
$failureReasonInsight
156+
));
157+
$resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
158+
$resultRedirect->setUrl($this->_url->getUrl('checkout/cart'), [ '_secure'=> false ]);
159+
return $resultRedirect;
94160
}
95161
}

Xendit/M2Invoice/Helper/ApiRequest.php

+24-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Xendit\M2Invoice\Helper;
44

55
use Magento\Framework\Phrase;
6+
use Magento\Framework\App\ProductMetadataInterface;
67
use Magento\Framework\HTTP\ZendClientFactory;
78
use Psr\Log\LoggerInterface;
89
use Xendit\M2Invoice\Model\Payment\M2Invoice;
@@ -21,18 +22,27 @@ public function __construct(
2122
ZendClientFactory $httpClientFactory,
2223
Crypto $cryptoHelper,
2324
M2Invoice $m2Invoice,
24-
LoggerInterface $logger
25+
LoggerInterface $logger,
26+
ProductMetadataInterface $productMetadata
2527
) {
2628
$this->httpClientFactory = $httpClientFactory;
2729
$this->cryptoHelper = $cryptoHelper;
2830
$this->m2Invoice = $m2Invoice;
2931
$this->logger = $logger;
32+
$this->productMetadata = $productMetadata;
3033
}
3134

32-
public function request($url, $method, $requestData = null, $isPublicRequest = false, $preferredMethod = null, $customOptions = [])
33-
{
35+
public function request(
36+
$url,
37+
$method,
38+
$requestData = null,
39+
$isPublicRequest = false,
40+
$preferredMethod = null,
41+
$customOptions = [],
42+
$customHeaders = []
43+
) {
3444
$client = $this->httpClientFactory->create();
35-
$headers = $this->getHeaders($isPublicRequest, $preferredMethod);
45+
$headers = $this->getHeaders($isPublicRequest, $preferredMethod, $customHeaders);
3646
$options = [
3747
'timeout' => 30
3848
];
@@ -65,7 +75,7 @@ public function request($url, $method, $requestData = null, $isPublicRequest = f
6575
return $jsonResponse;
6676
}
6777

68-
private function getHeaders($isPublicRequest, $preferredMethod = null)
78+
private function getHeaders($isPublicRequest, $preferredMethod = null, $customHeaders = [])
6979
{
7080
$apiKey = $isPublicRequest ? $this->m2Invoice->getPublicApiKey() : $this->m2Invoice->getApiKey();
7181
$auth = $this->cryptoHelper->generateBasicAuth($apiKey);
@@ -74,7 +84,8 @@ private function getHeaders($isPublicRequest, $preferredMethod = null)
7484
'Authorization' => $auth,
7585
'Content-Type' => 'application/json',
7686
'x-plugin-name' => 'MAGENTO2',
77-
'user-agent' => 'Magento 2 Module'
87+
'user-agent' => 'Magento 2 Module',
88+
'x-plugin-version' => '1.7.0'
7889
];
7990

8091
if ($preferredMethod !== null) {
@@ -84,6 +95,13 @@ private function getHeaders($isPublicRequest, $preferredMethod = null)
8495
);
8596
}
8697

98+
foreach ($customHeaders as $customHeader => $value) {
99+
array_push(
100+
$headers,
101+
[ $customHeader => $value ]
102+
);
103+
}
104+
87105
return $headers;
88106
}
89107
}

Xendit/M2Invoice/Helper/Data.php

+18
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,24 @@ public function failureReasonInsight($failureReason)
143143
another card that is enabled for eCommerce, or ask your bank to enable eCommerce payments for your card.";
144144
case 'EXPIRED_CARD': return "$failureReason - Your bank declined the payment due to the card being expired. Please try
145145
another card that has not expired.";
146+
case 'USER_DID_NOT_AUTHORIZE_THE_PAYMENT':
147+
return 'Please complete the payment request within 60 seconds.';
148+
case 'USER_DECLINED_THE_TRANSACTION':
149+
return 'You rejected the payment request, please try again when needed.';
150+
case 'PHONE_NUMBER_NOT_REGISTERED':
151+
return 'Your number is not registered in OVO, please register first or contact OVO Customer Service.';
152+
case 'EXTERNAL_ERROR':
153+
return 'There is a technical issue happens on OVO, please contact the merchant to solve this issue.';
154+
case 'SENDING_TRANSACTION_ERROR':
155+
return 'Your transaction is not sent to OVO, please try again.';
156+
case 'EWALLET_APP_UNREACHABLE':
157+
return 'Do you have OVO app on your phone? Please check your OVO app on your phone and try again.';
158+
case 'REQUEST_FORBIDDEN_ERROR':
159+
return 'Your merchant disable OVO payment from his side, please contact your merchant to re-enable it
160+
before trying it again.';
161+
case 'DEVELOPMENT_MODE_PAYMENT_ACKNOWLEDGED':
162+
return 'Development mode detected. Please refer to our documentations for successful payment
163+
simulation';
146164
default: return $failureReason;
147165
}
148166
}

Xendit/M2Invoice/Model/Payment/OVO.php

+23-12
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Magento\Framework\Model\Context;
99
use Magento\Framework\Phrase;
1010
use Magento\Framework\Registry;
11+
use Magento\Sales\Model\Order;
1112
use Magento\Payment\Helper\Data;
1213
use Magento\Payment\Model\Method\Logger;
1314
use Xendit\M2Invoice\Helper\ApiRequest;
@@ -47,17 +48,24 @@ public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount
4748
$ewalletPayment = $this->requestEwalletPayment($args);
4849

4950
if ( isset($ewalletPayment['error_code']) ) {
50-
$message = $this->mapOvoErrorCode($ewalletPayment['error_code']);
51-
$this->processFailedPayment($payment, $message);
52-
53-
throw new \Magento\Framework\Exception\LocalizedException(
54-
new Phrase($message)
55-
);
56-
} else {
57-
$transactionId = $ewalletPayment['ewallet_transaction_id'];
58-
59-
$payment->setAdditionalInformation('xendit_ewallet_id', $transactionId);
51+
if ($ewalletPayment['error_code'] == 'DUPLICATE_PAYMENT_REQUEST_ERROR') {
52+
$args = array_replace($args, array(
53+
'external_id' => $this->dataHelper->getExternalId($orderId, true)
54+
));
55+
$ewalletPayment = $this->requestEwalletPayment($args);
56+
}
57+
58+
if (isset($ewalletPayment['error_code'])) {
59+
$message = $this->mapOvoErrorCode($ewalletPayment['error_code']);
60+
$this->processFailedPayment($payment, $message);
61+
62+
throw new \Magento\Framework\Exception\LocalizedException(
63+
new Phrase($message)
64+
);
65+
}
6066
}
67+
68+
$payment->setAdditionalInformation('xendit_ovo_external_id', $ewalletPayment['external_id']);
6169
} catch (\Exception $e) {
6270
$errorMsg = $e->getMessage();
6371
throw new \Magento\Framework\Exception\LocalizedException(
@@ -68,7 +76,7 @@ public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount
6876
return $this;
6977
}
7078

71-
private function requestEwalletPayment($requestData)
79+
private function requestEwalletPayment($requestData, $isRetried = true)
7280
{
7381
$ewalletUrl = $this->dataHelper->getCheckoutUrl() . "/payment/xendit/ewallets";
7482
$ewalletMethod = \Zend\Http\Request::METHOD_POST;
@@ -83,7 +91,10 @@ private function requestEwalletPayment($requestData)
8391
$requestData,
8492
null,
8593
null,
86-
$options
94+
$options,
95+
[
96+
'x-api-version' => '2020-02-01'
97+
]
8798
);
8899
} catch (\Exception $e) {
89100
throw $e;

Xendit/M2Invoice/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "xendit/m2invoice",
33
"description": "Xendit Payment Gateway Module",
44
"type": "magento2-module",
5-
"version": "1.6.2",
5+
"version": "1.7.0",
66
"license": [
77
"GPL-3.0"
88
],

0 commit comments

Comments
 (0)