We will be off from 27/1 (Monday) to 31/1 (Friday) (GMT +7) for our Tet Holiday (Lunar New Year) in our country

Commit bddfa80f authored by Alessio Zampatti's avatar Alessio Zampatti Committed by GitHub

Merge pull request #172 from Adyen/recurring-cse

Fixed notifications received for Recurring contracts, CSE token not sent if the date is not updated.
parents ce18e7eb 0b4a91f1
......@@ -287,9 +287,12 @@ class Json extends \Magento\Framework\App\Action\Action
$pspReference = trim($response['pspReference']);
$eventCode = trim($response['eventCode']);
$success = trim($response['success']);
$originalReference = null;
if(isset($response['originalReference'])) {
$originalReference = trim($response['originalReference']);
}
$notification = $this->_objectManager->create('Adyen\Payment\Model\Notification');
return $notification->isDuplicate($pspReference, $eventCode, $success);
return $notification->isDuplicate($pspReference, $eventCode, $success, $originalReference);
}
/**
......
......@@ -784,133 +784,110 @@ class Cron
}
}
break;
case Notification::RECURRING_CONTRACT:
case Notification::RECURRING_CONTRACT:
// storedReferenceCode
$recurringDetailReference = $this->_pspReference;
// check if there is already a BillingAgreement
$billingAgreement = $this->_billingAgreementFactory->create();
$billingAgreement->load($recurringDetailReference, 'reference_id');
if ($billingAgreement && $billingAgreement->getAgreementId() > 0 && $billingAgreement->isValid()) {
$storeId = $this->_order->getStoreId();
$customerReference = $this->_order->getCustomerId();
$listRecurringContracts = null;
$this->_adyenLogger->addAdyenNotificationCronjob(
__('CustomerReference is: %1 and storeId is %2 and RecurringDetailsReference is %3', $customerReference, $storeId, $recurringDetailReference)
);
try {
$listRecurringContracts = $this->_adyenPaymentRequest->getRecurringContractsForShopper(
$customerReference, $storeId
);
$contractDetail = null;
// get current Contract details and get list of all current ones
$recurringReferencesList = [];
try {
$billingAgreement->addOrderRelation($this->_order);
$billingAgreement->setStatus($billingAgreement::STATUS_ACTIVE);
$billingAgreement->setIsObjectChanged(true);
$this->_order->addRelatedObject($billingAgreement);
$message = __('Used existing billing agreement #%s.', $billingAgreement->getReferenceId());
} catch (Exception $e) {
// could be that it is already linked to this order
$message = __('Used existing billing agreement #%s.', $billingAgreement->getReferenceId());
if (!$listRecurringContracts) {
throw new \Exception("Empty list recurring contracts");
}
// Find the reference on the list
foreach ($listRecurringContracts as $rc) {
$recurringReferencesList[] = $rc['recurringDetailReference'];
if (isset($rc['recurringDetailReference']) &&
$rc['recurringDetailReference'] == $recurringDetailReference) {
$contractDetail = $rc;
}
}
} else {
$this->_order->getPayment()->setBillingAgreementData(
[
'billing_agreement_id' => $recurringDetailReference,
'method_code' => $this->_order->getPayment()->getMethodCode(),
]
);
// create new object
$billingAgreement = $this->_billingAgreementFactory->create();
$billingAgreement->setStoreId($this->_order->getStoreId());
$billingAgreement->importOrderPayment($this->_order->getPayment());
if ($contractDetail == null) {
$this->_adyenLogger->addAdyenNotificationCronjob(print_r($listRecurringContracts, 1));
$message = __(
'Failed to create billing agreement for this order ' .
'(listRecurringCall did not contain contract)'
);
throw new \Exception($message);
}
// get all data for this contract by doing a listRecurringCall
$customerReference = $billingAgreement->getCustomerReference();
$storeId = $billingAgreement->getStoreId();
$billingAgreements = $this->_billingAgreementCollectionFactory->create();
$billingAgreements->addFieldToFilter('customer_id', $customerReference);
/*
* for quest checkout users we can't save this in the billing agreement
* because it is linked to customer
*/
if ($customerReference && $storeId) {
// Get collection and update existing agreements
$listRecurringContracts = null;
try {
$listRecurringContracts = $this->_adyenPaymentRequest->getRecurringContractsForShopper(
$customerReference, $storeId
foreach ($billingAgreements as $updateBillingAgreement) {
if (!in_array($updateBillingAgreement->getReferenceId(), $recurringReferencesList)) {
$updateBillingAgreement->setStatus(
\Adyen\Payment\Model\Billing\Agreement::STATUS_CANCELED
);
} else {
$updateBillingAgreement->setStatus(
\Adyen\Payment\Model\Billing\Agreement::STATUS_ACTIVE
);
} catch(\Exception $exception) {
$this->_adyenLogger->addAdyenNotificationCronjob($exception->getMessage());
}
$updateBillingAgreement->save();
}
$contractDetail = null;
// get current Contract details and get list of all current ones
$recurringReferencesList = [];
if ($listRecurringContracts) {
foreach ($listRecurringContracts as $rc) {
$recurringReferencesList[] = $rc['recurringDetailReference'];
if (isset($rc['recurringDetailReference']) &&
$rc['recurringDetailReference'] == $recurringDetailReference) {
$contractDetail = $rc;
}
}
}
// Get or create billing agreement
$billingAgreement = $this->_billingAgreementFactory->create();
$billingAgreement->load($recurringDetailReference, 'reference_id');
// check if BA exists
if (!($billingAgreement && $billingAgreement->getAgreementId() > 0 && $billingAgreement->isValid())) {
// create new
$this->_adyenLogger->addAdyenNotificationCronjob("Creating new Billing Agreement");
$this->_order->getPayment()->setBillingAgreementData(
[
'billing_agreement_id' => $recurringDetailReference,
'method_code' => $this->_order->getPayment()->getMethodCode(),
]
);
if ($contractDetail != null) {
// update status of all the current saved agreements in magento
$billingAgreements = $this->_billingAgreementCollectionFactory->create();
$billingAgreements->addFieldToFilter('customer_id', $customerReference);
// get collection
foreach ($billingAgreements as $updateBillingAgreement) {
if (!in_array($updateBillingAgreement->getReferenceId(), $recurringReferencesList)) {
$updateBillingAgreement->setStatus(
\Adyen\Payment\Model\Billing\Agreement::STATUS_CANCELED
);
$updateBillingAgreement->save();
} else {
$updateBillingAgreement->setStatus(
\Adyen\Payment\Model\Billing\Agreement::STATUS_ACTIVE
);
$updateBillingAgreement->save();
}
}
// add this billing agreement
$billingAgreement->parseRecurringContractData($contractDetail);
if ($billingAgreement->isValid()) {
$message = __('Created billing agreement #%1.', $billingAgreement->getReferenceId());
// save into sales_billing_agreement_order
$billingAgreement->addOrderRelation($this->_order);
// add to order to save agreement
$this->_order->addRelatedObject($billingAgreement);
} else {
$message = __('Failed to create billing agreement for this order.');
}
$billingAgreement = $this->_billingAgreementFactory->create();
$billingAgreement->setStoreId($this->_order->getStoreId());
$billingAgreement->importOrderPayment($this->_order->getPayment());
$message = __('Created billing agreement #%1.', $recurringDetailReference);
}
else {
$this->_adyenLogger->addAdyenNotificationCronjob("Using existing Billing Agreement");
$billingAgreement->setIsObjectChanged(true);
$message = __('Updated billing agreement #%1.', $recurringDetailReference);
}
// Populate billing agreement data
$billingAgreement->parseRecurringContractData($contractDetail);
if ($billingAgreement->isValid()) {
} else {
$this->_adyenLogger->addAdyenNotificationCronjob(
'Failed to create billing agreement for this order ' .
'(listRecurringCall did not contain contract)'
);
$this->_adyenLogger->addAdyenNotificationCronjob(
__('recurringDetailReference in notification is %1', $recurringDetailReference)
);
$this->_adyenLogger->addAdyenNotificationCronjob(
__('CustomerReference is: %1 and storeId is %2', $customerReference, $storeId)
);
$this->_adyenLogger->addAdyenNotificationCronjob(print_r($listRecurringContracts, 1));
$message = __(
'Failed to create billing agreement for this order ' .
'(listRecurringCall did not contain contract)'
);
}
// save into sales_billing_agreement_order
$billingAgreement->addOrderRelation($this->_order);
$comment = $this->_order->addStatusHistoryComment($message);
$this->_order->addRelatedObject($comment);
// add to order to save agreement
$this->_order->addRelatedObject($billingAgreement);
} else {
$message = __('Failed to create billing agreement for this order.');
throw new \Exception($message);
}
} catch(\Exception $exception) {
$message = $exception->getMessage();
}
$this->_adyenLogger->addAdyenNotificationCronjob($message);
$comment = $this->_order->addStatusHistoryComment($message);
$this->_order->addRelatedObject($comment);
break;
default:
$this->_adyenLogger->addAdyenNotificationCronjob(
......@@ -976,7 +953,7 @@ class Cron
}
} else {
$this->_adyenLogger->addAdyenNotificationCronjob(
'Did not create a credit memo for this order becasue refund is done through Magento'
'Did not create a credit memo for this order because refund is done through Magento'
);
}
}
......
......@@ -84,11 +84,12 @@ class Notification extends \Magento\Framework\Model\AbstractModel
* @param $pspReference
* @param $eventCode
* @param $success
* @param $originalReference
* @return bool (true if the notification is a duplicate)
*/
public function isDuplicate($pspReference, $eventCode, $success)
public function isDuplicate($pspReference, $eventCode, $success, $originalReference)
{
$result = $this->getResource()->getNotification($pspReference, $eventCode, $success);
$result = $this->getResource()->getNotification($pspReference, $eventCode, $success, $originalReference);
return (empty($result)) ? false : true;
}
......
......@@ -40,15 +40,17 @@ class Notification extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
* @param $pspReference
* @param $eventCode
* @param $success
* @param $originalReference
* @return array
*/
public function getNotification($pspReference, $eventCode, $success)
public function getNotification($pspReference, $eventCode, $success, $originalReference)
{
$select = $this->getConnection()->select()
->from(['notification' => $this->getTable('adyen_notification')])
->where('notification.pspreference=?', $pspReference)
->where('notification.event_code=?', $eventCode)
->where('notification.success=?', $success);
->where('notification.success=?', $success)
->where('notification.original_reference=?', $originalReference);
return $this->getConnection()->fetchAll($select);
}
}
\ No newline at end of file
......@@ -37,6 +37,7 @@ define(
],
function (ko, _, $, Component, placeOrderAction, $t, additionalValidators, selectPaymentMethodAction, quote, checkoutData) {
'use strict';
var updatedExpiryDate = false;
var recurringDetailReference = ko.observable(null);
var paymentMethod = ko.observable(null);
return Component.extend({
......@@ -90,10 +91,7 @@ define(
// only use CSE and installments for cards
if (self.agreement_data.card) {
var cse_key = this.getCSEKey();
var options = { enableValidations: false};
var cseInstance = adyen.encrypt.createEncryption(cse_key, options);
var generationtime = self.getGenerationTime();
var cardData = {
......@@ -103,10 +101,17 @@ define(
generationtime : generationtime
};
var encryptedData = cseInstance.encrypt(cardData);
if(updatedExpiryDate || self.hasVerification()){
var options = { enableValidations: false};
var cse_key = this.getCSEKey();
var cseInstance = adyen.encrypt.createEncryption(cse_key, options);
var encryptedData = cseInstance.encrypt(cardData);
data.additional_data.encrypted_data = encryptedData;
}
// set payment method to adyen_hpp
data.additional_data.encrypted_data = encryptedData;
data.additional_data.number_of_installments = self.installment;
}
......@@ -180,6 +185,9 @@ define(
getGenerationTime: function() {
return window.checkoutConfig.payment.adyenCc.generationTime;
},
hasVerification: function() {
return window.checkoutConfig.payment.adyenOneclick.hasCustomerInteraction;
},
validate: function () {
var code = self.item.method;
......@@ -192,13 +200,13 @@ define(
// if oneclick or recurring is a card do validation on expiration date
if(this.agreement_data.card) {
// add extra validation because jqeury validation will not work on non name attributes
// add extra validation because jquery validation will not work on non name attributes
var expiration = Boolean($(form + ' #' + codeValue + '_expiration').valid());
var expiration_yr = Boolean($(form + ' #' + codeValue + '_expiration_yr').valid());
// only check if recurring type is set to oneclick
var cid = true;
if(self.hasVerification()) {
if(this.hasVerification()) {
var cid = Boolean($(form + ' #' + codeValue + '_cc_cid').valid());
}
} else {
......@@ -214,6 +222,7 @@ define(
return true;
},
selectExpiry: function() {
updatedExpiryDate = true;
var self = this;
self.expiry(true);
return true;
......@@ -224,6 +233,8 @@ define(
},
selectBillingAgreement: function() {
var self = this;
self.expiry(false);
updatedExpiryDate = false;
// set payment method data
var data = {
......@@ -256,9 +267,6 @@ define(
}
return null;
}),
hasVerification: function() {
return window.checkoutConfig.payment.adyenOneclick.hasCustomerInteraction;
},
getPlaceOrderUrl: function() {
return window.checkoutConfig.payment.iframe.placeOrderUrl[this.getCode()];
}
......
......@@ -131,7 +131,7 @@
</div>
<!-- ko if: ($parent.hasVerification())-->
<!-- ko if: hasVerification()-->
<div class="field cvv required" data-bind="attr: {id: getCode() + '_' + value + '_cc_type_cvv_div'}">
<label data-bind="attr: {for: getCode() + '_' + value + '_cc_cid'}" class="label">
<span><!-- ko text: $t('Card Verification Number')--><!-- /ko --></span>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment