Skip to content

Commit

Permalink
merge with 2018-01-10 delevery for 2.2 release publish
Browse files Browse the repository at this point in the history
  • Loading branch information
PaylineGitHub committed Jan 20, 2018
1 parent 623504c commit ca80d79
Show file tree
Hide file tree
Showing 30 changed files with 1,819 additions and 88 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
2.2
===
<h2>released on 2018-01-20</h2>
<ul>
<li>recurring payment method</li>
</ul>

2.1
===
<h2>released on 2018-01-05</h2>
Expand Down
158 changes: 157 additions & 1 deletion class/PaylinePaymentGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class PaylinePaymentGateway

const WEB_PAYMENT_METHOD = 1;
const RECURRING_PAYMENT_METHOD = 2;
const SUBSCRIBE_PAYMENT_METHOD = 3;

/**
* Response code that does define the transaction approved state
Expand Down Expand Up @@ -343,13 +344,18 @@ public static function createPaymentRequest(Context $context, $paymentMethod)
$paymentMode = 'CPT';
if ($paymentMethod == self::RECURRING_PAYMENT_METHOD) {
$paymentMode = 'NX';
} elseif ($paymentMethod == self::SUBSCRIBE_PAYMENT_METHOD) {
// Create first transaction into CPT mode, we will create recurrent wallet on notification/customer return
$paymentMode = 'CPT';
}
// Payment action
$paymentAction = '101';
if ($paymentMethod == self::WEB_PAYMENT_METHOD) {
$paymentAction = Configuration::get('PAYLINE_WEB_CASH_ACTION');
} elseif ($paymentMethod == self::RECURRING_PAYMENT_METHOD) {
$paymentAction = '101';
} elseif ($paymentMethod == self::SUBSCRIBE_PAYMENT_METHOD) {
$paymentAction = '101';
}

// Get contracts
Expand Down Expand Up @@ -413,7 +419,7 @@ public static function createPaymentRequest(Context $context, $paymentMethod)
}
}
// Set buyer wallet id
if (($paymentMethod == self::WEB_PAYMENT_METHOD && Configuration::get('PAYLINE_WEB_CASH_BY_WALLET')) || ($paymentMethod == self::RECURRING_PAYMENT_METHOD && Configuration::get('PAYLINE_RECURRING_BY_WALLET'))) {
if (($paymentMethod == self::WEB_PAYMENT_METHOD && Configuration::get('PAYLINE_WEB_CASH_BY_WALLET')) || ($paymentMethod == self::RECURRING_PAYMENT_METHOD && Configuration::get('PAYLINE_RECURRING_BY_WALLET')) || ($paymentMethod == self::SUBSCRIBE_PAYMENT_METHOD)) {
$params['buyer']['walletId'] = Tools::encrypt((int)$context->customer->id);
}
// Customization
Expand Down Expand Up @@ -443,6 +449,8 @@ public static function createPaymentRequest(Context $context, $paymentMethod)
$instance->addPrivateData(array('key' => 'id_cart', 'value' => (int)$context->cart->id));
$instance->addPrivateData(array('key' => 'id_customer', 'value' => (int)$context->customer->id));
$instance->addPrivateData(array('key' => 'secure_key', 'value' => (string)$context->cart->secure_key));
// Add payment method to private data
$instance->addPrivateData(array('key' => 'payment_method', 'value' => (int)$paymentMethod));
$result = $instance->doWebPayment($params);

if (self::isValidResponse($result)) {
Expand All @@ -452,6 +460,43 @@ public static function createPaymentRequest(Context $context, $paymentMethod)
return array(null, $params);
}

/**
* Create a request for subscription
* @since 2.3.0
* @param array $paymentInfos
* @return array
*/
public static function createSubscriptionRequest($paymentInfos)
{
// Get Payline instance
$instance = self::getInstance();

$paymentInfos['order']['date'] = date('d/m/Y H:i', self::getTimestampFromPaylineDate($paymentInfos['order']['date']));
$paymentInfos['payment']['mode'] = 'REC';

$params = array(
'version' => self::API_VERSION,
'payment' => $paymentInfos['payment'],
'orderRef' => $paymentInfos['order']['ref'],
'orderDate' => $paymentInfos['order']['date'],
'scheduledDate' => '',
'cardInd' => '',
'walletId' => $paymentInfos['wallet']['walletId'],
'recurring' => PaylinePaymentGateway::getSubscriptionConfiguration($paymentInfos['payment']['amount']),
'privateDataList' => $paymentInfos['privateDataList'],
'order' => $paymentInfos['order'],
);

// Add private data to the payment request
foreach ($paymentInfos['formatedPrivateDataList'] as $k => $v) {
$instance->addPrivateData(array('key' => $k, 'value' => $v));
}

$result = $instance->doRecurrentWalletPayment($params);

return $result;
}

