Initial
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.idea
|
||||
/vendor/
|
||||
/composer.lock
|
26
Plugin.php
Normal file
26
Plugin.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php namespace Wpstudio\Sber;
|
||||
|
||||
use Wpstudio\Sber\Classes\DefaultMoneyRepair;
|
||||
use OFFLINE\Mall\Classes\Payments\PaymentGateway;
|
||||
use OFFLINE\Mall\Classes\Utils\Money;
|
||||
use System\Classes\PluginBase;
|
||||
use Wpstudio\Sber\Classes\SberCheckout;
|
||||
|
||||
class Plugin extends PluginBase
|
||||
{
|
||||
/**
|
||||
* @var array Plugin dependencies
|
||||
*/
|
||||
public $require = ['Offline.Mall'];
|
||||
|
||||
final public function boot(): void
|
||||
{
|
||||
$gateway = $this->app->get(PaymentGateway::class);
|
||||
$gateway->registerProvider(new SberCheckout());
|
||||
|
||||
// For solve this issue https://github.com/OFFLINE-GmbH/oc-mall-plugin/issues/258
|
||||
$this->app->singleton(Money::class, function () {
|
||||
return new DefaultMoneyRepair();
|
||||
});
|
||||
}
|
||||
}
|
16
classes/DefaultMoneyRepair.php
Normal file
16
classes/DefaultMoneyRepair.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php namespace Wpstudio\Sber\Classes;
|
||||
|
||||
use OFFLINE\Mall\Classes\Utils\DefaultMoney;
|
||||
|
||||
/***
|
||||
* Helper class to solve this problem https://github.com/OFFLINE-GmbH/oc-mall-plugin/issues/258
|
||||
* paypal error after redirect to site
|
||||
* After payment via PayPal upon returning to the site, we get an error Call to a member function getCurrent() on null
|
||||
*/
|
||||
class DefaultMoneyRepair extends DefaultMoney
|
||||
{
|
||||
final protected function render($contents, array $vars): string
|
||||
{
|
||||
return number_format($vars['price'],$vars['currency']->decimals, ',', ' ').' '.$vars['currency']->symbol;
|
||||
}
|
||||
}
|
283
classes/SberCheckout.php
Normal file
283
classes/SberCheckout.php
Normal file
@ -0,0 +1,283 @@
|
||||
<?php namespace Wpstudio\Sber\Classes;
|
||||
|
||||
use OFFLINE\Mall\Classes\Payments\PaymentProvider;
|
||||
use OFFLINE\Mall\Classes\Payments\PaymentResult;
|
||||
use OFFLINE\Mall\Models\OrderProduct;
|
||||
use OFFLINE\Mall\Models\PaymentGatewaySettings;
|
||||
use OFFLINE\Mall\Models\OrderState;
|
||||
use OFFLINE\Mall\Models\Order;
|
||||
use Omnipay\Omnipay;
|
||||
use Omnipay\Sberbank\Gateway;
|
||||
use Omnipay\Sberbank\Message\AbstractRequest;
|
||||
use Omnipay\Sberbank\Message\AbstractResponse;
|
||||
use Omnipay\Sberbank\Message\AuthorizeRequest;
|
||||
use Omnipay\Sberbank\Message\AuthorizeResponse;
|
||||
use Throwable;
|
||||
use Session;
|
||||
use Lang;
|
||||
|
||||
|
||||
class SberCheckout extends PaymentProvider
|
||||
{
|
||||
/**
|
||||
* The order that is being paid.
|
||||
*
|
||||
* @var Order
|
||||
*/
|
||||
public $order;
|
||||
/**
|
||||
* Data that is needed for the payment.
|
||||
* Card numbers, tokens, etc.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* Return the display name of your payment provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
final public function name(): string
|
||||
{
|
||||
return Lang::get('wpstudio.sber::lang.settings.sber_checkout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a unique identifier for this payment provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
final public function identifier(): string
|
||||
{
|
||||
return 'sber';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the given input data for this payment.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \October\Rain\Exception\ValidationException
|
||||
*/
|
||||
final public function validate(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the payment.
|
||||
*
|
||||
* @param PaymentResult $result
|
||||
*
|
||||
* @return PaymentResult
|
||||
*/
|
||||
final public function process(PaymentResult $result): PaymentResult
|
||||
{
|
||||
$gateway = $this->getGateway();
|
||||
|
||||
try {
|
||||
$request = $gateway->authorize([
|
||||
'orderNumber' => $this->order->id,
|
||||
'amount' => $this->order->total_in_currency,
|
||||
'returnUrl' => $this->returnUrl(),
|
||||
'failUrl' => $this->cancelUrl(),
|
||||
'description' => Lang::get('wpstudio.sber::lang.messages.order_number').$this->order->order_number,
|
||||
]);
|
||||
|
||||
assert($request instanceof AuthorizeRequest);
|
||||
|
||||
// hacking private method
|
||||
$reflectionMethod = new \ReflectionMethod(AbstractRequest::class, 'setParameter');
|
||||
$reflectionMethod->setAccessible(true);
|
||||
$reflectionMethod->invoke($request, 'orderBundle', $this->getOrderBundle());
|
||||
|
||||
$response = $request->send();
|
||||
} catch (Throwable $e) {
|
||||
return $result->fail([], $e);
|
||||
}
|
||||
|
||||
assert($response instanceof AuthorizeResponse);
|
||||
|
||||
Session::put('mall.payment.callback', self::class);
|
||||
|
||||
$this->setOrder($result->order);
|
||||
|
||||
$result->order->payment_transaction_id = $response->getOrderId();
|
||||
|
||||
$result->order->save();
|
||||
|
||||
return $result->redirect($response->getRedirectResponse()->getTargetUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gerenate sberbank orderBundle
|
||||
* @see https://securepayments.sberbank.ru/wiki/doku.php/integration:api:rest:requests:registerpreauth_cart#orderbundle
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
final public function getOrderBundle(): array
|
||||
{
|
||||
$orderCreationDateFormatted = $this->order->created_at->format('Y-m-dTH:m:s');
|
||||
|
||||
$cartItems = $this->getOrderCartItems();
|
||||
|
||||
if ($cartItems) {
|
||||
return [
|
||||
'orderCreationDate' => $orderCreationDateFormatted ?? '',
|
||||
'cartItems' => $cartItems
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create order cartitems for order bundle
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
final public function getOrderCartItems(): array
|
||||
{
|
||||
$cartItems = [];
|
||||
|
||||
foreach ($this->order->products as $positionId => $product) {
|
||||
assert($product instanceof OrderProduct);
|
||||
|
||||
$cartItems['items'] = [
|
||||
'positionId' => $positionId,
|
||||
'name' => $product->name,
|
||||
'quantity' => [
|
||||
'value' => $product->quantity,
|
||||
'measure' => ''
|
||||
],
|
||||
'itemCode' => $product->variant_id ?? $product->product_id,
|
||||
'itemPrice' => $product->pricePostTaxes()->float,
|
||||
];
|
||||
}
|
||||
|
||||
return $cartItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Y.K. has processed the payment and redirected the user back.
|
||||
*
|
||||
* @param PaymentResult $result
|
||||
*
|
||||
* @return PaymentResult
|
||||
*/
|
||||
final public function complete(PaymentResult $result): PaymentResult
|
||||
{
|
||||
$this->setOrder($result->order);
|
||||
|
||||
$gateway = $this->getGateway();
|
||||
|
||||
try {
|
||||
/**
|
||||
* It will be similar to calling methods `completeAuthorize()` and `completePurchase()`
|
||||
*/
|
||||
$response = $gateway->orderStatus(
|
||||
[
|
||||
'orderId' => $result->order->payment_gateway_id, // gateway order number
|
||||
'language' => 'ru'
|
||||
]
|
||||
)->send();
|
||||
} catch (Throwable $e) {
|
||||
return $result->fail([], $e);
|
||||
}
|
||||
|
||||
assert($response instanceof AbstractResponse);
|
||||
|
||||
$data = (array)$response->getData();
|
||||
|
||||
if ( ! $response->isSuccessful()) {
|
||||
return $result->fail($data, $response);
|
||||
}
|
||||
|
||||
return $result->success($data, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Omnipay Gateway for PayPal.
|
||||
*
|
||||
* @return \Omnipay\Common\GatewayInterface
|
||||
*/
|
||||
final protected function getGateway(): Gateway
|
||||
{
|
||||
$gateway = Omnipay::create('Sberbank');
|
||||
|
||||
$gateway->setUserName(PaymentGatewaySettings::get('username'));
|
||||
$gateway->setPassword(decrypt(PaymentGatewaySettings::get('password')));
|
||||
|
||||
if (PaymentGatewaySettings::get('sber_test_mode')) {
|
||||
$gateway->setTestMode(true);
|
||||
}
|
||||
|
||||
|
||||
return $gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any custom backend settings fields.
|
||||
*
|
||||
* These fields will be rendered in the backend
|
||||
* settings page of your provider.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
final public function settings(): array
|
||||
{
|
||||
return [
|
||||
'sber_test_mode' => [
|
||||
'label' => 'wpstudio.sber::lang.settings.sber_test_mode',
|
||||
'comment' => 'wpstudio.sber::lang.settings.sber_test_mode_label',
|
||||
'span' => 'left',
|
||||
'type' => 'switch',
|
||||
],
|
||||
'username' => [
|
||||
'label' => Lang::get('wpstudio.sber::lang.settings.username'),
|
||||
'comment' => Lang::get('wpstudio.sber::lang.settings.username_label'),
|
||||
'span' => 'left',
|
||||
'type' => 'text',
|
||||
],
|
||||
'password' => [
|
||||
'label' => Lang::get('wpstudio.sber::lang.settings.password'),
|
||||
'comment' => Lang::get('wpstudio.sber::lang.settings.password_label'),
|
||||
'span' => 'left',
|
||||
'type' => 'text',
|
||||
],
|
||||
'setPayedVirtualOrderAsComplete' => [
|
||||
'label' => Lang::get('wpstudio.sber::lang.settings.set_payed_virtual_order_as_complete'),
|
||||
'span' => 'left',
|
||||
'type' => 'checkbox',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting keys returned from this method are stored encrypted.
|
||||
*
|
||||
* Use this to store API tokens and other secret data
|
||||
* that is needed for this PaymentProvider to work.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
final public function encryptedSettings(): array
|
||||
{
|
||||
return ['password'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Getting order state id by flag
|
||||
*
|
||||
* @param $orderStateFlag
|
||||
* @return int
|
||||
*/
|
||||
final protected function getOrderStateId($orderStateFlag): int
|
||||
{
|
||||
$orderStateModel = OrderState::where('flag', $orderStateFlag)->first();
|
||||
|
||||
return $orderStateModel->id;
|
||||
}
|
||||
}
|
14
composer.json
Normal file
14
composer.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "dimti/oc-sber-plugin",
|
||||
"description": "Sber payment gateway for offline.mall",
|
||||
"require": {
|
||||
"andrewnovikof/omnipay-sberbank": "^3.0"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "WP Studio Team",
|
||||
"email": "info@wpstudio.ru"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "dev"
|
||||
}
|
18
lang/en/lang.php
Normal file
18
lang/en/lang.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php return [
|
||||
'plugin' => [
|
||||
'name' => 'Sber for Offline.Mall',
|
||||
'description' => 'Adding Sber payment to offline.mall'
|
||||
],
|
||||
'settings' => [
|
||||
'sber_checkout' => 'Sber',
|
||||
'sber_test_mode' => 'Test mode',
|
||||
'sber_test_mode_label' => 'Turned on test mode for sber gateway',
|
||||
'username' => 'Username',
|
||||
'username_label' => 'Sber api username: T****-api',
|
||||
'password' => 'Password',
|
||||
'password_label' => 'Sber api password',
|
||||
],
|
||||
'messages' => [
|
||||
'order_number' => 'Order №',
|
||||
]
|
||||
];
|
18
lang/ru/lang.php
Normal file
18
lang/ru/lang.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php return [
|
||||
'plugin' => [
|
||||
'name' => 'Sber для Mall',
|
||||
'description' => 'Добавляет платежный провайдер Sber в плагин Mall'
|
||||
],
|
||||
'settings' => [
|
||||
'sber_checkout' => 'Sber',
|
||||
'sber_test_mode' => 'Тестовый режим',
|
||||
'sber_test_mode_label' => 'Тестовый режим',
|
||||
'username' => 'Пользователь',
|
||||
'username_label' => 'Пользователь',
|
||||
'password' => 'Пароль',
|
||||
'password_label' => 'Пароль',
|
||||
],
|
||||
'messages' => [
|
||||
'order_number' => 'Заказ №',
|
||||
]
|
||||
];
|
6
plugin.yaml
Normal file
6
plugin.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
plugin:
|
||||
name: 'wpstudio.sber::lang.plugin.name'
|
||||
description: 'wpstudio.sber::lang.plugin.description'
|
||||
author: WP Studio, info@wpstudio.ru
|
||||
icon: oc-icon-credit-card
|
||||
homepage: ''
|
2
updates/version.yaml
Normal file
2
updates/version.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
1.0.1:
|
||||
- Initialize plugin.
|
Reference in New Issue
Block a user