PluginProbe
MultiSafepay plugin for WooCommerce / trunk
MultiSafepay plugin for WooCommerce vtrunk
6.11.1 6.12.0 6.13.0 6.2.0 6.2.1 6.3.0 6.3.1 6.4.0 6.4.1 6.4.2 6.4.3 6.5.0 6.5.1 6.6.0 6.6.1 6.6.2 6.7.0 6.7.1 6.7.2 6.7.3 6.8.0 6.8.1 6.8.2 6.8.3 6.9.0 All 84 releases
multisafepay / src / Services / Qr / QrOrderService.php

QrOrderService.php in MultiSafepay plugin for WooCommerce trunk, at src/Services/Qr/QrOrderService.php

224 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php declare(strict_types=1);
2
3 namespace MultiSafepay\WooCommerce\Services\Qr;
4
5 use MultiSafepay\Api\Transactions\Gateways as GatewaysSdk;
6 use MultiSafepay\Api\Transactions\OrderRequest;
7 use MultiSafepay\Api\Transactions\OrderRequest\Arguments\PaymentOptions;
8 use MultiSafepay\Api\Transactions\OrderRequest\Arguments\SecondChance;
9 use MultiSafepay\Exception\ApiException;
10 use MultiSafepay\Exception\InvalidArgumentException;
11 use MultiSafepay\WooCommerce\PaymentMethods\Base\BasePaymentMethod;
12 use MultiSafepay\WooCommerce\Services\OrderService;
13 use MultiSafepay\WooCommerce\Services\SdkService;
14 use MultiSafepay\WooCommerce\Utils\Logger;
15 use MultiSafepay\WooCommerce\Utils\MoneyUtil;
16 use Psr\Http\Client\ClientExceptionInterface;
17
18 /**
19 * Class QrOrderService
20 *
21 * @package MultiSafepay\WooCommerce\Services\Qr
22 */
23 class QrOrderService extends OrderService {
24
25 /**
26 * Expiration time for payment methods API request
27 */
28 public const EXPIRATION_TIME_CHECKOUT_QR_DATA = 86400;
29
30 /**
31 * @var QrCustomerService
32 */
33 public $qr_customer_service;
34
35 /**
36 * @var QrShoppingCartService
37 */
38 public $qr_shopping_cart_service;
39
40 /**
41 * @var Logger
42 */
43 private $logger;
44
45 /**
46 * ShoppingCartOrderService constructor.
47 */
48 public function __construct() {
49 parent::__construct();
50 $this->qr_customer_service = new QrCustomerService();
51 $this->qr_shopping_cart_service = new QrShoppingCartService();
52 $this->logger = new Logger();
53 }
54
55 /**
56 * @param string $order_id
57 * @param string $gateway_code
58 * @param string $payload
59 * @param array $checkout_fields
60 * @return OrderRequest
61 * @throws InvalidArgumentException
62 */
63 public function get_order_request(
64 string $order_id,
65 string $gateway_code,
66 string $payload,
67 array $checkout_fields
68 ): OrderRequest {
69 $cart = WC()->cart;
70 $order_request = new OrderRequest();
71 $order_request
72 ->addOrderId( $order_id )
73 ->addMoney( MoneyUtil::create_money( (float) $cart->get_total( 'edit' ), get_woocommerce_currency() ) )
74 ->addGatewayCode( $gateway_code )
75 ->addType( OrderRequest::DIRECT_TYPE )
76 ->addPluginDetails( $this->create_plugin_details() )
77 ->addDescriptionText( $this->get_order_description_text( $order_id ) )
78 ->addCustomer( $this->qr_customer_service->create_customer_details_from_cart( $checkout_fields['customer'] ) )
79 ->addPaymentOptions( $this->create_payment_options( $this->generate_token( $order_id ) ) )
80 ->addSecondsActive( $this->get_seconds_active() )
81 ->addSecondChance( ( new SecondChance() )->addSendEmail( (bool) get_option( 'multisafepay_second_chance', false ) ) )
82 ->addData( array( 'var2' => $order_id ) );
83
84 if ( $this->is_filled_shipping_address( $checkout_fields ) && WC()->cart->needs_shipping() ) {
85 $order_request->addDelivery( $this->qr_customer_service->create_customer_details_from_cart( $checkout_fields['customer'], 'shipping' ) );
86 }
87
88 if ( ! get_option( 'multisafepay_disable_shopping_cart', false ) || in_array( $gateway_code, GatewaysSdk::SHOPPING_CART_REQUIRED_GATEWAYS, true ) ) {
89 $order_request->addShoppingCart( $this->qr_shopping_cart_service->create_shopping_cart( $cart, get_woocommerce_currency() ) );
90 }
91
92 if ( ! empty( $payload ) ) {
93 $order_request->addData(
94 array(
95 'payment_data' => array(
96 'gateway' => $gateway_code,
97 'payload' => $payload,
98 ),
99 )
100 );
101 }
102
103 $order_request = $this->add_none_tax_rate( $order_request );
104
105 return apply_filters( 'multisafepay_order_request', $order_request );
106 }
107
108 /**
109 * Check if the shipping address is filled
110 *
111 * @param array $checkout_fields
112 * @return bool
113 */
114 public function is_filled_shipping_address( array $checkout_fields ): bool {
115 $filled_fields = $checkout_fields['customer']['shipping'] ?? array();
116 return ! empty( $filled_fields['address_1'] ) || ! empty( $filled_fields['address_2'] );
117 }
118
119 /**
120 * @param string $token
121 * @return PaymentOptions
122 */
123 public function create_payment_options( string $token ): PaymentOptions {
124 $redirect_cancel_url = add_query_arg( 'token', $token, get_rest_url( get_current_blog_id(), 'multisafepay/v1/qr-balancer' ) );
125 $payment_options = new PaymentOptions();
126 $payment_options->addNotificationUrl( get_rest_url( get_current_blog_id(), 'multisafepay/v1/qr-notification' ) );
127 $payment_options->addCancelUrl( $redirect_cancel_url );
128 $payment_options->addRedirectUrl( $redirect_cancel_url );
129 $payment_options->addSettings( array( 'qr' => array( 'enabled' => true ) ) );
130
131 return $payment_options;
132 }
133
134 /**
135 * Generate a token that will be used on validation of QR related endpoints
136 *
137 * @param string $order_id
138 * @return string
139 */
140 public function generate_token( string $order_id ) {
141 $token = wp_generate_password( 32, false );
142 set_transient( 'multisafepay_token_' . $order_id, $token, 86400 );
143 return $token;
144 }
145
146 /**
147 * Check if the QR data is valid
148 *
149 * @param array $qr_data
150 * @param string $order_id
151 * @return bool
152 */
153 public function is_valid_qr_data( array $qr_data, string $order_id ): bool {
154 $required_fields = array(
155 'image' => $qr_data['qr']['image'] ?? null,
156 'token' => $qr_data['qr']['params']['token'] ?? null,
157 'order_id' => $qr_data['order_id'] ?? null,
158 );
159
160 foreach ( $required_fields as $field => $value ) {
161 if ( empty( $value ) || ( ( 'order_id' === $field ) && ( (string) $value !== $order_id ) ) ) {
162 return false;
163 }
164 }
165
166 return true;
167 }
168
169 /**
170 * Generate a unique order ID for cart-based transactions
171 *
172 * @return string
173 */
174 public function generate_unique_order_id(): string {
175 return 'QR-' . uniqid( '', true );
176 }
177
178 /**
179 * Activate the QR code for the order
180 *
181 * @param BasePaymentMethod $payment_gateway
182 * @param string $payload
183 * @param array $checkout_fields
184 * @return array
185 * @throws InvalidArgumentException
186 */
187 public function place_order( BasePaymentMethod $payment_gateway, string $payload, array $checkout_fields ): array {
188 $order_id = $this->generate_unique_order_id();
189
190 // Create a transient using order ID and the checkout fields
191 set_transient( 'multisafepay_qr_order_' . $order_id, $checkout_fields, self::EXPIRATION_TIME_CHECKOUT_QR_DATA );
192
193 $order_request = $this->get_order_request(
194 $order_id,
195 $payment_gateway->get_payment_method_gateway_code(),
196 $payload,
197 $checkout_fields
198 );
199
200 $sdk = new SdkService();
201 $transaction_manager = $sdk->get_transaction_manager();
202
203 try {
204 $transaction = $transaction_manager->create( $order_request );
205 } catch ( ApiException |ClientExceptionInterface $exception ) {
206 $this->logger->log_error( $exception->getMessage() );
207 wc_add_notice( __( 'There was a problem processing your payment using a QR code. Please try again later or contact with us.', 'multisafepay' ), 'error' );
208 return array();
209 }
210
211 $payment_data = $transaction->getData();
212
213 $this->logger->log_info( 'Start MultiSafepay transaction for the order ID ' . $order_id . ' on ' . date( 'd/m/Y H:i:s' ) . ' with payment data ' . wp_json_encode( $payment_data ) );
214
215 if ( $this->is_valid_qr_data( $payment_data, $order_id ) ) {
216 return $payment_data;
217 }
218
219 $this->logger->log_error( 'QR code was not correct' );
220
221 return array();
222 }
223 }
224