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