Files
hotel/modules/qlopaypalcommerce/controllers/front/payment.php
2026-09-15 17:18:19 +05:30

408 lines
20 KiB
PHP

<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.md
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to support@qloapps.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to a newer
* versions in the future. If you wish to customize this module for your needs
* please refer to https://store.webkul.com/customisation-guidelines for more information.
*
* @author Webkul IN
* @copyright Since 2010 Webkul
* @license https://opensource.org/licenses/afl-3.0.php Academic Free License 3.0
*/
class QloPaypalCommercePaymentModuleFrontController extends ModuleFrontController
{
const WK_PAYPAL_COMMERCE_ACTION_CREATE_ORDER = 1;
const WK_PAYPAL_COMMERCE_ACTION_CAPTURE_ORDER = 2;
const WK_PAYPAL_COMMERCE_ACTION_CANCELLED = 3;
public function init()
{
parent::init();
$cart = $this->context->cart;
// cehck cart details
if ($cart->id_customer == 0
|| !$this->module->active
) {
Tools::redirect($this->context->link->getPageLink('order-opc', true, null));
}
// Check that this payment option is still available in case the customer
// changed his address just before the end of the checkout process
$authorized = false;
foreach (Module::getPaymentModules() as $module) {
if ($module['name'] == 'qlopaypalcommerce') {
$authorized = true;
break;
}
}
if (!$authorized) {
die($this->module->l('This payment method is not available.', 'payment'));
}
$customer = new Customer($cart->id_customer);
if (!Validate::isLoadedObject($customer)) {
Tools::redirect($this->context->link->getPageLink('order-opc', true, null));
}
}
public function initContent()
{
parent::initContent();
if ($this->module->secure_key != Tools::getValue('token')) {
die($this->module->l('Invalid token.', 'payment'));
}
if (Tools::isSubmit('action')) {
$action = (int)Tools::getValue('action');
switch ($action) {
case self::WK_PAYPAL_COMMERCE_ACTION_CREATE_ORDER:
$json = Tools::file_get_contents('php://input');
$orderDetails = json_decode($json, true);
$cart = $this->context->cart;
WkPaypalCommerceHelper::logMsg('payment', 'Payment initiated...', true);
WkPaypalCommerceHelper::logMsg('payment', 'Environment: '. Configuration::get('WK_PAYPAL_COMMERCE_PAYMENT_MODE'));
WkPaypalCommerceHelper::logMsg('payment', 'Cart ID: '. $cart->id);
WkPaypalCommerceHelper::logMsg('payment', 'Customer ID: '. $cart->id_customer);
WkPaypalCommerceHelper::logMsg('payment', 'Currency ID: '. $cart->id_currency);
WkPaypalCommerceHelper::logMsg('payment', 'Cart Total: '. $cart->getOrderTotal(true, Cart::BOTH));
WkPaypalCommerceHelper::logMsg('payment', 'Payment request data: ');
$ppCommerce = new PayPalCommerce();
header('Content-Type: application/json');
// create order
$orderDetails['original'] = $this->getOrderDetails();
WkPaypalCommerceHelper::logMsg('payment', json_encode($orderDetails));
$ppOrderData = $ppCommerce->orders->create($orderDetails);
WkPaypalCommerceHelper::logMsg('payment', 'Payment response data: ', true);
WkPaypalCommerceHelper::logMsg('payment', json_encode($ppOrderData));
die(json_encode($ppOrderData));
case self::WK_PAYPAL_COMMERCE_ACTION_CAPTURE_ORDER:
$json = Tools::file_get_contents('php://input');
$orderData = json_decode($json, true);
if ($orderData['orderID'] && $orderData['getOrderData']) {
$ppCommerce = new PayPalCommerce();
$returnData = $ppCommerce->orders->capture($orderData['orderID']);
header('Content-Type: application/json');
echo json_encode($returnData['data']);
die;
} elseif (Tools::getIsset('order_id')) {
$orderID = Tools::getValue('order_id');
$ppCommerce = new PayPalCommerce();
$returnData = $ppCommerce->orders->get($orderID);
$cart = $this->context->cart;
$customer = new Customer($cart->id_customer);
WkPaypalCommerceHelper::logMsg('payment', 'Payment response...', true);
WkPaypalCommerceHelper::logMsg('payment', 'Cart ID: '. $cart->id);
WkPaypalCommerceHelper::logMsg('payment', 'Customer ID: '. $cart->id_customer);
WkPaypalCommerceHelper::logMsg('payment', 'Currency ID: '. $cart->id_currency);
WkPaypalCommerceHelper::logMsg('payment', 'Cart Total: '. $cart->getOrderTotal(true, Cart::BOTH));
WkPaypalCommerceHelper::logMsg('payment', json_encode($returnData));
if (isset($returnData['data']['id']) && !empty($returnData['data']['id'])) {
// Payment success
$paypalOrderID = $returnData['data']['id'];
$paymentStatus = '';
if (isset($returnData['data']['purchase_units'][0]['payments']['captures'][0]['status'])) {
$paymentStatus = $returnData['data']['purchase_units'][0]['payments']['captures'][0]['status'];
}
$paypalOrderCartId = isset($returnData['data']['purchase_units'][0]['custom_id']) ? $returnData['data']['purchase_units'][0]['custom_id'] : null;
$belongsToCurrentCart = ((int) $paypalOrderCartId === (int) $cart->id);
if ($paypalOrderID && $paymentStatus == WkPaypalCommerceWebhook::WK_PAYPAL_COMMERCE_PAYMENT_STATUS_COMPLETED && $belongsToCurrentCart) {
// Save order data
$this->saveOrderData($returnData);
$currency = $this->context->currency;
// Order status/amount must reflect what PayPal actually captured,
// not the cart's is_advance_payment flag (still editable by the
// customer after payment, so it cannot be trusted here).
$capturedAmount = isset($returnData['data']['purchase_units'][0]['payments']['captures'][0]['amount']['value']) ?
(float) $returnData['data']['purchase_units'][0]['payments']['captures'][0]['amount']['value'] : 0;
$fullTotal = (float) $cart->getOrderTotal(true, Cart::BOTH);
$isFullyPaid = $capturedAmount >= $fullTotal;
// set order status
if ($returnData['data']['status'] == WkPaypalCommerceWebhook::WK_PAYPAL_COMMERCE_PAYMENT_STATUS_COMPLETED) {
$orderStatus = $isFullyPaid
? Configuration::get('PS_OS_PAYMENT_ACCEPTED')
: Configuration::get('PS_OS_PARTIAL_PAYMENT_ACCEPTED');
} else {
$orderStatus = Configuration::get('PS_OS_AWAITING_PAYMENT');
}
$transactionId = '';
if (isset($returnData['data']['purchase_units'][0]['payments']['captures'][0]['id'])) {
$transactionId = $returnData['data']['purchase_units'][0]['payments']['captures'][0]['id'];
}
$extraVars = array('transaction_id' => $transactionId);
// create order for the payment
$this->module->validateOrder(
$cart->id,
$orderStatus,
$capturedAmount,
$this->module->l('PayPal Checkout', 'payment'),
null,
$extraVars,
(int)$currency->id,
false,
$customer->secure_key
);
// Update order id in paypal_seller_order table
$objOrder = new Order($this->module->currentOrder);
WkPayPalCommerceOrder::updateOrderReference(
$paypalOrderID,
$objOrder->reference
);
WkPaypalCommerceHelper::logMsg('payment', 'Order ID: '. $this->module->currentOrder);
WkPaypalCommerceHelper::logMsg('payment', '--------------', true);
$link = new Link();
$orderLink = $link->getPageLink(
'order-confirmation',
null,
(int)Context::getContext()->language->id,
array(
'id_cart' => (int)$cart->id,
'id_module' => (int)$this->module->id,
'id_order' => (int)$this->module->currentOrder,
'key' => $customer->secure_key,
)
);
Tools::redirect($orderLink);
} else {
if ($paypalOrderID && $paymentStatus == WkPaypalCommerceWebhook::WK_PAYPAL_COMMERCE_PAYMENT_STATUS_COMPLETED && !$belongsToCurrentCart) {
WkPaypalCommerceHelper::logMsg(
'payment',
'PayPal order/cart mismatch. Expected cart: '.$cart->id.', PayPal custom_id: '.$paypalOrderCartId
);
}
WkPaypalCommerceHelper::logMsg('payment', 'Payment status'. $returnData['data']['status']);
WkPaypalCommerceHelper::logMsg('payment', '--------------', true);
Tools::redirect('index.php?controller=order&step=1');
}
} else {
WkPaypalCommerceHelper::logMsg('payment', 'Payment failed...', true);
WkPaypalCommerceHelper::logMsg(
'payment',
'Payment failed message: '.$returnData['data']['name']
);
WkPaypalCommerceHelper::logMsg(
'payment',
'Payment failed message: '.$returnData['data']['message']
);
WkPaypalCommerceHelper::logMsg('payment', '--------------', true);
$failedLink = $this->context->link->getModuleLink(
'qlopaypalcommerce',
'errorpayment',
array(
'err_name' => $returnData['data']['name'],
'err_msg' => $returnData['data']['message']
)
);
Tools::redirect($failedLink);
}
}
break;
case self::WK_PAYPAL_COMMERCE_ACTION_CANCELLED:
WkPaypalCommerceHelper::logMsg('payment', 'Payment cancelled by customer...', true);
WkPaypalCommerceHelper::logMsg('payment', json_encode(Tools::getAllValues()));
WkPaypalCommerceHelper::logMsg('payment', '--------------', true);
Tools::redirect($this->context->link->getPageLink('order-opc', true, null).'?pp_cancel=1');
break;
default:
# code...
break;
}
}
die;
}
// Save order data
private function saveOrderData($orderData)
{
if ($orderData) {
$purchaseUnits = $orderData['data']['purchase_units'];
foreach ($purchaseUnits as $purchase) {
$transactionId = $purchase['payments']['captures'][0]['id'];
$paymentStatus = $purchase['payments']['captures'][0]['status'];
$paymentTotal = $purchase['payments']['captures'][0]['amount']['value'];
$paymentCurrency = $purchase['payments']['captures'][0]['amount']['currency_code'];
$cart = $this->context->cart;
$currency = Currency::getCurrency((int) $cart->id_currency);
// total order amount
if ($cart->is_advance_payment) {
$cartTotalAmountTI = $cart->getOrderTotal(true, Cart::ADVANCE_PAYMENT);
} else {
$cartTotalAmountTI = $cart->getOrderTotal(true, Cart::BOTH);
}
$orderObj = new WkPayPalCommerceOrder();
$orderObj->order_reference = '';
$orderObj->id_cart = (int)$cart->id;
$orderObj->id_currency = (int)$cart->id_currency;
$orderObj->environment = Configuration::get('WK_PAYPAL_COMMERCE_PAYMENT_MODE');
$orderObj->id_customer = (int)$cart->id_customer;
$orderObj->order_total = (float)$cartTotalAmountTI;
$orderObj->checkout_currency = $currency['iso_code'];
// PayPal Returned Data
$orderObj->pp_paid_total = (float)$paymentTotal;
$orderObj->pp_paid_currency = $paymentCurrency;
$orderObj->pp_reference_id = $purchase['reference_id'];
$orderObj->pp_order_id = $orderData['data']['id'];
$orderObj->pp_transaction_id = $transactionId;
$orderObj->pp_payment_status = $paymentStatus;
$orderObj->response = json_encode($orderData);
$orderObj->order_date = date('Y-m-d H:i:s');
$orderObj->save();
}
return true;
}
return false;
}
// Create order data to send to PayPal
private function getOrderDetails()
{
$orderData = array();
$orderData['intent'] = 'CAPTURE';
$cart = $this->context->cart;
$customer = new Customer((int)$cart->id_customer);
$ppHelper = new WkPaypalCommerceHelper();
$orderData['payer'] = array(
'name' => array(
'given_name' => $customer->firstname,
'surname' => $customer->lastname
),
'email_address' => $customer->email
);
// address is not required in paypal payment, if customer has added an address then we add tha address to paypal payer object
if ($billingAddress = $ppHelper->getSimpleAddress(
(int)$cart->id_customer,
(int)$cart->id_address_invoice
)) {
$orderData['payer']['address'] = array(
'address_line_1' => $billingAddress['address1'],
'address_line_2' => $billingAddress['address2'],
'admin_area_2' => $billingAddress['city'],
'admin_area_1' => $billingAddress['state_iso'],
'postal_code' => $billingAddress['postcode'],
'country_code' => $billingAddress['country_iso'],
);
}
$timestamp = time().rand(100, 999);
$currency = Currency::getCurrency((int) $cart->id_currency);
$discountTI = $cart->getOrderTotal(true, Cart::ONLY_DISCOUNTS);
$discountTE = $cart->getOrderTotal(false, Cart::ONLY_DISCOUNTS);
// total cart amount
// items totals will be calculated after removing discount from the total cart as additional facility is also considered as an item
if ($cart->is_advance_payment) {
$cartTotalAmountTI = $cart->getOrderTotal(true, Cart::ADVANCE_PAYMENT);
$cartTotalAmountTE = $cart->getOrderTotal(false, Cart::ADVANCE_PAYMENT);
$itemTotalAmountTI = $cartTotalAmountTI + $discountTI;
$itemTotalAmountTE = $cartTotalAmountTE + $discountTE;
} else {
$cartTotalAmountTI = $cart->getOrderTotal(true, Cart::BOTH);
$cartTotalAmountTE = $cart->getOrderTotal(false, Cart::BOTH);
$itemTotalAmountTI = $cartTotalAmountTI + $discountTI;
$itemTotalAmountTE = $cartTotalAmountTE + $discountTE;
}
$orderData['purchase_units'][0] = array(
'reference_id' => $timestamp,
'description' => "Payment for " . Configuration::get('PS_SHOP_NAME'),
// Maxlength 22
'soft_descriptor' => Tools::substr(Configuration::get('PS_SHOP_NAME'), 0, 21),
'payment_group_id' => 1,
'custom_id' => $cart->id,
'invoice_id' => 'INV-' . $timestamp,
);
$orderData['purchase_units'][0]['amount'] = array(
'currency_code' => $currency['iso_code'],
'value' => number_format(Tools::ps_round($cartTotalAmountTI, 2), 2, '.', ''),
'breakdown' => array(
'item_total' => array(
'currency_code' => $currency['iso_code'],
'value' => number_format(Tools::ps_round($itemTotalAmountTE, 2), 2, '.', ''),
),
'shipping' => array(
'currency_code' => $currency['iso_code'],
'value' => '0.00',
),
'shipping_discount' => array(
'currency_code' => $currency['iso_code'],
'value' => '0.00',
),
'tax_total' => array(
'currency_code' => $currency['iso_code'],
'value' => number_format(Tools::ps_round(($itemTotalAmountTI - $itemTotalAmountTE), 2), 2, '.', ''),
),
'discount' => array(
'currency_code' => $currency['iso_code'],
'value' => number_format(Tools::ps_round($discountTI, 2), 2, '.', ''),
),
)
);
// set item details (for rounding issue, paypal said not to send item details)
// $items = $ppHelper->getPaypalOrderItemDetails($cart->id);
// $orderData['purchase_units'][0]['items'] = array_values($items);
$wkEnvironment = Configuration::get('WK_PAYPAL_COMMERCE_PAYMENT_MODE');
$merchantId = ($wkEnvironment == QloPaypalCommerce::WK_PAYPAL_COMMERCE_PAYMENT_MODE_PRODUCTION) ? Configuration::get('WK_PAYPAL_COMMERCE_LIVE_MERCHANT_ID') : Configuration::get('WK_PAYPAL_COMMERCE_SANDBOX_MERCHANT_ID');
$orderData['purchase_units'][0]['payee'] = array(
'merchant_id' => $merchantId
);
$orderData['application_context'] = array(
'user_action' => 'PAY_NOW',
'shipping_preference' => 'NO_SHIPPING',
);
return $orderData;
}
}