update
This commit is contained in:
@@ -3,11 +3,14 @@
|
||||
* Class Przelewy24ServiceRefund
|
||||
*
|
||||
* This service has the features required for cash returns.
|
||||
*
|
||||
* @author Przelewy24
|
||||
* @copyright Przelewy24
|
||||
* @license https://www.gnu.org/licenses/lgpl-3.0.en.html
|
||||
*
|
||||
*/
|
||||
if (!defined('_PS_VERSION_')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Przelewy24ServiceRefund
|
||||
@@ -22,23 +25,23 @@ class Przelewy24ServiceRefund extends Przelewy24Service
|
||||
private $suffix = '';
|
||||
|
||||
/**
|
||||
* P24 soap api client.
|
||||
* P24 REST api client.
|
||||
*
|
||||
* @var SoapClient
|
||||
* @var Przelewy24RestRefund
|
||||
*/
|
||||
private $soap;
|
||||
private $restApi;
|
||||
|
||||
/**
|
||||
* Array of allowed refund statuses.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $status = array(
|
||||
private $status = [
|
||||
0 => 'Refund error',
|
||||
1 => 'Refund done',
|
||||
3 => 'Awaiting for refund',
|
||||
4 => 'Refund rejected',
|
||||
);
|
||||
];
|
||||
|
||||
/**
|
||||
* Default refund status.
|
||||
@@ -50,14 +53,14 @@ class Przelewy24ServiceRefund extends Przelewy24Service
|
||||
/**
|
||||
* Przelewy24ServiceRefund constructor.
|
||||
*
|
||||
* @param Przelewy24 $przelewy24
|
||||
* @param string $suffix
|
||||
* @param Przelewy24Soap $przelewy24Soap
|
||||
* @param Przelewy24 $przelewy24
|
||||
* @param string $suffix
|
||||
* @param Przelewy24RestRefund $restApi
|
||||
*/
|
||||
public function __construct(Przelewy24 $przelewy24, $suffix, $przelewy24Soap)
|
||||
public function __construct(Przelewy24 $przelewy24, $suffix, $restApi)
|
||||
{
|
||||
$this->setSuffix($suffix);
|
||||
$this->soap = $przelewy24Soap->getSoapClient();
|
||||
$this->restApi = $restApi;
|
||||
parent::__construct($przelewy24);
|
||||
}
|
||||
|
||||
@@ -71,61 +74,16 @@ class Przelewy24ServiceRefund extends Przelewy24Service
|
||||
$this->suffix = $suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get refunds.
|
||||
*
|
||||
* @param int $orderId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRefunds($orderId)
|
||||
{
|
||||
$return = array();
|
||||
try {
|
||||
$soap = $this->soap;
|
||||
$result = $soap->GetRefundInfo(
|
||||
Configuration::get('P24_MERCHANT_ID' . $this->suffix),
|
||||
Configuration::get('P24_API_KEY' . $this->suffix),
|
||||
$orderId
|
||||
);
|
||||
|
||||
if ($result && is_array($result->result)) {
|
||||
$maxToRefund = 0;
|
||||
$refunds = array();
|
||||
foreach ($result->result as $key => $value) {
|
||||
$refunds[$key]['amount_refunded'] = $value->amount;
|
||||
$date = new DateTime($value->date);
|
||||
$refunds[$key]['created'] = $date->format('Y-m-d H:i:s');
|
||||
$refunds[$key]['status'] = $this->getStatusMessage($value->status);
|
||||
|
||||
if ((1 === $value->status) || (3 === $value->status)) {
|
||||
$maxToRefund += $value->amount;
|
||||
}
|
||||
}
|
||||
$return = array(
|
||||
'maxToRefund' => $maxToRefund,
|
||||
'refunds' => $refunds,
|
||||
);
|
||||
}
|
||||
|
||||
return $return;
|
||||
} catch (Exception $e) {
|
||||
PrestaShopLogger::addLog(__METHOD__ . ' ' . $e->getMessage(), 1);
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status message.
|
||||
*
|
||||
* @param integer $status
|
||||
* @param int $status
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getStatusMessage($status)
|
||||
{
|
||||
$status = (int)$status;
|
||||
$status = (int) $status;
|
||||
$return = $this->statusDefault;
|
||||
if (isset($this->status[$status])) {
|
||||
$return = $this->status[$status];
|
||||
@@ -134,62 +92,52 @@ class Przelewy24ServiceRefund extends Przelewy24Service
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if refund is possible and returns data to refund.
|
||||
*
|
||||
* @param int $orderId
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws PrestaShopDatabaseException
|
||||
*/
|
||||
public function checkIfRefundIsPossibleAndReturnDataToRefund($orderId)
|
||||
private function extractDate($input)
|
||||
{
|
||||
$return = array();
|
||||
$dataFromDB = $this->getRefundDataFromDB($orderId);
|
||||
if ($dataFromDB) {
|
||||
$dataFromP24 = $this->checkIfPaymentCompletedUsingWSAndReturnData($dataFromDB['sessionId']);
|
||||
if ($dataFromP24) {
|
||||
$return = array(
|
||||
'sessionId' => $dataFromDB['sessionId'],
|
||||
'amount' => isset($dataFromP24->result->amount) ? (int)$dataFromP24->result->amount : 0,
|
||||
'p24OrderId' => isset($dataFromP24->result->orderId) ? (int)$dataFromP24->result->orderId : 0,
|
||||
);
|
||||
}
|
||||
$rx = '/^(?P<Y>\\d{4})(?P<m>\\d{2})(?P<d>\\d{2})/';
|
||||
if (preg_match($rx, $input, $m)) {
|
||||
return $m['Y'] . '-' . $m['m'] . '-' . $m['d'];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if payment is completed using ws and return data.
|
||||
* Get refund data from Przelewy24.
|
||||
*
|
||||
* @param $sessionId
|
||||
* @param array $refundDataFromDb
|
||||
*
|
||||
* @return bool
|
||||
* @return array
|
||||
*/
|
||||
public function checkIfPaymentCompletedUsingWSAndReturnData($sessionId)
|
||||
public function getDataToRefund(array $refundDataFromDb)
|
||||
{
|
||||
try {
|
||||
$soap = $this->soap;
|
||||
$result = $soap->GetTransactionBySessionId(
|
||||
Configuration::get('P24_MERCHANT_ID' . $this->suffix),
|
||||
Configuration::get('P24_API_KEY' . $this->suffix),
|
||||
$sessionId
|
||||
);
|
||||
|
||||
if (isset($result->error->errorCode, $result->result->status) &&
|
||||
(($result->error->errorCode > 0) || (2 !== (int)$result->result->status))
|
||||
) {
|
||||
return false;
|
||||
$return = [];
|
||||
$order = $this->restApi->transactionBySessionId($refundDataFromDb['sessionId']);
|
||||
$refunds = $this->restApi->refundByOrderId($refundDataFromDb['p24OrderId']);
|
||||
if (isset($order['data'])) {
|
||||
$return = [
|
||||
'sessionId' => (string) $order['data']['sessionId'],
|
||||
'p24OrderId' => (int) $order['data']['orderId'],
|
||||
'originalAmount' => (int) $order['data']['amount'],
|
||||
'amount' => null, /* Reserve field position. */
|
||||
'refunded' => 0,
|
||||
'refunds' => [],
|
||||
];
|
||||
if (isset($refunds['data'])) {
|
||||
foreach ($refunds['data']['refunds'] as $refund) {
|
||||
$amountRefunded = (int) $refund['amount'];
|
||||
$return['refunded'] += $amountRefunded;
|
||||
$return['refunds'][] = [
|
||||
'amount_refunded' => $amountRefunded,
|
||||
'created' => $this->extractDate($refund['date']),
|
||||
'status' => $this->status[$refund['status']],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
} catch (Exception $e) {
|
||||
PrestaShopLogger::addLog(__METHOD__ . ' ' . $e->getMessage(), 1);
|
||||
|
||||
return false;
|
||||
$return['amount'] = $return['originalAmount'] - $return['refunded'];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,16 +151,16 @@ class Przelewy24ServiceRefund extends Przelewy24Service
|
||||
*/
|
||||
public function getRefundDataFromDB($orderId)
|
||||
{
|
||||
$return = array();
|
||||
$return = [];
|
||||
|
||||
$orderId = (int)$orderId;
|
||||
$orderId = (int) $orderId;
|
||||
$przelewy24Order = new Przelewy24Order();
|
||||
$result = $przelewy24Order->getByPshopOrderId($orderId);
|
||||
if ($result) {
|
||||
$return = array(
|
||||
$return = [
|
||||
'sessionId' => $result->p24_session_id,
|
||||
'p24OrderId' => $result->p24_order_id,
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
return $return;
|
||||
@@ -223,93 +171,257 @@ class Przelewy24ServiceRefund extends Przelewy24Service
|
||||
*
|
||||
* @param string $sessionId
|
||||
* @param int $p24OrderId
|
||||
* @param float $amountToRefund
|
||||
* @param int $amountToRefund
|
||||
*
|
||||
* @return false|stdClass
|
||||
*/
|
||||
public function refundProcess($sessionId, $p24OrderId, $amountToRefund)
|
||||
{
|
||||
$refunds = array(
|
||||
array(
|
||||
'sessionId' => $sessionId,
|
||||
'orderId' => $p24OrderId,
|
||||
'amount' => $amountToRefund,
|
||||
),
|
||||
);
|
||||
$sessionId = (string) $sessionId;
|
||||
$p24OrderId = (int) $p24OrderId;
|
||||
$amountToRefund = (int) $amountToRefund;
|
||||
|
||||
try {
|
||||
return $this->soap->refundTransaction(
|
||||
Configuration::get('P24_MERCHANT_ID' . $this->suffix),
|
||||
Configuration::get('P24_API_KEY' . $this->suffix),
|
||||
time(),
|
||||
$refunds
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
PrestaShopLogger::addLog(__METHOD__ . ' ' . $e->getMessage(), 1);
|
||||
|
||||
return false;
|
||||
$response = $this->restApi->transactionRefund($p24OrderId, $sessionId, $amountToRefund);
|
||||
if (isset($response['data'][0])) {
|
||||
return $response['data'][0]['amount'] === $amountToRefund;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function checks the availability of the following functions :
|
||||
* GetTransactionBySessionId
|
||||
* RefundTransaction
|
||||
* Update products for a refund.
|
||||
*
|
||||
* @param Order $order A order
|
||||
* @param array $products List of products to refund
|
||||
* @return bool
|
||||
*/
|
||||
public function checkRefundFunction()
|
||||
public function updateProductsForRefund($order, $products)
|
||||
{
|
||||
try {
|
||||
return (
|
||||
$this->soapMethodExists('GetTransactionBySessionId') &&
|
||||
$this->soapMethodExists('RefundTransaction')
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
PrestaShopLogger::addLog(__METHOD__ . ' ' . $e->getMessage(), 1);
|
||||
|
||||
return false;
|
||||
$ok = true;
|
||||
if (Configuration::get('P24_REFUND_WITH_ALTER_STOCK')) {
|
||||
$ok &= $this->updateStock($order, $products);
|
||||
}
|
||||
$ok &= $this->addOrderSlip($order, $products);
|
||||
$ok &= $this->updateOrderDetails($order, $products);
|
||||
|
||||
return (bool) $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function checks the availability of the following functions :
|
||||
* GetRefundInfo
|
||||
* Update stock.
|
||||
*
|
||||
* @return bool
|
||||
* @param Order $order A order
|
||||
* @param array $products List of products to refund
|
||||
* @return float|null
|
||||
*/
|
||||
public function checkGetRefundInfo()
|
||||
private function updateStock($order, $products)
|
||||
{
|
||||
try {
|
||||
return ($this->soapMethodExists('GetRefundInfo'));
|
||||
} catch (Exception $e) {
|
||||
PrestaShopLogger::addLog(__METHOD__ . ' ' . $e->getMessage(), 1);
|
||||
$totalPrice = 0.0;
|
||||
$removed = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$orderProducts = $order->getProductsDetail();
|
||||
|
||||
foreach ($products as $productId => $quantity) {
|
||||
if (!$quantity) {
|
||||
continue;
|
||||
}
|
||||
foreach ($orderProducts as $orderProduct) {
|
||||
if ((int) $orderProduct['id_order_detail'] === (int) $productId) {
|
||||
$productObject = new Product($orderProduct['product_id']);
|
||||
$stock = new StockAvailable();
|
||||
$stock->updateQuantity(
|
||||
$orderProduct['product_id'],
|
||||
$orderProduct['product_attribute_id'],
|
||||
$quantity
|
||||
);
|
||||
$totalPrice += round($productObject->price * $quantity, 2);
|
||||
$totalPrice = round($totalPrice, 2);
|
||||
$removed = true;
|
||||
|
||||
/**
|
||||
* Checks if soap method exists.
|
||||
*
|
||||
* @param string $method
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function soapMethodExists($method)
|
||||
{
|
||||
$return = false;
|
||||
$list = $this->soap->__getFunctions();
|
||||
if (is_array($list)) {
|
||||
foreach ($list as $line) {
|
||||
$explodeLine = explode(' ', $line, 2);
|
||||
if (array_key_exists(1, $explodeLine) && (0 === strpos($explodeLine[1], $method))) {
|
||||
$return = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
if ($removed) {
|
||||
$order->update();
|
||||
return $totalPrice;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a order slip.
|
||||
*
|
||||
* @param Order $order A order
|
||||
* @param array $products List of products to refund
|
||||
* @return bool
|
||||
*/
|
||||
private function addOrderSlip(Order $order, $products)
|
||||
{
|
||||
$orderProducts = $order->getProductsDetail();
|
||||
$productsToPass = [];
|
||||
foreach ($products as $productId => $quantity) {
|
||||
if (!$quantity) {
|
||||
continue;
|
||||
}
|
||||
foreach ($orderProducts as $orderProduct) {
|
||||
if ((int) $orderProduct['id_order_detail'] === (int) $productId) {
|
||||
$quantity = min((int) $quantity, (int) $orderProduct['product_quantity']);
|
||||
$orderProduct['quantity'] = $quantity;
|
||||
$orderProduct['unit_price'] = $orderProduct['unit_price_tax_excl'];
|
||||
$productsToPass[] = $orderProduct;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OrderSlip::create($order, $productsToPass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all order dtails.
|
||||
*
|
||||
* @param Order $order A order
|
||||
* @param array $products Array of products to update
|
||||
* @return bool True on cucess
|
||||
*/
|
||||
private function updateOrderDetails(Order $order, $products)
|
||||
{
|
||||
$orderProducts = $order->getProductsDetail();
|
||||
$success = true;
|
||||
|
||||
foreach ($products as $productId => $quantity) {
|
||||
if (!$quantity) {
|
||||
continue;
|
||||
}
|
||||
$productFound = false;
|
||||
foreach ($orderProducts as $orderProduct) {
|
||||
if ((int) $orderProduct['id_order_detail'] === (int) $productId) {
|
||||
$quantity = min((int) $quantity, (int) $orderProduct['product_quantity']);
|
||||
if ($quantity) {
|
||||
$this->updateOneLineOfOrderDetails($productId, $quantity);
|
||||
}
|
||||
$productFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$productFound) {
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
|
||||
$order->update();
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal update one order detail.
|
||||
*
|
||||
* @param int $id_order_detail Id of a order detail
|
||||
* @param int $quantity Quantity of a product to refund
|
||||
* @return void
|
||||
*/
|
||||
private function updateOneLineOfOrderDetails($id_order_detail, $quantity)
|
||||
{
|
||||
$orderDetail = new OrderDetail($id_order_detail);
|
||||
|
||||
if (!property_exists($orderDetail, 'total_refunded_tax_incl')) {
|
||||
/* Old version. Nothing to do. */
|
||||
return;
|
||||
}
|
||||
if (!property_exists($orderDetail, 'total_refunded_tax_excl')) {
|
||||
/* Old version. Nothing to do. */
|
||||
return;
|
||||
}
|
||||
|
||||
$withTaxUnit = round($orderDetail->unit_price_tax_incl, 2);
|
||||
$withoutTaxUnit = round($orderDetail->unit_price_tax_excl, 2);
|
||||
$withTax = round($withTaxUnit * $quantity, 2);
|
||||
$withoutTax = round($withoutTaxUnit * $quantity, 2);
|
||||
$withTaxRefunded = round($orderDetail->total_refunded_tax_incl, 2);
|
||||
$withoutTaxRefunded = round($orderDetail->total_refunded_tax_excl, 2);
|
||||
$withTaxRefunded = round($withTaxRefunded + $withTax, 2);
|
||||
$withoutTaxRefunded = round($withoutTaxRefunded + $withoutTax, 2);
|
||||
$orderDetail->total_refunded_tax_incl = $withTaxRefunded;
|
||||
$orderDetail->total_refunded_tax_excl = $withoutTaxRefunded;
|
||||
$orderDetail->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of products that may be refunded.
|
||||
*
|
||||
* @param Order $order Order that may be refunded
|
||||
* @return array List of products
|
||||
*/
|
||||
public function extractProductsDetails($order)
|
||||
{
|
||||
$context = Context::getContext();
|
||||
if (method_exists($context, 'getCurrentLocale')) {
|
||||
return $this->extractProductsDetailsModern($order, $context);
|
||||
} else {
|
||||
return $this->extractProductsDetailsLegacy($order, $context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of products that may be refunded. Modern version.
|
||||
*
|
||||
* @param Order $order Order that may be refunded
|
||||
* @param Context $context Context of request
|
||||
* @return array List of products
|
||||
*/
|
||||
private function extractProductsDetailsModern($order, $context)
|
||||
{
|
||||
$currency = Currency::getCurrencyInstance($order->id_currency);
|
||||
$locale = $context->getCurrentLocale();
|
||||
$products = $order->getProductsDetail();
|
||||
|
||||
$ret = [];
|
||||
|
||||
foreach ($products as $product) {
|
||||
$line = [
|
||||
'productId' => $product['id_order_detail'],
|
||||
'name' => $product['product_name'],
|
||||
'quantity' => $product['product_quantity'] - $product['product_quantity_refunded'],
|
||||
'price' => $product['unit_price_tax_incl'],
|
||||
'priceFormatted' => $locale->formatPrice($product['unit_price_tax_incl'], $currency->iso_code),
|
||||
];
|
||||
$ret[] = $line;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of products that may be refunded. Legacy version.
|
||||
*
|
||||
* It is used for versions older than 1.7.6.
|
||||
*
|
||||
* @param Order $order Order that may be refunded
|
||||
* @param Context $context Context of request
|
||||
* @return array List of products
|
||||
*/
|
||||
private function extractProductsDetailsLegacy($order, $context)
|
||||
{
|
||||
$currency = Currency::getCurrencyInstance($order->id_currency);
|
||||
$products = $order->getProductsDetail();
|
||||
|
||||
$ret = [];
|
||||
|
||||
foreach ($products as $product) {
|
||||
$line = [
|
||||
'productId' => $product['id_order_detail'],
|
||||
'name' => $product['product_name'],
|
||||
'quantity' => $product['product_quantity'] - $product['product_quantity_refunded'],
|
||||
'price' => $product['unit_price_tax_incl'],
|
||||
'priceFormatted' => Tools::displayPrice($product['unit_price_tax_incl'], $currency, false, $context),
|
||||
];
|
||||
$ret[] = $line;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user