first commit
This commit is contained in:
980
class/class.Payment.php
Normal file
980
class/class.Payment.php
Normal file
@@ -0,0 +1,980 @@
|
||||
<?php
|
||||
|
||||
use KupShop\AdminBundle\Util\ActivityLog;
|
||||
use KupShop\KupShopBundle\Config;
|
||||
use KupShop\KupShopBundle\Context\CurrencyContext;
|
||||
use KupShop\KupShopBundle\Context\DomainContext;
|
||||
use KupShop\KupShopBundle\Context\LanguageContext;
|
||||
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
||||
use KupShop\KupShopBundle\Util\Contexts;
|
||||
use KupShop\KupShopBundle\Util\Delivery\RestrictionParams;
|
||||
use KupShop\KupShopBundle\Util\Delivery\RestrictionUtils;
|
||||
use KupShop\OrderingBundle\Entity\Purchase\PurchaseState;
|
||||
use KupShop\OrderingBundle\Exception\PaymentException;
|
||||
use KupShop\OrderingBundle\Util\Order\OrderInfo;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
#[AllowDynamicProperties]
|
||||
class Payment implements ArrayAccess
|
||||
{
|
||||
use DatabaseCommunication;
|
||||
|
||||
// Payment statuses
|
||||
public const STATUS_UNKNOWN = -1;
|
||||
public const STATUS_CREATED = 1;
|
||||
public const STATUS_PENDING = 2;
|
||||
public const STATUS_STORNO = 3;
|
||||
public const STATUS_FINISHED = 0;
|
||||
|
||||
/** @var \Symfony\Component\HttpFoundation\Request */
|
||||
protected $request;
|
||||
|
||||
// Payment class info
|
||||
public static $name = 'NoName';
|
||||
|
||||
public static bool $canAutoReturn = false;
|
||||
|
||||
public $class = 'NoClass';
|
||||
|
||||
protected $databaseName;
|
||||
|
||||
// Shop Settings
|
||||
public $config;
|
||||
|
||||
public $step = 0;
|
||||
public $template = 'payment.tpl';
|
||||
protected $templateCart;
|
||||
protected $templateDescription;
|
||||
protected $templateOrderView = 'payment.orderView.tpl';
|
||||
protected $templateInit;
|
||||
|
||||
protected ?string $defaultIcon = null;
|
||||
|
||||
/** Order of payment.
|
||||
* @var Order
|
||||
*/
|
||||
public $order;
|
||||
public $orderId;
|
||||
|
||||
public $status = self::STATUS_UNKNOWN;
|
||||
public ?int $paymentId = null;
|
||||
protected $id;
|
||||
protected $custom_data;
|
||||
|
||||
/**
|
||||
* @var \KupShop\OrderingBundle\Exception\PaymentException
|
||||
*/
|
||||
public $exception;
|
||||
|
||||
protected $pay_method;
|
||||
|
||||
public const METHOD_CASH = 1;
|
||||
public const METHOD_CARD = 2;
|
||||
public const METHOD_INVOICE = 3;
|
||||
public const METHOD_TRANSFER = 6;
|
||||
public const METHOD_COD = 7;
|
||||
public const METHOD_ONLINE = 8;
|
||||
|
||||
public const METHOD_CASH_INSERTION = 4;
|
||||
public const METHOD_CASH_SELECTION = 5;
|
||||
public const METHOD_COMPENSATION = 9;
|
||||
|
||||
// Používá se pro slovenské EET - úhrada faktury (101 - hotově, 102 - kartou)
|
||||
public const METHOD_EET_INVOICE_CASH = 101;
|
||||
public const METHOD_EET_INVOICE_CARD = 102;
|
||||
|
||||
public const METHOD_UNKNOWN = 10;
|
||||
public const METHOD_INSTALLMENTS = 11;
|
||||
|
||||
protected $isNotification = false;
|
||||
|
||||
/** @var RestrictionUtils */
|
||||
protected $restrictionUtils;
|
||||
|
||||
/** @var RestrictionParams */
|
||||
protected $restrictionParams;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
protected $kibanaLogger;
|
||||
|
||||
public static function getSettingsConfiguration(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function getCanAutoReturn(): bool
|
||||
{
|
||||
return static::$canAutoReturn;
|
||||
}
|
||||
|
||||
public static function includeClass($name)
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
$name = preg_replace('/[^a-zA-Z0-9-]/', '', $name);
|
||||
$class = "payments/class.{$name}.php";
|
||||
|
||||
if (file_exists($cfg['Path']['web_root'].$class) && !isFunctionalTests()) {
|
||||
require_once $cfg['Path']['web_root'].$class;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file_exists($cfg['Path']['shared_class'].$class)) {
|
||||
throw new NotFoundHttpException('Platební modul '.$name.' neexistuje');
|
||||
}
|
||||
|
||||
require_once $cfg['Path']['shared_class'].$class;
|
||||
}
|
||||
|
||||
/** Factory function for Payment clases.
|
||||
* @param string $className Payment class name
|
||||
*
|
||||
* @return Payment
|
||||
*/
|
||||
public static function getClass($className)
|
||||
{
|
||||
self::includeClass($className);
|
||||
|
||||
if ($paymentClass = ServiceContainer::getService('kupshop.payment.'.strtolower($className), Container::NULL_ON_INVALID_REFERENCE)) {
|
||||
return $paymentClass;
|
||||
}
|
||||
|
||||
if (!$className::isEnabled($className)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new $className();
|
||||
}
|
||||
|
||||
/** List all Payment implementations.
|
||||
*/
|
||||
public static function listClasses()
|
||||
{
|
||||
global $cfg;
|
||||
|
||||
$classDir = $cfg['Path']['shared_class'].'payments/';
|
||||
|
||||
$shopClassDir = $cfg['Path']['web_root'].'payments/';
|
||||
$classesDir = array_merge(glob($classDir.'class.*.php'), glob($shopClassDir.'class.*.php'));
|
||||
$classes = [];
|
||||
|
||||
foreach ($classesDir as $class) {
|
||||
$class = basename($class);
|
||||
preg_match('/class.([a-zA-Z0-9-]+).php/', $class, $matches);
|
||||
$class = $matches[1];
|
||||
|
||||
self::includeClass($class);
|
||||
|
||||
if (!$class::isEnabled($class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$classes[$class] = $class::$name;
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id ? (int) $this->id : null;
|
||||
}
|
||||
|
||||
public function setIsNotification(bool $isNotification): Payment
|
||||
{
|
||||
$this->isNotification = $isNotification;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setDatabaseName($databaseName)
|
||||
{
|
||||
$this->databaseName = $databaseName;
|
||||
}
|
||||
|
||||
public function hasCartTitle()
|
||||
{
|
||||
return (bool) $this->templateCart;
|
||||
}
|
||||
|
||||
public function hasCartTemplate()
|
||||
{
|
||||
return (bool) $this->templateCart;
|
||||
}
|
||||
|
||||
public function getGenericPaymentUrl(int $step = 1, array $params = []): string
|
||||
{
|
||||
return path('kupshop_ordering_payment_payment', array_merge([
|
||||
'IDo' => $this->order->id,
|
||||
'cf' => $this->order->getSecurityCode(),
|
||||
'step' => $step,
|
||||
'class' => $this->class,
|
||||
], $params), \Symfony\Component\Routing\Router::ABSOLUTE_URL);
|
||||
}
|
||||
|
||||
/** @deprecated Use getGenericPaymentUrl() instead. */
|
||||
public function getPaymentUrl()
|
||||
{
|
||||
return $this->getGenericPaymentUrl();
|
||||
}
|
||||
|
||||
/** Get row in cart with payment title.
|
||||
* @param Smarty $smarty
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @internal param array $context
|
||||
*/
|
||||
public function getCartTitle($smarty)
|
||||
{
|
||||
if ($this->templateCart) {
|
||||
$params = [
|
||||
'object' => $this,
|
||||
];
|
||||
|
||||
$_smarty_tpl_vars = $smarty->tpl_vars;
|
||||
|
||||
$ret = $smarty->_subTemplateRender($this->templateCart, $smarty->cache_id, $smarty->compile_id, 0, null, $params, 0, false);
|
||||
|
||||
$smarty->tpl_vars = $_smarty_tpl_vars;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getInitTemplate($smarty)
|
||||
{
|
||||
if ($this->templateInit) {
|
||||
$params = [
|
||||
'object' => $this,
|
||||
];
|
||||
|
||||
$_smarty_tpl_vars = $smarty->tpl_vars;
|
||||
|
||||
$ret = $smarty->_subTemplateRender($this->templateInit, $smarty->cache_id, $smarty->compile_id, 0, null, $params, 0, false);
|
||||
|
||||
$smarty->tpl_vars = $_smarty_tpl_vars;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Get payment HTML when payment selected.
|
||||
*/
|
||||
public function getCartDescription()
|
||||
{
|
||||
if ($this->templateDescription) {
|
||||
$smarty = createSmarty();
|
||||
$smarty->assign([
|
||||
'object' => $this,
|
||||
]);
|
||||
|
||||
return $smarty->fetch($this->templateDescription);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Get payment HTML on completed order.
|
||||
*/
|
||||
public function getOrderViewDescription($smarty = null)
|
||||
{
|
||||
$params = [
|
||||
'payment' => $this,
|
||||
'order' => $this->order,
|
||||
];
|
||||
|
||||
if ($smarty) {
|
||||
return $smarty->_subTemplateRender($this->templateOrderView, $smarty->cache_id, $smarty->compile_id, 0, null, $params, 0, false);
|
||||
} else {
|
||||
$smarty = createSmarty(false, true);
|
||||
$smarty->assign($params);
|
||||
|
||||
return $smarty->fetch($this->templateOrderView);
|
||||
}
|
||||
}
|
||||
|
||||
public static function isEnabled($className)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Get payment icon url and name.
|
||||
* @return array|null
|
||||
*/
|
||||
public function getIcon()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getRestrictionUtils()
|
||||
{
|
||||
if (!isset($this->restrictionUtils)) {
|
||||
$this->restrictionUtils = ServiceContainer::getService(RestrictionUtils::class);
|
||||
}
|
||||
|
||||
return $this->restrictionUtils->setType('payment');
|
||||
}
|
||||
|
||||
public function accept($totalPrice, $freeDelivery)
|
||||
{
|
||||
return $this->getRestrictionUtils()->checkHardRequirements($this);
|
||||
}
|
||||
|
||||
public function check(CartBase $cart)
|
||||
{
|
||||
$this->checkRestrictions($cart->getPurchaseState());
|
||||
|
||||
ServiceContainer::getService('event_dispatcher')->dispatch(
|
||||
new \KupShop\OrderingBundle\Event\PaymentCheckEvent($this, $cart)
|
||||
);
|
||||
}
|
||||
|
||||
public function checkRestrictions(PurchaseState $purchaseState)
|
||||
{
|
||||
$customData = $this->getCustomData();
|
||||
if ($restrictions = $customData['restrictions'] ?? false) {
|
||||
if (!isset($this->restrictionParams)) {
|
||||
$this->restrictionParams = $this->getRestrictionUtils()
|
||||
->createParamsFromConfig($this->config ?? [], $customData['restrictions'] ?? []);
|
||||
}
|
||||
$this->getRestrictionUtils()->checkSoftRequirements(
|
||||
$purchaseState->getDeliveryRestrictionParams(),
|
||||
$this->restrictionParams
|
||||
);
|
||||
|
||||
if ($productsFilter = $restrictions['productsFilter'] ?? null) {
|
||||
$this->getRestrictionUtils()->checkProductsFilter($productsFilter, $purchaseState->getProductList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setException(Exception $exception)
|
||||
{
|
||||
$this->exception = $exception;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return empty($this->databaseName) ? static::$name : $this->databaseName;
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->loadConfig();
|
||||
|
||||
$this->kibanaLogger = ServiceContainer::getService('logger');
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return static::class;
|
||||
}
|
||||
|
||||
public function setOrder($order)
|
||||
{
|
||||
if (is_object($order)) {
|
||||
$this->orderId = $order->id;
|
||||
$this->order = $order;
|
||||
} else {
|
||||
$this->orderId = $order;
|
||||
$this->order = new Order();
|
||||
|
||||
if (!$this->order->createFromDB($this->orderId)) {
|
||||
$this->error(replacePlaceholders(translate('errorOrderNotFound', 'payment'), ['ID' => $this->orderId]));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
public function getOrderNumber(): string
|
||||
{
|
||||
return $this->order->order_no;
|
||||
}
|
||||
|
||||
public function loadConfig(?string $language = null)
|
||||
{
|
||||
$cfg = Config::get();
|
||||
// pokud je poslana $language, tak naloaduju settingy pro ten danej jazyk
|
||||
// napr. v administraci getDefault vzdycky naloaduje default jazyk, ale v nekterych pripadech
|
||||
// chci settingy pro jiny jazyk (napr. kdyz vracim platbu)
|
||||
$dbcfg = $language ? Settings::getFromCache($language) : Settings::getDefault();
|
||||
|
||||
$dbConfig = $this->loadPaymentDbConfig($dbcfg);
|
||||
|
||||
if (isset($dbcfg->payment_config['order_status_new']) && !isset($dbConfig['order_status_new'])) {
|
||||
$dbConfig['order_status_new'] = $dbcfg->payment_config['order_status_new'];
|
||||
}
|
||||
if (isset($dbcfg->payment_config['order_status_finished'])) {
|
||||
$dbConfig['order_status_finished'] = $dbcfg->payment_config['order_status_finished'] !== 'keep' ? $dbcfg->payment_config['order_status_finished'] : null;
|
||||
}
|
||||
|
||||
$config = $cfg['Modules']['payments'][$this->class] ?? false;
|
||||
|
||||
if (!is_array($config)) {
|
||||
$config = [];
|
||||
}
|
||||
|
||||
// Do not load database configuration in development - use one from config_db.php
|
||||
if (isLocalDevelopment()) {
|
||||
$dbConfig = [];
|
||||
}
|
||||
|
||||
$this->config = array_merge($config, $dbConfig);
|
||||
|
||||
// neni pouzity isset kvuli tomu ze hodnota muze bejt null !!
|
||||
if (!array_key_exists('order_status_finished', $this->config)) {
|
||||
$this->config['order_status_finished'] = 1;
|
||||
$languageContext = Contexts::get(LanguageContext::class);
|
||||
if ($languageContext->translationActive()) {
|
||||
// hotfix, zahranicni platby menily stav objednavek
|
||||
$defaultDbcfg = Settings::getFromCache($languageContext->getDefaultId());
|
||||
if (isset($defaultDbcfg->payment_config['order_status_finished'])) {
|
||||
$this->config['order_status_finished'] = $defaultDbcfg->payment_config['order_status_finished'] !== 'keep' ? $defaultDbcfg->payment_config['order_status_finished'] : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load domain config
|
||||
if (array_key_exists('domain_config', $this->config)) {
|
||||
$domainContext = ServiceContainer::getService(DomainContext::class);
|
||||
$domain = $domainContext->getActiveId();
|
||||
if (array_key_exists($domain, $this->config['domain_config'])) {
|
||||
$domain_config = $this->config['domain_config'][$domain];
|
||||
$this->config = array_merge($this->config, $domain_config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadPaymentDbConfig($dbcfg): array
|
||||
{
|
||||
return array_filter($dbcfg->payments[$this->class] ?? []);
|
||||
}
|
||||
|
||||
public function getOrderId($session)
|
||||
{
|
||||
$session = sqlFormatInput($session);
|
||||
$orderId = returnSQLResult('SELECT id_order FROM '.getTableName('order_payments')." WHERE payment_data LIKE '%\"{$session}\"%'");
|
||||
|
||||
/*
|
||||
if (empty($orderId))
|
||||
logError(__FILE__, __LINE__, "Payment: getOrderId: Cannot get order id of session: {$session}, POST:".print_r($_POST, true));
|
||||
*/
|
||||
|
||||
return $orderId;
|
||||
}
|
||||
|
||||
public function getStatus($session = null)
|
||||
{
|
||||
$SQL = sqlQuery('SELECT id, status, payment_data FROM '.getTableName('order_payments')." WHERE id_order={$this->orderId} FOR UPDATE");
|
||||
|
||||
if (empty($session) && sqlNumRows($SQL) > 1) {
|
||||
logError(__FILE__, __LINE__, 'Payment: getStatus: empty session but multiple payments!');
|
||||
}
|
||||
|
||||
while (($payment = sqlFetchAssoc($SQL)) !== false) {
|
||||
if (!empty($payment['payment_data'])) {
|
||||
$payment_data = json_decode($payment['payment_data'], true);
|
||||
|
||||
if (empty($session) || (isset($payment_data['session']) && $payment_data['session'] == $session)) {
|
||||
$this->status = $payment['status'];
|
||||
$this->paymentId = $payment['id'];
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function createPayment($session, $price = null, $data = [])
|
||||
{
|
||||
$fields = [
|
||||
'id_order' => $this->orderId,
|
||||
'price' => $price,
|
||||
'note' => "Platba modulu {$this->class}",
|
||||
'status' => self::STATUS_CREATED,
|
||||
'payment_data' => json_encode(array_merge($data, ['session' => $session])),
|
||||
'date' => date('Y-m-d H:i:s'),
|
||||
'method' => $this->pay_method ?? self::METHOD_ONLINE,
|
||||
'admin' => getAdminID(null),
|
||||
];
|
||||
|
||||
$this->insertSQL('order_payments', $fields);
|
||||
|
||||
$this->status = self::STATUS_CREATED;
|
||||
$this->paymentId = sqlInsertId();
|
||||
|
||||
$this->order->updatePayments();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setStatus($status, $session = null)
|
||||
{
|
||||
$change = false;
|
||||
// Použiju transakci, abych zajistil že zjištění stavu transakce a její následná změna jsou atomický a nevběhne tam mezitím jiný thread
|
||||
sqlGetConnection()->transactional(function () use ($status, $session, &$change) {
|
||||
if (!$this->getStatus($session)) {
|
||||
logError(__FILE__, __LINE__, 'Payment::setStatus: get status failed!');
|
||||
$this->error('Payment::setStatus: get status failed!');
|
||||
}
|
||||
|
||||
if ($this->status != $status) {
|
||||
if ($this->status == self::STATUS_FINISHED) {
|
||||
return;
|
||||
}
|
||||
|
||||
$change = true;
|
||||
|
||||
sqlQuery('UPDATE '.getTableName('order_payments')." SET status={$status}, date=NOW() WHERE id={$this->paymentId}");
|
||||
}
|
||||
});
|
||||
|
||||
// Tohle mám mimo transakci, protože to může trvat dlouho (odesílá se email o zaplacení).
|
||||
// Hlavní je, že se tdvakrát nezavolá změna stavu zaplacení platby
|
||||
if ($change) {
|
||||
$this->order->updatePayments();
|
||||
|
||||
$forceEmail = null;
|
||||
$this->changeOrderStatus($status, $forceEmail);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function changeOrderStatus($paymentStatus, $forceEmail)
|
||||
{
|
||||
switch ($paymentStatus) {
|
||||
case self::STATUS_FINISHED:
|
||||
if ($this->order->isActive() && !$this->order->isPaid()) {
|
||||
break;
|
||||
}
|
||||
|
||||
$status = $this->config['order_status_finished'] ?? null;
|
||||
if (is_null($status)) {
|
||||
$status = $this->order->status;
|
||||
}
|
||||
|
||||
$this->order->changeStatus($status, translate('msgStatusFinished', 'payment'), false);
|
||||
|
||||
if (($forceEmail !== false) && ($this->order->source != OrderInfo::ORDER_SOURCE_POS)) {
|
||||
// Send Payment email
|
||||
$this->order->sendPaymentReceipt($this->paymentId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$this->status = $paymentStatus;
|
||||
}
|
||||
|
||||
private function getPayment()
|
||||
{
|
||||
return sqlQueryBuilder()->select('*')
|
||||
->from('order_payments', 'op')
|
||||
->where(\Query\Operator::equals(['op.id' => $this->paymentId]))->execute()->fetch();
|
||||
}
|
||||
|
||||
public function checkOrderIsActiveAndNotPaid()
|
||||
{
|
||||
if (!$this->order->isActive()) {
|
||||
$this->error(replacePlaceholders(translate('errorOrderCanceled', 'payment'), ['ID' => $this->order->order_no]));
|
||||
}
|
||||
|
||||
if ($this->order->isPaid(true)) {
|
||||
$this->error(replacePlaceholders(translate('errorOrderAlreadyPaid', 'payment'), ['ID' => $this->order->order_no]));
|
||||
}
|
||||
}
|
||||
|
||||
public function startPayment()
|
||||
{
|
||||
$this->step(1, translate('msgStartPayment', 'payment'));
|
||||
}
|
||||
|
||||
public function processStep($index)
|
||||
{
|
||||
try {
|
||||
if ($index == 1) {
|
||||
$this->checkOrderIsActiveAndNotPaid();
|
||||
}
|
||||
if ($index >= 0) {
|
||||
$reflectionMethod = new ReflectionMethod($this, 'processStep_'.intval($index));
|
||||
|
||||
return $reflectionMethod->invoke($this);
|
||||
}
|
||||
} catch (\KupShop\KupShopBundle\Exception\RedirectException $e) {
|
||||
throw $e;
|
||||
} catch (Exception $e) {
|
||||
addActivityLog(ActivityLog::SEVERITY_ERROR, ActivityLog::TYPE_COMMUNICATION, 'Payment error: '.$this->getName().': '.$e->getMessage());
|
||||
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function step($index, $message, $data = [])
|
||||
{
|
||||
// logError(__FILE__, __LINE__, "Payment::Step: $index, $message, {$this->orderId}");
|
||||
if ($this->isNotification) {
|
||||
$this->sendNotificationResponse(500, $message);
|
||||
}
|
||||
|
||||
$redirect = [
|
||||
'URL' => 'launch.php',
|
||||
's' => 'payment',
|
||||
'IDo' => $this->orderId,
|
||||
'class' => $this->class,
|
||||
'step' => $index,
|
||||
'cf' => $this->order ? $this->order->getSecurityCode() : '',
|
||||
'message' => $message,
|
||||
];
|
||||
$redirect = array_merge($redirect, $data);
|
||||
|
||||
redirection(createScriptURL($redirect));
|
||||
}
|
||||
|
||||
public function getStepUrl(int $step): string
|
||||
{
|
||||
return createScriptURL([
|
||||
's' => 'payment',
|
||||
'IDo' => $this->order->id,
|
||||
'cf' => $this->order->getSecurityCode(),
|
||||
'step' => $step,
|
||||
'class' => $this->class,
|
||||
'absolute' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function error($message)
|
||||
{
|
||||
if ($this->isNotification) {
|
||||
$this->sendNotificationResponse(500, $message);
|
||||
}
|
||||
if ($this->order) {
|
||||
addUserMessage($message, 'danger');
|
||||
|
||||
redirection($this->order->getUrl());
|
||||
}
|
||||
|
||||
if (getVal('step') != -1) {
|
||||
$this->step(-1, $message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function success($message)
|
||||
{
|
||||
if ($this->isNotification) {
|
||||
$this->sendNotificationResponse(200, 'OK');
|
||||
}
|
||||
if ($this->order) {
|
||||
addUserMessage($message, 'success');
|
||||
|
||||
redirection($this->order->getDetailUrl(1));
|
||||
}
|
||||
|
||||
$this->step(-2, $message);
|
||||
}
|
||||
|
||||
public function info($message)
|
||||
{
|
||||
if ($this->isNotification) {
|
||||
$this->sendNotificationResponse(200, $message);
|
||||
}
|
||||
addUserMessage($message, 'info');
|
||||
redirection($this->order->getUrl());
|
||||
}
|
||||
|
||||
public function checkAuth()
|
||||
{
|
||||
$cf = getVal('cf');
|
||||
|
||||
if ($this->order->getSecurityCode() != $cf) {
|
||||
throw new NotFoundHttpException(translate('errorSecurityCode', 'payment'));
|
||||
}
|
||||
}
|
||||
|
||||
public function storePaymentInfo()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function loadPaymentInfo($data)
|
||||
{
|
||||
foreach ($data as $key => $value) {
|
||||
$this->$key = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function requiresEET()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasOnlinePayment()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasPaymentDescription()
|
||||
{
|
||||
return $this->hasOnlinePayment();
|
||||
}
|
||||
|
||||
public function getPayMethod()
|
||||
{
|
||||
if (!$this->pay_method) {
|
||||
throw new RuntimeException('Missing pay_method in Payment class '.$this->getName());
|
||||
} else {
|
||||
return $this->pay_method;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ArrayAccess interface.
|
||||
*/
|
||||
public function offsetSet($offset, $value): void
|
||||
{
|
||||
$this->{$offset} = $value;
|
||||
}
|
||||
|
||||
public function offsetExists($offset): bool
|
||||
{
|
||||
return isset($this->{$offset});
|
||||
}
|
||||
|
||||
public function offsetUnset($offset): void
|
||||
{
|
||||
unset($this->{$offset});
|
||||
}
|
||||
|
||||
public function offsetGet($offset): mixed
|
||||
{
|
||||
return isset($this->{$offset}) ? $this->{$offset} : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false|array $payment (with decoded json payment_data as decoded_data)
|
||||
*/
|
||||
public function getPendingPayment()
|
||||
{
|
||||
$payments = $this->order->getPaymentsArray();
|
||||
foreach ($payments as $payment) {
|
||||
$paymentData = json_decode($payment['payment_data']);
|
||||
if (($payment['status'] == self::STATUS_CREATED || $payment['status'] == self::STATUS_PENDING)
|
||||
and isset($paymentData->paymentClass)
|
||||
and $paymentData->paymentClass === static::class
|
||||
) {
|
||||
$payment['decoded_data'] = $paymentData;
|
||||
|
||||
return $payment;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function setRequest(Symfony\Component\HttpFoundation\Request $request): Payment
|
||||
{
|
||||
$this->request = $request;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function orderCreatedPostProcess(Order $order)
|
||||
{
|
||||
if (($this->hasOnlinePayment() || (findModule(\Modules::BANK_AUTO_PAYMENTS) && $this->getPayMethod() === self::METHOD_TRANSFER))
|
||||
&& !empty($this->config['order_status_new'])
|
||||
&& $order->status !== $this->config['order_status_new']
|
||||
) {
|
||||
$order->changeStatus($this->config['order_status_new'], null, false);
|
||||
}
|
||||
}
|
||||
|
||||
public function deletePayment()
|
||||
{
|
||||
return sqlQueryBuilder()->delete('order_payments')->where(\Query\Operator::equals(['id' => $this->paymentId]))->execute();
|
||||
}
|
||||
|
||||
public function processAdminWindowData($data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getCustomData()
|
||||
{
|
||||
if (isset($this->custom_data)) {
|
||||
return $this->custom_data;
|
||||
}
|
||||
|
||||
if ($this->id !== null) {
|
||||
$this->custom_data = json_decode(sqlQueryBuilder()->select('data')
|
||||
->from('delivery_type_payment')
|
||||
->where(\Query\Operator::equals(['id' => $this->id]))
|
||||
->execute()
|
||||
->fetchColumn(), true);
|
||||
}
|
||||
|
||||
return $this->custom_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $id
|
||||
*/
|
||||
public function setID($id = null)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $custom_data
|
||||
*/
|
||||
public function setCustomData($custom_data): void
|
||||
{
|
||||
$this->custom_data = $custom_data;
|
||||
}
|
||||
|
||||
private function isPaymentInstanceOfClass($payment)
|
||||
{
|
||||
$data = (is_array($payment['payment_data'])) ? $payment['payment_data'] : json_decode($payment['payment_data'], true);
|
||||
|
||||
return ($data['paymentClass'] ?? '') === static::class;
|
||||
}
|
||||
|
||||
protected function updateReturnPayment($payment, $returnId, $full)
|
||||
{
|
||||
if ($returnId) {
|
||||
$title = 'Vrácení částky: objednávka '.$this->order->order_no.', číslo platby: '.$payment['id'];
|
||||
$data = ['return_from_payment' => $payment['id'], 'paymentClass' => $this->class];
|
||||
$this->updateSQL('order_payments', ['note' => $title, 'payment_data' => json_encode($data)], ['id' => $returnId]);
|
||||
}
|
||||
}
|
||||
|
||||
public function getPaymentForReturn($amount, ?int $paymentId = null)
|
||||
{
|
||||
if ($paymentId) {
|
||||
$this->paymentId = $paymentId;
|
||||
$payment = $this->getPayment();
|
||||
if ($this->isPaymentInstanceOfClass($payment)) {
|
||||
$payment['payment_data'] = json_decode($payment['payment_data'], true);
|
||||
|
||||
return $payment;
|
||||
}
|
||||
}
|
||||
|
||||
$paymentsArray = $this->order->getPaymentsArray();
|
||||
$payment = false;
|
||||
foreach ($paymentsArray as $paytmp) {
|
||||
if ((int) $paytmp['status'] === Payment::STATUS_FINISHED && $paytmp['price'] >= ($amount * -1)) {
|
||||
$paytmp['payment_data'] = json_decode($paytmp['payment_data'], true);
|
||||
if (isset($paytmp['payment_data']['session']) && $this->isPaymentInstanceOfClass($paytmp)) {
|
||||
$payment = $paytmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$payment) {
|
||||
throw new PaymentException('Platba nemohla být automaticky vrácena, protože neexistuje validní platba.');
|
||||
}
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
||||
public function enabledReturnPayment(): bool
|
||||
{
|
||||
$dbcfg = \Settings::getDefault();
|
||||
|
||||
return (($dbcfg->payment_config['return_payment_auto_gate'] ?? null) !== 'N') && static::$canAutoReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function doReturnPayment(array $payment, float $amount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function returnPayment($amount, ?int $paymentId = null, ?int $returnId = null)
|
||||
{
|
||||
// TODO: zabránit znovuvrácení platby, když už se z ní vracelo - vracet pouze zbytek
|
||||
// TODO: zakázat editaci vrácené platby, pokud byla vrácena automatem
|
||||
if ($this->enabledReturnPayment()) {
|
||||
$payment = $this->getPaymentForReturn($amount, $paymentId);
|
||||
$this->updateReturnPayment($payment, $returnId, ($payment['price'] + $amount) == 0);
|
||||
if ($result = $this->doReturnPayment($payment, $amount)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
$currencyContext = Contexts::get(CurrencyContext::class);
|
||||
$currency = $currencyContext->getActive();
|
||||
// Automatic return not implemented
|
||||
throw new PaymentException('Vrácení nelze pro tento způsob platby automatizovat. Vraťte zákazníkovi '.$amount * (-1).' '.$currency->getSymbol().' manuálně.');
|
||||
}
|
||||
|
||||
protected function sendNotificationResponse(int $httpResponseCode, $message)
|
||||
{
|
||||
http_response_code($httpResponseCode);
|
||||
echo $message;
|
||||
exit;
|
||||
}
|
||||
|
||||
public function getPhoto(?string $photo, ?string $date_updated = null): ?array
|
||||
{
|
||||
$icon = $this->getPhotoPath($photo);
|
||||
|
||||
if ($icon === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getImage($this->id, basename($icon), dirname($icon), 8, $this::$name, strtotime($date_updated));
|
||||
}
|
||||
|
||||
public function getPhotoPath(?string $photo): ?string
|
||||
{
|
||||
return empty($photo) ? $this->defaultIcon : '../payment/'.$photo;
|
||||
}
|
||||
|
||||
public function getClassName(): string
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pro platebni brany - vrati platebni metody.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getAvailableMethods()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getSelectedMethodId(): ?string
|
||||
{
|
||||
return $this->method ?? null;
|
||||
}
|
||||
|
||||
public function getSelectedMethod(): ?array
|
||||
{
|
||||
if (empty($this->method)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$methods = $this->getAvailableMethods();
|
||||
|
||||
return $methods[$this->method] ?? null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user