/**
* Retrieve cart id from order reference
* @since 2.1.0
Expand Down Expand Up @@ -497,6 +542,75 @@ public static function getNxConfiguration($totalToPay)
);
}

/**
* Generate subscribe configuration depending on total to pay
* @since 2.2.0
* @param float $totalToPay
* @return array
*/
public static function getSubscriptionConfiguration($totalToPay)
{
$startDay = (int)Configuration::get('PAYLINE_SUBSCRIBE_DAY');
$subscribePeriodicity = (int)Configuration::get('PAYLINE_SUBSCRIBE_PERIODICITY');
$waitPeriod = (int)Configuration::get('PAYLINE_SUBSCRIBE_START_DATE') + 1;
// Remove 1 billing because we've already done it into CPT mode
$billingLeft = (Configuration::get('PAYLINE_SUBSCRIBE_NUMBER') > 1 ? ((int)Configuration::get('PAYLINE_SUBSCRIBE_NUMBER') - 1) : null);

switch ($subscribePeriodicity) {
case 10:
// Daily
$recurringStartDate = date('d/m/Y', strtotime(sprintf('now + %d day', $waitPeriod)));
break;
case 20:
// Weekly
$recurringStartDate = date('d/m/Y', strtotime(sprintf('now + %d week', $waitPeriod)));
break;
case 30:
// Bimonthly
$recurringStartDate = date('d/m/Y', strtotime(sprintf('now + %d week', $waitPeriod * 2)));
break;
case 40:
// Monthly
if ($startDay == 0) {
// Start date is the same day as the initial order
$recurringStartDate = date('d/m/Y', strtotime(sprintf('now + %d month', $waitPeriod)));
} else {
// Start date has a specific day, check if we have to go to the next month
$recurringStartDateTimeStamp = strtotime(sprintf('+ %d month ', $waitPeriod), mktime(date("H"), date("i"), date("s"), date("n"), $startDay, date("Y")));
$recurringStartDate = date('d/m/Y', $recurringStartDateTimeStamp);
}
break;
case 50:
// Two quaterly
$recurringStartDate = date('d/m/Y', strtotime(sprintf('now + %d month', $waitPeriod * 2)));
break;
case 60:
// Quaterly
$recurringStartDate = date('d/m/Y', strtotime(sprintf('now + %d month', $waitPeriod * 3)));
break;
case 70:
// Semiannual
$recurringStartDate = date('d/m/Y', strtotime(sprintf('now + %d month', $waitPeriod * 6)));
break;
case 80:
// Annual
$recurringStartDate = date('d/m/Y', strtotime(sprintf('now + %d year', $waitPeriod)));
break;
case 90:
// Biannual
$recurringStartDate = date('d/m/Y', strtotime(sprintf('now + %d year', $waitPeriod * 2)));
break;
}
return array(
'firstAmount' => null,
'amount' => $totalToPay,
'billingLeft' => $billingLeft,
'billingCycle' => Configuration::get('PAYLINE_SUBSCRIBE_PERIODICITY'),
'billingDay' => Configuration::get('PAYLINE_SUBSCRIBE_DAY') ? Configuration::get('PAYLINE_SUBSCRIBE_DAY') : date('d'),
'startDate' => $recurringStartDate,
);
}

