PluginProbe
seQura / 3.0.5
seQura v3.0.5
4.3.4 4.3.3 4.3.2 4.3.1 trunk 2.0.0 2.0.10 2.0.11 2.0.12 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 3.0.0 3.0.2 3.0.5 3.0.6 3.0.7 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 4.0.0 All 30 releases
sequra / src / Services / Payment / class-payment-method-service.php

class-payment-method-service.php in seQura 3.0.5, at src/Services/Payment/class-payment-method-service.php

336 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Payment method service
4 *
5 * @package SeQura/WC
6 * @subpackage SeQura/WC/Services
7 */
8
9 namespace SeQura\WC\Services\Payment;
10
11 use SeQura\Core\BusinessLogic\AdminAPI\AdminAPI;
12 use SeQura\Core\BusinessLogic\CheckoutAPI\CheckoutAPI;
13 use SeQura\Core\BusinessLogic\CheckoutAPI\Solicitation\Response\SolicitationResponse;
14 use SeQura\Core\BusinessLogic\Domain\Order\Models\SeQuraForm;
15 use SeQura\Core\Infrastructure\Logger\LogContextData;
16 use SeQura\WC\Core\Extension\BusinessLogic\Domain\Order\Builders\Interface_Create_Order_Request_Builder;
17 use SeQura\WC\Core\Extension\Infrastructure\Configuration\Configuration;
18 use SeQura\WC\Dto\Payment_Method_Data;
19 use SeQura\WC\Services\Interface_Logger_Service;
20 use SeQura\WC\Services\Order\Interface_Order_Service;
21 use Throwable;
22 use WC_Order;
23
24 /**
25 * Handle use cases related to payment methods
26 */
27 class Payment_Method_Service implements Interface_Payment_Method_Service {
28
29 /**
30 * Part payment
31 */
32 const PART_PAYMENT = 'part_payment';
33
34 /**
35 * Configuration
36 *
37 * @var Configuration
38 */
39 private $configuration;
40
41 /**
42 * Payment methods
43 *
44 * @var array<string, string>[]
45 */
46 private $payment_methods;
47
48 /**
49 * Create order request builder
50 *
51 * @var Interface_Create_Order_Request_Builder
52 */
53 private $create_order_request_builder;
54
55 /**
56 * Order service
57 *
58 * @var Interface_Order_Service
59 */
60 private $order_service;
61
62 /**
63 * Logger
64 *
65 * @var Interface_Logger_Service
66 */
67 private $logger;
68
69 /**
70 * Constructor
71 */
72 public function __construct(
73 Configuration $configuration,
74 Interface_Create_Order_Request_Builder $create_order_request_builder,
75 Interface_Order_Service $order_service,
76 Interface_Logger_Service $logger
77 ) {
78 $this->configuration = $configuration;
79 $this->create_order_request_builder = $create_order_request_builder;
80 $this->order_service = $order_service;
81 $this->logger = $logger;
82 }
83
84 /**
85 * Request solicitation
86 */
87 private function request_solicitation( ?WC_Order $order = null ): ?SolicitationResponse {
88 try {
89 $this->create_order_request_builder->set_current_order( $order );
90
91 if ( ! $this->create_order_request_builder->is_allowed() ) {
92 $ctx = $order ? array( new LogContextData( 'order_id', $order->get_id() ) ) : array();
93 $this->logger->log_debug( 'Order is not allowed for solicitation', __FUNCTION__, __CLASS__, $ctx );
94 return null;
95 }
96
97 $response = CheckoutAPI::get()
98 ->solicitation( $this->configuration->get_store_id() )
99 ->solicitFor( $this->create_order_request_builder );
100
101 if ( ! $response->isSuccessful() ) {
102 $ctx = $order ? array( new LogContextData( 'order_id', $order->get_id() ) ) : array();
103 $ctx[] = new LogContextData( 'response', $response->toArray() );
104 $this->logger->log_error( 'Solicitation response is not successful', __FUNCTION__, __CLASS__, $ctx );
105 }
106
107 return $response;
108 } catch ( Throwable $e ) {
109 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
110 return null;
111 }
112 }
113
114 /**
115 * Get identification form
116 */
117 public function get_identification_form( WC_Order $order ): ?SeQuraForm {
118
119 $response = $this->request_solicitation( $order );
120
121 if ( ! $response || ! $response->isSuccessful() ) {
122 return null;
123 }
124
125 /**
126 * Filter the options to be sent to seQura if needed
127 *
128 * @since 2.0.0
129 * */
130 $opts = apply_filters(
131 'wc_sequra_pumbaa_options',
132 array(
133 'product' => $this->order_service->get_product( $order ),
134 'campaign' => $this->order_service->get_campaign( $order ),
135 ),
136 $order,
137 array()
138 );
139
140 try {
141 $cart_info = $this->order_service->get_cart_info( $order );
142
143 if ( ! $cart_info ) {
144 $this->logger->log_error( 'Cart info is null', __FUNCTION__, __CLASS__, array( new LogContextData( 'order_id', $order->get_id() ) ) );
145 return null;
146 }
147
148 $response = CheckoutAPI::get()
149 ->solicitation( $this->configuration->get_store_id() )
150 ->getIdentificationForm(
151 $cart_info->ref,
152 isset( $opts['product'] ) && '' !== $opts['product'] ? $opts['product'] : null,
153 isset( $opts['campaign'] ) && '' !== $opts['campaign'] ? $opts['campaign'] : null
154 );
155
156 if ( ! $response ) {
157 $this->logger->log_error( 'Identification form response is null', __FUNCTION__, __CLASS__, array( new LogContextData( 'order_id', $order->get_id() ) ) );
158 return null;
159 }
160
161 if ( ! $response->isSuccessful() ) {
162 $this->logger->log_error(
163 'Identification form response is not successful',
164 __FUNCTION__,
165 __CLASS__,
166 array(
167 new LogContextData( 'response', $response->toArray() ),
168 new LogContextData( 'order_id', $order->get_id() ),
169 )
170 );
171 return null;
172 }
173
174 return $response->getIdentificationForm();
175 } catch ( Throwable $e ) {
176 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
177 return null;
178 }
179 }
180
181 /**
182 * Get payment methods
183 *
184 * @return array<string, string>[]
185 */
186 public function get_payment_methods( ?WC_Order $order = null ): array {
187 if ( null !== $this->payment_methods ) {
188 return $this->payment_methods;
189 }
190 // TODO: Implement a cache system to avoid multiple requests with the same payload.
191 $response = $this->request_solicitation( $order );
192
193 if ( ! $response || ! $response->isSuccessful() ) {
194 return array();
195 }
196
197 $this->payment_methods = $response->toArray()['availablePaymentMethods'] ?? array();
198 return $this->payment_methods;
199 }
200
201 /**
202 * Get a list of all payment methods defined for store and merchant
203 *
204 * @throws Throwable
205 *
206 * @return array<string, string>[]
207 */
208 public function get_all_payment_methods( ?string $store_id, ?string $merchant ): array {
209 if ( ! $store_id || ! $merchant ) {
210 return array();
211 }
212 try {
213 $response = AdminAPI::get()
214 ->paymentMethods( $store_id )
215 ->getPaymentMethods( strval( $merchant ) );
216
217 if ( ! $response->isSuccessful() ) {
218 return array();
219 }
220 $payment_methods = $response->toArray();
221
222 foreach ( $payment_methods as &$method ) {
223 $method['supportsWidgets'] = $this->supports_widgets( $method );
224 $method['supportsInstallmentPayments'] = $this->supports_installment_payments( $method );
225 }
226
227 return $payment_methods;
228 } catch ( Throwable $e ) {
229 $this->logger->log_throwable( $e, __FUNCTION__, __CLASS__ );
230 return array();
231 }
232 }
233
234 /**
235 * Look for available payment methods which can be used with the widget
236 *
237 * @throws Throwable
238 *
239 * @return array<string, string>[]
240 */
241 public function get_all_widget_compatible_payment_methods( string $store_id, ?string $merchant ): array {
242 $compatible_payment_methods = array();
243 foreach ( $this->get_all_payment_methods( $store_id, $merchant ) as $method ) {
244 if ( $method['supportsWidgets'] ) {
245 $compatible_payment_methods[] = $method;
246 }
247 }
248 return $compatible_payment_methods;
249 }
250
251 /**
252 * Look for available payment methods that can be used with part payments
253 *
254 * @throws Throwable
255 *
256 * @return array<string, string>[]
257 */
258 public function get_all_mini_widget_compatible_payment_methods( string $store_id, ?string $merchant ): array {
259 $compatible_payment_methods = array();
260 foreach ( $this->get_all_payment_methods( $store_id, $merchant ) as $method ) {
261 if ( $method['supportsInstallmentPayments'] ) {
262 $compatible_payment_methods[] = $method;
263 }
264 }
265 return $compatible_payment_methods;
266 }
267
268 /**
269 * Look for available payment methods which can be used with the widget
270 *
271 * @throws Throwable
272 *
273 * @return array<string, string>[]
274 */
275 public function get_cart_widget( string $store_id, ?string $merchant ): array {
276 $compatible_payment_methods = array();
277 foreach ( $this->get_all_payment_methods( $store_id, $merchant ) as $method ) {
278 if ( $method['supportsWidgets'] ) {
279 $compatible_payment_methods[] = $method;
280 }
281 }
282 return $compatible_payment_methods;
283 }
284
285 /**
286 * Check if the payment method can be displayed in the widget
287 *
288 * @param array<string, string> $method the payment method. Must contain 'product' at least.
289 */
290 private function supports_widgets( array $method ): bool {
291 return isset( $method['product'] ) && in_array( $method['product'], array( 'i1', 'pp5', 'pp3', 'pp6', 'pp9', 'sp1' ), true );
292 }
293
294 /**
295 * Check if the payment method represents a part payment
296 *
297 * @param array<string, string> $method the payment method. Must contain 'product' at least.
298 */
299 private function supports_installment_payments( array $method ): bool {
300 // phpcs:ignore
301 // return isset( $method['product'] ) && in_array( $method['product'], array( 'pp5', 'pp3', 'pp6', 'pp9', 'sp1' ), true );
302 return isset( $method['product'] ) && in_array( $method['product'], array( 'pp3' ), true );
303 }
304
305 /**
306 * Check if the payment method data matches a valid payment method.
307 */
308 public function is_payment_method_data_valid( Payment_Method_Data $data ): bool {
309 foreach ( $this->get_payment_methods() as $pm ) {
310 if ( $pm['product'] === $data->product && $pm['campaign'] === $data->campaign ) {
311 return true;
312 }
313 }
314 return false;
315 }
316
317 /**
318 * Check if the current page is the order pay page
319 */
320 public function is_order_pay_page(): bool {
321 return ( (int) strval( get_query_var( 'order-pay' ) ) ) > 0;
322 }
323
324 /**
325 * Check if the current page is the checkout page
326 */
327 public function is_checkout(): bool {
328 /**
329 * Check if current page is checkout
330 *
331 * @since 3.0.0
332 */
333 return (bool) apply_filters( 'sequra_is_checkout', is_checkout() || $this->is_order_pay_page() || WC()->is_store_api_request() );
334 }
335 }
336