You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

283 lines
7.8 KiB

3 years ago
  1. <?php namespace Wpstudio\Sber\Classes;
  2. use OFFLINE\Mall\Classes\Payments\PaymentProvider;
  3. use OFFLINE\Mall\Classes\Payments\PaymentResult;
  4. use OFFLINE\Mall\Models\OrderProduct;
  5. use OFFLINE\Mall\Models\PaymentGatewaySettings;
  6. use OFFLINE\Mall\Models\OrderState;
  7. use OFFLINE\Mall\Models\Order;
  8. use Omnipay\Omnipay;
  9. use Omnipay\Sberbank\Gateway;
  10. use Omnipay\Sberbank\Message\AbstractRequest;
  11. use Omnipay\Sberbank\Message\AbstractResponse;
  12. use Omnipay\Sberbank\Message\AuthorizeRequest;
  13. use Omnipay\Sberbank\Message\AuthorizeResponse;
  14. use Throwable;
  15. use Session;
  16. use Lang;
  17. class SberCheckout extends PaymentProvider
  18. {
  19. /**
  20. * The order that is being paid.
  21. *
  22. * @var Order
  23. */
  24. public $order;
  25. /**
  26. * Data that is needed for the payment.
  27. * Card numbers, tokens, etc.
  28. *
  29. * @var array
  30. */
  31. public $data;
  32. /**
  33. * Return the display name of your payment provider.
  34. *
  35. * @return string
  36. */
  37. final public function name(): string
  38. {
  39. return Lang::get('wpstudio.sber::lang.settings.sber_checkout');
  40. }
  41. /**
  42. * Return a unique identifier for this payment provider.
  43. *
  44. * @return string
  45. */
  46. final public function identifier(): string
  47. {
  48. return 'sber';
  49. }
  50. /**
  51. * Validate the given input data for this payment.
  52. *
  53. * @return bool
  54. * @throws \October\Rain\Exception\ValidationException
  55. */
  56. final public function validate(): bool
  57. {
  58. return true;
  59. }
  60. /**
  61. * Process the payment.
  62. *
  63. * @param PaymentResult $result
  64. *
  65. * @return PaymentResult
  66. */
  67. final public function process(PaymentResult $result): PaymentResult
  68. {
  69. $gateway = $this->getGateway();
  70. try {
  71. $request = $gateway->authorize([
  72. 'orderNumber' => $this->order->id,
  73. 'amount' => $this->order->total_in_currency,
  74. 'returnUrl' => $this->returnUrl(),
  75. 'failUrl' => $this->cancelUrl(),
  76. 'description' => Lang::get('wpstudio.sber::lang.messages.order_number').$this->order->order_number,
  77. ]);
  78. assert($request instanceof AuthorizeRequest);
  79. // hacking private method
  80. $reflectionMethod = new \ReflectionMethod(AbstractRequest::class, 'setParameter');
  81. $reflectionMethod->setAccessible(true);
  82. $reflectionMethod->invoke($request, 'orderBundle', $this->getOrderBundle());
  83. $response = $request->send();
  84. } catch (Throwable $e) {
  85. return $result->fail([], $e);
  86. }
  87. assert($response instanceof AuthorizeResponse);
  88. Session::put('mall.payment.callback', self::class);
  89. $this->setOrder($result->order);
  90. $result->order->payment_transaction_id = $response->getOrderId();
  91. $result->order->save();
  92. return $result->redirect($response->getRedirectResponse()->getTargetUrl());
  93. }
  94. /**
  95. * Gerenate sberbank orderBundle
  96. * @see https://securepayments.sberbank.ru/wiki/doku.php/integration:api:rest:requests:registerpreauth_cart#orderbundle
  97. *
  98. * @return array
  99. *
  100. */
  101. final public function getOrderBundle(): array
  102. {
  103. $orderCreationDateFormatted = $this->order->created_at->format('Y-m-dTH:m:s');
  104. $cartItems = $this->getOrderCartItems();
  105. if ($cartItems) {
  106. return [
  107. 'orderCreationDate' => $orderCreationDateFormatted ?? '',
  108. 'cartItems' => $cartItems
  109. ];
  110. }
  111. return [];
  112. }
  113. /**
  114. * Create order cartitems for order bundle
  115. *
  116. * @return array
  117. */
  118. final public function getOrderCartItems(): array
  119. {
  120. $cartItems = [];
  121. foreach ($this->order->products as $positionId => $product) {
  122. assert($product instanceof OrderProduct);
  123. $cartItems['items'] = [
  124. 'positionId' => $positionId,
  125. 'name' => $product->name,
  126. 'quantity' => [
  127. 'value' => $product->quantity,
  128. 'measure' => ''
  129. ],
  130. 'itemCode' => $product->variant_id ?? $product->product_id,
  131. 'itemPrice' => $product->pricePostTaxes()->float,
  132. ];
  133. }
  134. return $cartItems;
  135. }
  136. /**
  137. * Y.K. has processed the payment and redirected the user back.
  138. *
  139. * @param PaymentResult $result
  140. *
  141. * @return PaymentResult
  142. */
  143. final public function complete(PaymentResult $result): PaymentResult
  144. {
  145. $this->setOrder($result->order);
  146. $gateway = $this->getGateway();
  147. try {
  148. /**
  149. * It will be similar to calling methods `completeAuthorize()` and `completePurchase()`
  150. */
  151. $response = $gateway->orderStatus(
  152. [
  153. 'orderId' => $result->order->payment_gateway_id, // gateway order number
  154. 'language' => 'ru'
  155. ]
  156. )->send();
  157. } catch (Throwable $e) {
  158. return $result->fail([], $e);
  159. }
  160. assert($response instanceof AbstractResponse);
  161. $data = (array)$response->getData();
  162. if ( ! $response->isSuccessful()) {
  163. return $result->fail($data, $response);
  164. }
  165. return $result->success($data, $response);
  166. }
  167. /**
  168. * Build the Omnipay Gateway for PayPal.
  169. *
  170. * @return \Omnipay\Common\GatewayInterface
  171. */
  172. final protected function getGateway(): Gateway
  173. {
  174. $gateway = Omnipay::create('Sberbank');
  175. $gateway->setUserName(PaymentGatewaySettings::get('username'));
  176. $gateway->setPassword(decrypt(PaymentGatewaySettings::get('password')));
  177. if (PaymentGatewaySettings::get('sber_test_mode')) {
  178. $gateway->setTestMode(true);
  179. }
  180. return $gateway;
  181. }
  182. /**
  183. * Return any custom backend settings fields.
  184. *
  185. * These fields will be rendered in the backend
  186. * settings page of your provider.
  187. *
  188. * @return array
  189. */
  190. final public function settings(): array
  191. {
  192. return [
  193. 'sber_test_mode' => [
  194. 'label' => 'wpstudio.sber::lang.settings.sber_test_mode',
  195. 'comment' => 'wpstudio.sber::lang.settings.sber_test_mode_label',
  196. 'span' => 'left',
  197. 'type' => 'switch',
  198. ],
  199. 'username' => [
  200. 'label' => Lang::get('wpstudio.sber::lang.settings.username'),
  201. 'comment' => Lang::get('wpstudio.sber::lang.settings.username_label'),
  202. 'span' => 'left',
  203. 'type' => 'text',
  204. ],
  205. 'password' => [
  206. 'label' => Lang::get('wpstudio.sber::lang.settings.password'),
  207. 'comment' => Lang::get('wpstudio.sber::lang.settings.password_label'),
  208. 'span' => 'left',
  209. 'type' => 'text',
  210. ],
  211. 'setPayedVirtualOrderAsComplete' => [
  212. 'label' => Lang::get('wpstudio.sber::lang.settings.set_payed_virtual_order_as_complete'),
  213. 'span' => 'left',
  214. 'type' => 'checkbox',
  215. ],
  216. ];
  217. }
  218. /**
  219. * Setting keys returned from this method are stored encrypted.
  220. *
  221. * Use this to store API tokens and other secret data
  222. * that is needed for this PaymentProvider to work.
  223. *
  224. * @return array
  225. */
  226. final public function encryptedSettings(): array
  227. {
  228. return ['password'];
  229. }
  230. /**
  231. * Getting order state id by flag
  232. *
  233. * @param $orderStateFlag
  234. * @return int
  235. */
  236. final protected function getOrderStateId($orderStateFlag): int
  237. {
  238. $orderStateModel = OrderState::where('flag', $orderStateFlag)->first();
  239. return $orderStateModel->id;
  240. }
  241. }