/**
* Format address for Payline API request
* @since 2.0.0
Expand Down Expand Up @@ -667,6 +781,26 @@ public static function getPaymentRecord($contractNumber, $paymentRecordId)
return $result;
}

/**
* Disable payment record
* @since 2.2.0
* @param string $contractNumber
* @param string $paymentRecordId
* @return array
*/
public static function disablePaymentRecord($contractNumber, $paymentRecordId)
{
$instance = self::getInstance();
$params = array(
'version' => self::API_VERSION,
'contractNumber' => $contractNumber,
'paymentRecordId' => $paymentRecordId,
);
$result = $instance->disablePaymentRecord($params);

return $result;
}

/**
* Return number of validated transaction for a recurring payment
* @since 2.1.0
Expand Down Expand Up @@ -787,6 +921,28 @@ public static function resetTransaction($transactionId, $comment = null)
return $result;
}

/**
* Cancel a transaction (refund or reset depending on paymentInfos)
* @since 2.3.0
* @param array $paymentInfos
* @param string $comment
* @return bool
*/
public static function cancelTransaction($paymentInfos, $comment = null)
{
if ($paymentInfos['payment']['action'] == 100) {
// Cancel author
$resetTransaction = PaylinePaymentGateway::resetTransaction($paymentInfos['transaction']['id'], null, $comment);
$validResponse = PaylinePaymentGateway::isValidResponse($resetTransaction, array('02601', '02602'));
} else {
// Refund
$refundTransaction = PaylinePaymentGateway::refundTransaction($paymentInfos['transaction']['id'], null, $comment);
$validResponse = PaylinePaymentGateway::isValidResponse($refundTransaction);
}

return $validResponse;
}

/**
* Check if an API response is valid or not (check code 00000)
* @since 2.0.0
Expand Down
112 changes: 104 additions & 8 deletions class/PaylineToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,40 @@ class PaylineToken
* @param Order $order
* @param Cart $cart
* @param string $token
* @param string $paymentRecordId
* @param string $transactionId
* @return bool
*/
public static function insert(Order $order, Cart $cart, $token)
public static function insert(Order $order, Cart $cart, $token, $paymentRecordId = null, $transactionId = null)
{
if (empty($paymentRecordId)) {
$paymentRecordId = '';
}
if (empty($transactionId)) {
$transactionId = '';
}
return Db::getInstance()->execute('
INSERT IGNORE INTO `'._DB_PREFIX_.'payline_token` (`id_order`, `id_cart`, `token`)
VALUES('.(int)$order->id.', '.(int)$cart->id.', "'.pSQL($token).'")');
INSERT IGNORE INTO `'._DB_PREFIX_.'payline_token` (`id_order`, `id_cart`, `token`, `payment_record_id`, `transaction_id`)
VALUES('.(int)$order->id.', '.(int)$cart->id.', "'.pSQL($token).'", "'.pSQL($paymentRecordId).'", "'.pSQL($transactionId).'")');
}

/**
* Update payment_record_id into table
* @param Order $order
* @param string $paymentRecordId
* @return bool
*/
public static function setPaymentRecordIdByIdOrder(Order $order, $paymentRecordId)
{
return Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'payline_token` SET `payment_record_id`="'.pSQL($paymentRecordId).'" WHERE `id_order`='.(int)$order->id);
}

