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
$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