3
0

Compare commits

..

No commits in common. "release" and "payanyway.ocmod" have entirely different histories.

9 changed files with 144 additions and 341 deletions

View File

@ -4,7 +4,7 @@
![PHP](https://img.shields.io/badge/PHP-5.6%2B-purple) ![PHP](https://img.shields.io/badge/PHP-5.6%2B-purple)
![License](https://img.shields.io/badge/License-MIT-green) ![License](https://img.shields.io/badge/License-MIT-green)
> **📦 Версия модуля: 1.0.3** > **📦 Версия модуля: 1.0.0**
> ** Совместимость версий OpenCart:** > ** Совместимость версий OpenCart:**
> 3.0.0.0, 3.0.1.1, 3.0.1.2, 3.0.2.0, 3.0.3.0, 3.0.3.1, 3.0.3.2, 3.0.3.3, 3.0.3.4, 3.0.3.5, 3.0.3.6, 3.0.3.7, 3.0.3.8, 3.0.3.9, 3.0.4.0, 3.0.4.1, 3.0.5.0 > 3.0.0.0, 3.0.1.1, 3.0.1.2, 3.0.2.0, 3.0.3.0, 3.0.3.1, 3.0.3.2, 3.0.3.3, 3.0.3.4, 3.0.3.5, 3.0.3.6, 3.0.3.7, 3.0.3.8, 3.0.3.9, 3.0.4.0, 3.0.4.1, 3.0.5.0
@ -76,7 +76,7 @@
| **Тестовый режим** | `Нет` | | **Тестовый режим** | `Нет` |
| **Check URL** | `https://your_site_name/index.php?route=extension/payment/payanyway/callback` | | **Check URL** | `https://your_site_name/index.php?route=extension/payment/payanyway/callback` |
| **Pay URL** | `https://your_site_name/index.php?route=extension/payment/payanyway/callback` | | **Pay URL** | `https://your_site_name/index.php?route=extension/payment/payanyway/callback` |
| **HTTP method** | `GET` | | **HTTP method** | `GET` / `POST` |
| **Можно переопределять настройки в URL** | `Да` | | **Можно переопределять настройки в URL** | `Да` |
| **Подпись формы оплаты обязательна** | `Да` | | **Подпись формы оплаты обязательна** | `Да` |
| **Код проверки целостности данных** | аш_код` (произвольный набор символов) | | **Код проверки целостности данных** | аш_код` (произвольный набор символов) |

View File

@ -2,7 +2,7 @@
<modification> <modification>
<name>PayAnyWay</name> <name>PayAnyWay</name>
<code>payanyway</code> <code>payanyway</code>
<version>1.0.3</version> <version>1.0.0</version>
<author>PayAnyWay</author> <author>PayAnyWay</author>
<link>https://payanyway.ru/</link> <link>https://payanyway.ru/</link>
</modification> </modification>

View File

@ -9,7 +9,7 @@
class ControllerExtensionPaymentPayanyway extends Controller { class ControllerExtensionPaymentPayanyway extends Controller {
const CMS_NAME = 'OpenCart'; const CMS_NAME = 'OpenCart';
const MODULE_NAME = 'payanyway'; const MODULE_NAME = 'payanyway';
const MODULE_VERSION = '1.0.3'; const MODULE_VERSION = '1.0.0';
const MODULE_DEFAULT_SORT_ORDER = 0; const MODULE_DEFAULT_SORT_ORDER = 0;
private $supportedCurrencies = array('RUB'); private $supportedCurrencies = array('RUB');
@ -289,10 +289,9 @@ class ControllerExtensionPaymentPayanyway extends Controller {
$cmsName = $this->detectCmsByPatterns($textFooter); $cmsName = $this->detectCmsByPatterns($textFooter);
$cmsVersion = defined('VERSION') ? constant('VERSION') : '.unknown'; $cmsVersion = defined('VERSION') ? constant('VERSION') : '.unknown';
return sprintf('%s v%s|PHP %s|%s v%s', return sprintf('%s v%s | %s v%s',
$cmsName, $cmsName,
$cmsVersion, $cmsVersion,
PHP_VERSION,
self::MODULE_NAME, self::MODULE_NAME,
self::MODULE_VERSION self::MODULE_VERSION
); );

BIN
upload/admin/view/image/payment/payanyway.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 150 KiB

View File

@ -27,7 +27,7 @@
</div> </div>
<div class="panel-heading text-center"> <div class="panel-heading text-center">
<a href="https://www.payanyway.ru/" target="_blank"> <a href="https://www.payanyway.ru/" target="_blank">
<img src="view/image/payment/payanyway.png" alt="PayAnyWay" title="PayAnyWay" width="336" height="50"/> <img src="view/image/payment/payanyway.png" alt="PayAnyWay" title="PayAnyWay" width="250" height="29"/>
</a> </a>
</div> </div>
<div class="panel-body"> <div class="panel-body">

View File

@ -10,20 +10,13 @@ class ControllerExtensionPaymentPayanyway extends Controller {
const PAYMENT_URL_PROD = 'https://www.payanyway.ru/assistant.htm'; const PAYMENT_URL_PROD = 'https://www.payanyway.ru/assistant.htm';
const PAYMENT_URL_DEMO = 'https://demo.moneta.ru/assistant.htm'; const PAYMENT_URL_DEMO = 'https://demo.moneta.ru/assistant.htm';
const FAIL_RESPONSE = 'FAIL';
const XML_CONTENT_TYPE = 'application/xml';
const JSON_CONTENT_TYPE = 'application/json';
const TEXT_CONTENT_TYPE = 'text/plain; charset=UTF-8';
const TRANSACTION_ID_STRING_DELIMITER = '|'; const TRANSACTION_ID_STRING_DELIMITER = '|';
const DESCRIPTION_MAX_LENGTH = 500; const DESCRIPTION_MAX_LENGTH = 500;
const CLIENT_NAME_MAX_LENGTH = 256; const INVENTORY_ITEM_NAME_MAX_LENGTH = 128;
const ITEM_NAME_MAX_LENGTH = 128; const INVENTORY_ITEM_DEFAULT_PAYMENT_METHOD = 'full_payment';
const DEFAULT_PAYMENT_METHOD = 'full_payment'; const INVENTORY_ITEM_DEFAULT_PAYMENT_OBJECT = 'commodity';
const DEFAULT_PAYMENT_OBJECT = 'commodity'; const INVENTORY_ITEM_DEFAULT_MEASURE = 'unit';
const SHIPPING_PAYMENT_OBJECT = 'service';
const DEFAULT_MEASURE = 'unit';
/** @var int */ /** @var int */
private $mntId; private $mntId;
@ -98,15 +91,14 @@ class ControllerExtensionPaymentPayanyway extends Controller {
$this->integrityCode $this->integrityCode
); );
$data['MNT_SIGNATURE'] = $signature; $data['MNT_SIGNATURE'] = $signature;
$data['MNT_SUCCESS_URL'] = $this->url->link('extension/payment/payanyway/success', '', true); $data['MNT_SUCCESS_URL'] = $this->url->link('extension/payment/payanyway/success', 'language=' . $this->config->get('config_language'), true);
$data['MNT_FAIL_URL'] = $this->url->link('extension/payment/payanyway/fail', '', true); $data['MNT_FAIL_URL'] = $this->url->link('extension/payment/payanyway/fail', 'language=' . $this->config->get('config_language'), true);
$data['MNT_RETURN_URL'] = $this->url->link('checkout/checkout', '', true); $data['MNT_RETURN_URL'] = $this->url->link('checkout/checkout', 'language=' . $this->config->get('config_language'), true);
$data['moneta_locale'] = $this->language->get('text_locale');
$data['MNT_CMS'] = $this->cmsModuleVersion; $data['MNT_CMS'] = $this->cmsModuleVersion;
$data['btn_confirm'] = $this->language->get('text_paw_pay'); $data['btn_confirm'] = $this->language->get('text_paw_pay');
$data['confirm_url'] = $this->url->link('extension/payment/payanyway/confirm', '', true); $data['confirm_url'] = $this->url->link('extension/payment/payanyway/confirm', 'language=' . $this->config->get('config_language'), true);
return $this->load->view('extension/payment/payanyway', $data); return $this->load->view('extension/payment/payanyway', $data);
} }
@ -133,11 +125,7 @@ class ControllerExtensionPaymentPayanyway extends Controller {
*/ */
public function success() { public function success() {
$this->load->language('extension/payment/payanyway'); $this->load->language('extension/payment/payanyway');
$orderStatusId = isset($this->orderInfo['order_status_id']) ? (int)$this->orderInfo['order_status_id'] : null;
if ((null !== $orderStatusId) && ($orderStatusId !== $this->successOrderStatusId)) {
$this->addOrderHistory($this->pendingOrderStatusId, $this->language->get('text_payment_processing')); $this->addOrderHistory($this->pendingOrderStatusId, $this->language->get('text_payment_processing'));
}
$this->response->redirect($this->url->link('checkout/success', '', true)); $this->response->redirect($this->url->link('checkout/success', '', true));
} }
@ -178,7 +166,7 @@ class ControllerExtensionPaymentPayanyway extends Controller {
/** @return string */ /** @return string */
private function createTransactionId() { private function createTransactionId() {
$date = date('YmdHis'); $date = (new \DateTimeImmutable())->format('YmdHis');
return $this->orderId . self::TRANSACTION_ID_STRING_DELIMITER . $date; return $this->orderId . self::TRANSACTION_ID_STRING_DELIMITER . $date;
} }
@ -192,11 +180,14 @@ class ControllerExtensionPaymentPayanyway extends Controller {
/** @return string */ /** @return string */
private function getDescription() { private function getDescription() {
$clientFirstName = isset($this->orderInfo['firstname']) ? $this->orderInfo['firstname'] : '';
$clientLastName = isset($this->orderInfo['lastname']) ? $this->orderInfo['lastname'] : '';
$clientName = trim($clientFirstName . ' ' . $clientLastName);
$orderId = isset($this->orderInfo['order_id']) ? $this->orderInfo['order_id'] : null; $orderId = isset($this->orderInfo['order_id']) ? $this->orderInfo['order_id'] : null;
$description = "Оплата заказа" . (!empty($orderId) ? "{$orderId}" : ''); $description = "Оплата заказа" . (!empty($orderId) ? "{$orderId}" : '');
$clientName = $this->getClientName(); if ('' !== $clientName) {
if (null !== $clientName) {
$description .= " от {$clientName}"; $description .= " от {$clientName}";
} }
@ -239,14 +230,16 @@ class ControllerExtensionPaymentPayanyway extends Controller {
/** @return string */ /** @return string */
private function getSubscriberId() { private function getSubscriberId() {
$email = $this->getClientEmail(); $email = isset($this->orderInfo['email'])
if (null !== $email) { ? filter_var($this->orderInfo['email'], FILTER_SANITIZE_EMAIL)
: '';
if ('' !== $email) {
return $email; return $email;
} }
$phone = $this->getClientPhone(); return isset($this->orderInfo['telephone'])
? preg_replace('/[^0-9+]/', '', $this->orderInfo['telephone'])
return (null !== $phone) ? $phone : ''; : '';
} }
/** /**
@ -265,14 +258,19 @@ class ControllerExtensionPaymentPayanyway extends Controller {
* @throws \Exception * @throws \Exception
*/ */
public function callback() { public function callback() {
if (null === $this->orderId) {
$this->sendResponse('FAIL');
}
if (false === $this->orderInfo) {
$this->sendResponse('FAIL');
}
$requestData = ($_SERVER['REQUEST_METHOD'] === 'POST') ? $_POST : $_GET; $requestData = ($_SERVER['REQUEST_METHOD'] === 'POST') ? $_POST : $_GET;
$callback = $this->getCallbackData($requestData); $callbackData = $this->getCallbackData($requestData);
$this->validateCallback($callback); (isset($callbackData['MNT_COMMAND'])) && ('CHECK' === $callbackData['MNT_COMMAND'])
? $this->handleCheckCallback($callbackData)
(isset($callback['MNT_COMMAND'])) && ('CHECK' === $callback['MNT_COMMAND']) : $this->handlePayCallback($callbackData);
? $this->handleCheckCallback($callback)
: $this->handlePayCallback($callback);
} }
/** /**
@ -298,7 +296,7 @@ class ControllerExtensionPaymentPayanyway extends Controller {
if (!isset($_REQUEST['MNT_TRANSACTION_ID'])) { if (!isset($_REQUEST['MNT_TRANSACTION_ID'])) {
return null; return null;
} }
$transactionIdData = explode(self::TRANSACTION_ID_STRING_DELIMITER, $_REQUEST['MNT_TRANSACTION_ID'], 2); $transactionIdData = explode(self::TRANSACTION_ID_STRING_DELIMITER, $_REQUEST['MNT_TRANSACTION_ID']);
return isset($transactionIdData[0]) ? (int)$transactionIdData[0] : null; return isset($transactionIdData[0]) ? (int)$transactionIdData[0] : null;
} }
@ -309,46 +307,23 @@ class ControllerExtensionPaymentPayanyway extends Controller {
} }
/** /**
* @param array|string $response * @param string $response
* @param int $statusCode * @param int $statusCode
* @return void * @return void
*/ */
private function sendResponse($response, $statusCode = 200) private function sendResponse($response, $statusCode = 200) {
{
http_response_code($statusCode); http_response_code($statusCode);
if (is_string($response)) {
header('Content-Type: ' . self::TEXT_CONTENT_TYPE); if (strpos($response, '<?xml') === 0 || strpos($response, '<MNT_RESPONSE') !== false) {
echo $response; header('Content-Type: application/xml');
} else { } else {
header('Content-Type: ' . $response['contentType']); header('Content-Type: text/plain; charset=UTF-8');
echo $response['data'];
} }
echo $response;
exit(); exit();
} }
/**
* @param array $callback
* @return void
*/
private function validateCallback(array $callback)
{
if (null === $this->orderId) {
$this->sendResponse(self::FAIL_RESPONSE);
}
if (false === $this->orderInfo) {
$this->sendResponse(self::FAIL_RESPONSE);
}
if (empty($this->mntId) || empty($this->integrityCode)) {
$this->sendResponse(self::FAIL_RESPONSE);
}
if ($this->mntId !== (int)$callback['MNT_ID']) {
$this->sendResponse(self::FAIL_RESPONSE);
}
}
/** /**
* @param array<string, mixed> $data * @param array<string, mixed> $data
* @return bool * @return bool
@ -368,7 +343,7 @@ class ControllerExtensionPaymentPayanyway extends Controller {
? array_merge(['MNT_COMMAND'], $baseFields) ? array_merge(['MNT_COMMAND'], $baseFields)
: $baseFields; : $baseFields;
$signatureString = array_reduce($fields, function ($carry, $field) use ($data) { $signatureString = array_reduce($fields, static function ($carry, $field) use ($data) {
return $carry . $data[$field]; return $carry . $data[$field];
}, '') . $this->integrityCode; }, '') . $this->integrityCode;
@ -382,19 +357,62 @@ class ControllerExtensionPaymentPayanyway extends Controller {
*/ */
private function handleCheckCallback(array $callbackData) { private function handleCheckCallback(array $callbackData) {
if (!$this->checkSignature($callbackData, $callbackData['MNT_SIGNATURE'])) { if (!$this->checkSignature($callbackData, $callbackData['MNT_SIGNATURE'])) {
$this->sendResponse(self::FAIL_RESPONSE); $this->sendResponse('FAIL');
} }
list($resultCode, $description) = $this->determineCheckResult($callbackData); $this->load->model('account/order');
$responseData = $this->buildBaseResponseData($callbackData, $resultCode, $description); $products = $this->model_account_order->getOrderProducts($this->orderId);
$deliveryPrice = $this->getDeliveryPrice();
$products = $this->getAccountOrderProducts(); $orderTotal = (float)(isset($this->orderInfo['total']) ? $this->orderInfo['total'] : 0);
$deliveryInfo = $this->getDeliveryInfo();
$responseData['client'] = $this->getClientInfo(); $xmlData = array(
$responseData['items'] = $this->getCheckItems($products, $deliveryInfo); 'MNT_ID' => $this->mntId,
'MNT_TRANSACTION_ID' => $callbackData['MNT_TRANSACTION_ID'],
'MNT_AMOUNT' => $this->formatPrice($orderTotal),
'MNT_CURRENCY_CODE' => $callbackData['MNT_CURRENCY_CODE'],
'inventory' => $this->getInventoryJson($products) ?: null,
'client' => $callbackData['MNT_SUBSCRIBER_ID'],
'sno' => null,
'delivery' => (null !== $deliveryPrice) ? $this->formatPrice($deliveryPrice) : null,
);
$this->sendResponse($this->buildJsonResponse($responseData)); $orderStatusId = (int)(isset($this->orderInfo['order_status_id']) ? $this->orderInfo['order_status_id'] : 1);
list($xmlData['MNT_RESULT_CODE'], $xmlData['MNT_DESCRIPTION']) = $this->determineCheckResult($callbackData, $orderStatusId);
$xmlData['MNT_SIGNATURE'] = md5(
$xmlData['MNT_RESULT_CODE'] .
$xmlData['MNT_ID'] .
$xmlData['MNT_TRANSACTION_ID'] .
$this->integrityCode
);
$this->sendResponse($this->buildXMLResponse($xmlData));
}
/**
* @param array<string, mixed> $callbackData
* @param int $orderStatusId
* @return array
* @throws \Exception
*/
private function determineCheckResult(array $callbackData, $orderStatusId) {
$orderStatus = $this->getOrderStatusById($orderStatusId);
if (empty($callbackData['MNT_AMOUNT'])) {
return array(100, "Order status is '{$orderStatus}'");
}
if ($this->successOrderStatusId === $orderStatusId) {
return array(200, 'Order Paid');
}
if (in_array($orderStatusId, array(7, 9, 16), true)) {
return array(500, "Order status is '{$orderStatus}'");
}
return array(402, 'Order created, but not paid');
} }
/** /**
@ -404,6 +422,7 @@ class ControllerExtensionPaymentPayanyway extends Controller {
*/ */
private function handlePayCallback(array $callbackData) { private function handlePayCallback(array $callbackData) {
$orderTotal = (float)(isset($this->orderInfo['total']) ? $this->orderInfo['total'] : 0); $orderTotal = (float)(isset($this->orderInfo['total']) ? $this->orderInfo['total'] : 0);
$currencyCode = isset($this->orderInfo['currency_code']) ? $this->orderInfo['currency_code'] : 'RUB'; $currencyCode = isset($this->orderInfo['currency_code']) ? $this->orderInfo['currency_code'] : 'RUB';
$shopData = array( $shopData = array(
'MNT_ID' => $this->mntId, 'MNT_ID' => $this->mntId,
@ -416,82 +435,37 @@ class ControllerExtensionPaymentPayanyway extends Controller {
); );
if (!$this->checkSignature($shopData, $callbackData['MNT_SIGNATURE'])) { if (!$this->checkSignature($shopData, $callbackData['MNT_SIGNATURE'])) {
$this->sendResponse(self::FAIL_RESPONSE); $this->sendResponse('FAIL');
} }
$isPayedOrder = $this->isOrderPaid(); $isPayedOrder = $this->isOrderPaid();
$resultCode = 200;
$this->load->model('account/order');
$products = $this->model_account_order->getOrderProducts($this->orderId);
$deliveryPrice = $this->getDeliveryPrice();
$xmlData = array(
'MNT_ID' => $this->mntId,
'MNT_TRANSACTION_ID' => $callbackData['MNT_TRANSACTION_ID'],
'MNT_RESULT_CODE' => $resultCode,
'MNT_SIGNATURE' => md5($resultCode . $this->mntId . $callbackData['MNT_TRANSACTION_ID'] . $this->integrityCode),
'MNT_AMOUNT' => $callbackData['MNT_AMOUNT'],
'MNT_CURRENCY_CODE' => $callbackData['MNT_CURRENCY_CODE'],
'MNT_DESCRIPTION' => $isPayedOrder ? 'Order already paid' : 'Order success paid',
'inventory' => $this->getInventoryJson($products),
'client' => $callbackData['MNT_SUBSCRIBER_ID'],
'sno' => null,
'delivery' => $deliveryPrice !== null ? $this->formatPrice($deliveryPrice) : null,
);
if (!$isPayedOrder) { if (!$isPayedOrder) {
$this->load->language('extension/payment/payanyway'); $this->load->language('extension/payment/payanyway');
$this->addOrderHistory($this->successOrderStatusId, $this->language->get('text_payment_completed')); $this->addOrderHistory($this->successOrderStatusId, $this->language->get('text_payment_completed'));
} }
$resultCode = 200; $this->sendResponse($this->buildXMLResponse($xmlData));
$description = $isPayedOrder ? 'Order already paid' : 'Order success paid';
$responseData = $this->buildBaseResponseData($callbackData, $resultCode, $description);
$products = $this->getAccountOrderProducts();
$deliveryInfo = $this->getDeliveryInfo();
$payInventoryJson = $this->getPayInventoryJson($products, $deliveryInfo);
$responseData['inventory'] = $payInventoryJson ?: null;
$clientInfo = $this->getClientInfo();
$responseData['client'] = $clientInfo
? json_encode([$clientInfo], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
: null;
$this->sendResponse($this->buildXmlResponse($responseData));
}
/**
* @param array $callbackData
* @param int $resultCode
* @param string $description
* @return array<string, mixed>
* @throws \Exception
*/
private function buildBaseResponseData(array $callbackData, $resultCode, $description) {
$orderTotal = (float)(isset($this->orderInfo['total']) ? $this->orderInfo['total'] : 0);
$data = array(
'MNT_ID' => $this->mntId,
'MNT_TRANSACTION_ID' => $callbackData['MNT_TRANSACTION_ID'],
'MNT_RESULT_CODE' => $resultCode,
'MNT_DESCRIPTION' => $this->validateString($description, self::DESCRIPTION_MAX_LENGTH),
'MNT_AMOUNT' => $this->formatPrice($orderTotal),
'MNT_CURRENCY_CODE' => $callbackData['MNT_CURRENCY_CODE'],
);
$signatureSource = $resultCode . $this->mntId . $callbackData['MNT_TRANSACTION_ID'] . $this->integrityCode;
$data['MNT_SIGNATURE'] = md5($signatureSource);
return $data;
}
/**
* @param array<string, mixed> $callbackData
* @return array<int|string>
* @throws \Exception
*/
private function determineCheckResult(array $callbackData) {
$orderStatusId = isset($this->orderInfo['order_status_id']) ? (int)$this->orderInfo['order_status_id'] : null;
if (null === $orderStatusId) {
return array(500, 'Order status not set');
}
$orderStatus = $this->getOrderStatusById($orderStatusId);
if (empty($callbackData['MNT_AMOUNT'])) {
return array(100, "Order status is {$orderStatus}");
}
if ($this->successOrderStatusId === $orderStatusId) {
return array(200, 'Order Paid');
}
if (in_array($orderStatusId, array(7, 9, 16), true)) {
return array(500, "Order status is {$orderStatus}");
}
return array(402, 'Order created, but not paid');
} }
/** @return bool */ /** @return bool */
@ -504,14 +478,15 @@ class ControllerExtensionPaymentPayanyway extends Controller {
} }
/** /**
* @return array * @return float|null
* @throws \Exception * @throws \Exception
*/ */
private function getDeliveryInfo() { private function getDeliveryPrice() {
$this->load->model('account/order'); $this->load->model('account/order');
foreach ($this->model_account_order->getOrderTotals($this->orderId) as $orderTotal) { foreach ($this->model_account_order->getOrderTotals($this->orderId) as $orderTotal) {
if (isset($orderTotal['code']) && ($orderTotal['code'] === 'shipping')) { if (isset($orderTotal['code']) && ($orderTotal['code'] === 'shipping')) {
return $orderTotal; $deliveryPrice = isset($orderTotal['value']) ? (float)$orderTotal['value'] : 0;
return ($deliveryPrice !== 0.0) ? $deliveryPrice : null;
} }
} }
@ -520,125 +495,29 @@ class ControllerExtensionPaymentPayanyway extends Controller {
/** /**
* @param array<string, mixed> $products * @param array<string, mixed> $products
* @param array<string, mixed> $deliveryInfo
* @return false|string * @return false|string
*/ */
private function getPayInventoryJson(array $products, array $deliveryInfo) { private function getInventoryJson(array $products) {
if (empty($products) && empty($deliveryInfo)) {
return false;
}
$inventory = array(); $inventory = array();
foreach ($products as $product) { foreach ($products as $product) {
$name = isset($product['name']) ? $product['name'] : ''; $name = isset($product['name']) ? $product['name'] : '';
$price = isset($product['price']) ? (float)$product['price'] : 0; $price = isset($product['price']) ? (float)$product['price'] : 0;
$quantity = isset($product['quantity']) ? (float)$product['quantity'] : 0; $quantity = isset($product['quantity']) ? (string)$product['quantity'] : '0';
$inventory[] = array( $inventory[] = array(
'name' => $this->validateString($name, self::ITEM_NAME_MAX_LENGTH), 'name' => $this->validateString($name, self::INVENTORY_ITEM_NAME_MAX_LENGTH),
'price' => $this->formatPrice($price), 'price' => $this->formatPrice($price),
'quantity' => $this->formatQuantity($quantity), 'quantity' => $this->formatQuantity($quantity),
'vatTag' => $this->vatRate, 'vatTag' => $this->vatRate,
'pm' => self::DEFAULT_PAYMENT_METHOD, 'pm' => self::INVENTORY_ITEM_DEFAULT_PAYMENT_METHOD,
'po' => self::DEFAULT_PAYMENT_OBJECT, 'po' => self::INVENTORY_ITEM_DEFAULT_PAYMENT_OBJECT,
'measure' => self::DEFAULT_MEASURE, 'measure' => self::INVENTORY_ITEM_DEFAULT_MEASURE,
); );
} }
$name = isset($deliveryInfo['title']) ? $deliveryInfo['title'] : '';
$price = isset($deliveryInfo['value']) ? (float)$deliveryInfo['value'] : 0;
$inventory[] = array(
'name' => $this->validateString($name, self::ITEM_NAME_MAX_LENGTH),
'price' => $this->formatPrice($price),
'quantity' => '1',
'vatTag' => $this->vatRate,
'pm' => self::DEFAULT_PAYMENT_METHOD,
'po' => self::SHIPPING_PAYMENT_OBJECT,
'measure' => self::DEFAULT_MEASURE,
);
return json_encode($inventory, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); return json_encode($inventory, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
} }
/** @return array */
private function getClientInfo() {
$clientInfo = array();
$name = $this->getClientName();
if (null !== $name) {
$clientInfo['name'] = $name;
}
$email = $this->getClientEmail();
if (null !== $email) {
$clientInfo['email'] = $email;
}
$phoneNumber = $this->getClientPhone();
if (null !== $phoneNumber) {
$clientInfo['phone'] = $phoneNumber;
}
return $clientInfo;
}
/**
* @param array<string, mixed> $products
* @param array<string, mixed> $deliveryInfo
* @return non-empty-array
*/
private function getCheckItems(array $products, array $deliveryInfo) {
$checkItems = array();
foreach ($products as $product) {
$name = isset($product['name']) ? $product['name'] : '';
$price = isset($product['price']) ? (float)$product['price'] : 0;
$quantity = isset($product['quantity']) ? (float)$product['quantity'] : 0;
$checkItems[] = array(
'name' => $this->validateString($name, self::ITEM_NAME_MAX_LENGTH),
'price' => $this->formatPrice($price),
'quantity' => $quantity,
'vat' => $this->getVat($this->vatRate),
'measure' => self::DEFAULT_MEASURE,
'paymentMethod' => self::DEFAULT_PAYMENT_METHOD,
'paymentObject' => self::DEFAULT_PAYMENT_OBJECT,
);
}
$name = isset($deliveryInfo['title']) ? $deliveryInfo['title'] : '';
$price = isset($deliveryInfo['value']) ? (float)$deliveryInfo['value'] : 0;
$checkItems[] = array(
'name' => $this->validateString($name, self::ITEM_NAME_MAX_LENGTH),
'price' => $this->formatPrice($price),
'quantity' => 1,
'vat' => $this->getVat($this->vatRate),
'measure' => self::DEFAULT_MEASURE,
'paymentMethod' => self::DEFAULT_PAYMENT_METHOD,
'paymentObject' => self::SHIPPING_PAYMENT_OBJECT,
);
return $checkItems;
}
/**
* @param string $vatRate
* @return string
*/
public function getVat($vatRate) {
$map = array(
'1104' => 'vat0',
'1108' => 'vat5',
'1109' => 'vat7',
'1103' => 'vat10',
'7000' => 'vat20',
'1113' => 'vat22',
'1110' => 'vat105',
'1111' => 'vat107',
'1107' => 'vat110',
'7001' => 'vat120',
'1114' => 'vat122',
);
return isset($map[$vatRate]) ? $map[$vatRate] : 'none';
}
/** /**
* @param int $orderStatusId * @param int $orderStatusId
* @return string * @return string
@ -662,48 +541,25 @@ class ControllerExtensionPaymentPayanyway extends Controller {
} }
/** /**
* @param float $quantity * @param string $quantity
* @return string * @return string
*/ */
private function formatQuantity($quantity) { private function formatQuantity($quantity) {
$quantityString = number_format($quantity, 3, '.', ''); $quantity = str_replace(',', '.', $quantity);
return rtrim(rtrim($quantityString, '0'), '.'); if (strpos($quantity, '.') === false && ctype_digit($quantity)) {
return (string)(int)$quantity;
} }
/** return number_format((float)$quantity, 3, '.', '');
* @param array<non-empty-string, mixed> $data
* @return array
* @throws \JsonException
*/
public function buildJsonResponse(array $data) {
$jsonData = array(
'id' => $data['MNT_ID'],
'transactionId' => $data['MNT_TRANSACTION_ID'],
'amount' => $data['MNT_AMOUNT'],
'signature' => $data['MNT_SIGNATURE'],
'resultCode' => $data['MNT_RESULT_CODE'],
'description' => $data['MNT_DESCRIPTION'],
'externalId' => $data['MNT_TRANSACTION_ID'],
'receipt' => array(
'client' => $data['client'],
'items' => $data['items'],
),
);
$json = json_encode($jsonData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
return array(
'data' => $json ?: '',
'contentType' => self::JSON_CONTENT_TYPE,
);
} }
/** /**
* @param array<string, mixed> $data * @param array<string, mixed> $data
* @return array * @return false|string
* @return bool|string
* @throws \Exception * @throws \Exception
*/ */
private function buildXmlResponse(array $data) { private function buildXMLResponse(array $data) {
$dom = new \DOMDocument('1.0', 'UTF-8'); $dom = new \DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = false; $dom->formatOutput = false;
@ -745,47 +601,7 @@ class ControllerExtensionPaymentPayanyway extends Controller {
} }
} }
$xml = $dom->saveXML(); return $dom->saveXML();
return array(
'data' => (false !== $xml) ? $xml : self::FAIL_RESPONSE,
'contentType' => (false !== $xml) ? self::XML_CONTENT_TYPE : self::TEXT_CONTENT_TYPE,
);
}
/**
* @return non-empty-string|null
*/
private function getClientName()
{
$firstname = isset($this->orderInfo['firstname']) ? $this->orderInfo['firstname'] : '';
$lastname = isset($this->orderInfo['lastname']) ? $this->orderInfo['lastname'] : '';
$name = trim($firstname . ' ' . $lastname);
return ('' !== $name) ? $this->validateString($name, self::CLIENT_NAME_MAX_LENGTH) : null;
}
/**
* @return non-empty-string|null
*/
private function getClientEmail()
{
$email = isset($this->orderInfo['email']) ? $this->orderInfo['email'] : '';
$email = trim((string)$email);
return ('' !== $email) ? filter_var($email, FILTER_SANITIZE_EMAIL) : null;
}
/**
* @return non-empty-string|null
*/
private function getClientPhone()
{
$telephone = isset($this->orderInfo['telephone']) ? $this->orderInfo['telephone'] : '';
$digits = preg_replace('/\D/', '', trim((string)$telephone));
return ('' !== $digits) ? '+' . $digits : null;
} }
/** /**
@ -853,13 +669,4 @@ class ControllerExtensionPaymentPayanyway extends Controller {
$this->errorOrderStatusId = (int)$this->config->get('payment_payanyway_error_order_status_id'); $this->errorOrderStatusId = (int)$this->config->get('payment_payanyway_error_order_status_id');
$this->cmsModuleVersion = (string)$this->config->get('payment_payanyway_cms_module_version'); $this->cmsModuleVersion = (string)$this->config->get('payment_payanyway_cms_module_version');
} }
/**
* @return array
* @throws \Exception
*/
public function getAccountOrderProducts() {
$this->load->model('account/order');
return $this->model_account_order->getOrderProducts($this->orderId);
}
} }

View File

@ -1,6 +1,5 @@
<?php <?php
// Text // Text
$_['text_locale'] = 'en';
$_['text_title'] = 'PayAnyWay (MIR, VISA, MasterCard and 30+ other ways)'; $_['text_title'] = 'PayAnyWay (MIR, VISA, MasterCard and 30+ other ways)';
$_['text_ap_pay_with'] = 'Pay with'; $_['text_ap_pay_with'] = 'Pay with';
$_['text_ap_and_other'] = 'or another payment method'; $_['text_ap_and_other'] = 'or another payment method';

View File

@ -1,6 +1,5 @@
<?php <?php
// Text // Text
$_['text_locale'] = 'ru';
$_['text_title'] = 'PayAnyWay (МИР, Visa, MasterCard и более 30-и способов оплаты)'; $_['text_title'] = 'PayAnyWay (МИР, Visa, MasterCard и более 30-и способов оплаты)';
$_['text_ap_pay_with'] = 'Оплатить с'; $_['text_ap_pay_with'] = 'Оплатить с';
$_['text_ap_and_other'] = 'или другой способ оплаты'; $_['text_ap_and_other'] = 'или другой способ оплаты';

View File

@ -10,7 +10,6 @@
<input type="hidden" name="MNT_SUCCESS_URL" value="{{ MNT_SUCCESS_URL }}"/> <input type="hidden" name="MNT_SUCCESS_URL" value="{{ MNT_SUCCESS_URL }}"/>
<input type="hidden" name="MNT_FAIL_URL" value="{{ MNT_FAIL_URL }}"/> <input type="hidden" name="MNT_FAIL_URL" value="{{ MNT_FAIL_URL }}"/>
<input type="hidden" name="MNT_RETURN_URL" value="{{ MNT_RETURN_URL }}"/> <input type="hidden" name="MNT_RETURN_URL" value="{{ MNT_RETURN_URL }}"/>
<input type="hidden" name="moneta.locale" value="{{ moneta_locale }}"/>
<input type="hidden" name="MNT_CMS" value="{{ MNT_CMS }}"/> <input type="hidden" name="MNT_CMS" value="{{ MNT_CMS }}"/>
<div class="buttons"> <div class="buttons">
<div class="{% if ap_use %} text-center {% else %} pull-right {% endif %}"> <div class="{% if ap_use %} text-center {% else %} pull-right {% endif %}">