/**
* Retrieve token by id_order
* @param int $idOrder
* @return string
*/
public static function getByIdOrder($idOrder)
public static function getTokenByIdOrder($idOrder)
{
$result = Db::getInstance()->getValue('SELECT `token` FROM `'._DB_PREFIX_.'payline_token` WHERE `id_order`='.(int)$idOrder);
if (!empty($result)) {
Expand All @@ -38,15 +57,92 @@ public static function getByIdOrder($idOrder)
}

/**
* Retrieve token by id_cart
* @param int $idCart
* Retrieve payment record id by id_order
* @param int $idOrder
* @return string
*/
public static function getPaymentRecordIdByIdOrder($idOrder)
{
$result = Db::getInstance()->getValue('SELECT `payment_record_id` FROM `'._DB_PREFIX_.'payline_token` WHERE `id_order`='.(int)$idOrder);
if (!empty($result)) {
return $result;
}

return null;
}

/**
* Retrieve list of payment record id by id_customer
* @param int $idCustomer
* @return array
*/
public static function getPaymentRecordIdListByIdCustomer($idCustomer)
{
$paymentRecordIdList = array();

$result = Db::getInstance()->executeS('SELECT DISTINCT `payment_record_id` FROM `'._DB_PREFIX_.'payline_token` WHERE `id_order` IN (SELECT `id_order` FROM `'._DB_PREFIX_.'orders` WHERE `id_customer`='.(int)$idCustomer . ')');
if (!empty($result)) {
foreach ($result as $paymentRecordRow) {
$paymentRecordIdList[] = $paymentRecordRow['payment_record_id'];
}
}

return $paymentRecordIdList;
}

/**
* Retrieve list of id_order for a payment_record_id
* @param string $paymentRecordId
* @return array
*/
public static function getIdOrderListByPaymentRecordId($paymentRecordId)
{
$idOrderList = array();

$result = Db::getInstance()->executeS('SELECT DISTINCT `id_order` FROM `'._DB_PREFIX_.'payline_token` WHERE `payment_record_id`="'.pSQL($paymentRecordId).'" ORDER BY `id_order`');
if (!empty($result)) {
foreach ($result as $paymentRecordRow) {
$idOrderList[] = $paymentRecordRow['id_order'];
}
}

return $idOrderList;
}

/**
* Retrieve id_transaction by id_order
* @param int $idOrder
* @return string
*/
public static function getIdTransactionByIdOrder($idOrder)
{
$result = Db::getInstance()->getValue('SELECT `transaction_id` FROM `'._DB_PREFIX_.'payline_token` WHERE `id_order`='.(int)$idOrder);
if (!empty($result)) {
return $result;
}

return null;
}

/**
* Retrieve id_order by transaction_id
* @param int $idTransaction
* @return string
*/
public static function getByIdCart($idCart)
public static function getIdOrderByIdTransaction($idTransaction)
{
$result = Db::getInstance()->getValue('SELECT `token` FROM `'._DB_PREFIX_.'payline_token` WHERE `id_order`='.(int)$idCart);
$result = Db::getInstance()->getValue('SELECT `id_order` FROM `'._DB_PREFIX_.'payline_token` WHERE `transaction_id`="'.pSQL($idTransaction).'"');
if (!empty($result)) {
return $result;
} else {
// Fallback method, use native PrestaShop table
$orderReference = Db::getInstance()->getValue('SELECT `order_reference` FROM `'._DB_PREFIX_.'order_payment` WHERE `transaction_id`="'.pSQL($idTransaction).'"');
if (!empty($orderReference)) {
$idOrder = Db::getInstance()->getValue('SELECT `id_order` FROM `'._DB_PREFIX_.'orders` WHERE `reference`="'.pSQL($orderReference).'"');
if (!empty($idOrder)) {
return $idOrder;
}
}
}

return null;
Expand Down
4 changes: 3 additions & 1 deletion controllers/front/notification.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ public function initContent()
$this->module->processNotification(Tools::getValue('token'));
} elseif ($notificationType == 'TRS' && Tools::getValue('transactionId')) {
$this->module->processTransactionNotification(Tools::getValue('transactionId'));
} elseif ($notificationType == 'BILL' && Tools::getValue('transactionId') && Tools::getValue('paymentRecordId')) {
} elseif ($notificationType == 'BILL' && Tools::getValue('transactionId') && Tools::getValue('paymentRecordId') && Tools::getValue('paymentMode') == 'NX') {
$this->module->processNxNotification(Tools::getValue('transactionId'), Tools::getValue('paymentRecordId'));
} elseif ($notificationType == 'BILL' && Tools::getValue('transactionId') && Tools::getValue('paymentRecordId') && Tools::getValue('paymentMode') == 'REC') {
$this->module->processRecNotification(Tools::getValue('transactionId'), Tools::getValue('paymentRecordId'));
} else {
PrestaShopLogger::addLog('Payline - Unknown notification type "'. $notificationType .'"');
}
Expand Down
Loading

0 comments on commit ca80d79

Please sign in to comment.