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 / PaymentMethods / PaymentMethodsController.php

PaymentMethodsController.php in MultiSafepay plugin for WooCommerce trunk, at src/PaymentMethods/PaymentMethodsController.php

356 lines 13.6 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\PaymentMethods;
4
5 use Exception;
6 use MultiSafepay\Api\Transactions\TransactionResponse;
7 use MultiSafepay\Api\Transactions\UpdateRequest;
8 use MultiSafepay\Api\Wallets\ApplePay\MerchantSessionRequest;
9 use MultiSafepay\Exception\ApiException;
10 use MultiSafepay\Util\Notification;
11 use MultiSafepay\WooCommerce\Services\OrderService;
12 use MultiSafepay\WooCommerce\Services\PaymentMethodService;
13 use MultiSafepay\WooCommerce\Services\SdkService;
14 use MultiSafepay\WooCommerce\Utils\Hpos;
15 use MultiSafepay\WooCommerce\Utils\Logger;
16 use MultiSafepay\WooCommerce\Utils\Order as OrderUtil;
17 use MultiSafepay\WooCommerce\Utils\RestResponseBuilder;
18 use Psr\Http\Client\ClientExceptionInterface;
19 use WC_Data_Exception;
20 use WC_Order;
21 use WP_REST_Request;
22 use WP_REST_Response;
23
24 /**
25 * Defines all the methods needed to register related with Payment Methods actions and filters
26 */
27 class PaymentMethodsController {
28
29 public const VALIDATION_URL_KEY = 'validation_url';
30 public const ORIGIN_DOMAIN_KEY = 'origin_domain';
31
32 /**
33 * @var Logger
34 */
35 private $logger;
36
37 /**
38 * @param Logger|null $logger
39 */
40 public function __construct( ?Logger $logger = null ) {
41 $this->logger = $logger ?? new Logger();
42 }
43
44 /**
45 * Register the stylesheets related with the payment methods
46 *
47 * @see https://developer.wordpress.org/reference/functions/wp_enqueue_style/
48 *
49 * @return void
50 */
51 public function enqueue_styles(): void {
52 if ( is_checkout() ) {
53 wp_enqueue_style( 'multisafepay-public-css', MULTISAFEPAY_PLUGIN_URL . '/assets/public/css/multisafepay-public.css', array(), MULTISAFEPAY_PLUGIN_VERSION, 'all' );
54 }
55 }
56
57 /**
58 * Set the MultiSafepay transaction as shipped when the order
59 * status change to the one defined as shipped in the settings.
60 *
61 * @param int $order_id
62 * @return void
63 * @throws ClientExceptionInterface
64 */
65 public function set_multisafepay_transaction_as_shipped( int $order_id ): void {
66 $order = wc_get_order( $order_id );
67 if ( OrderUtil::is_multisafepay_order( $order ) ) {
68 $sdk = new SdkService();
69 $transaction_manager = $sdk->get_transaction_manager();
70 $update_order = new UpdateRequest();
71 $update_order->addStatus( 'shipped' );
72 try {
73 $transaction_manager->update( (string) $order->get_order_number(), $update_order );
74 } catch ( ApiException $api_exception ) {
75 $this->logger->log_error( $api_exception->getMessage() );
76 return;
77 }
78 }
79 }
80
81 /**
82 * Set the MultiSafepay transaction as invoiced when the order
83 * status change to the one defined as invoiced in the settings.
84 *
85 * @param int $order_id
86 * @return void
87 * @throws ClientExceptionInterface
88 */
89 public function set_multisafepay_transaction_as_invoiced( int $order_id ): void {
90 $order = wc_get_order( $order_id );
91 if ( OrderUtil::is_multisafepay_order( $order ) ) {
92 $sdk = new SdkService();
93 $transaction_manager = $sdk->get_transaction_manager();
94 $update_order = new UpdateRequest();
95 $update_order->addData( array( 'invoice_id' => $order->get_order_number() ) );
96 try {
97 $transaction_manager->update( (string) $order->get_order_number(), $update_order );
98 } catch ( ApiException $api_exception ) {
99 $this->logger->log_error( $api_exception->getMessage() );
100 return;
101 }
102 }
103 }
104
105 /**
106 * Catch the notification request.
107 *
108 * @return void
109 * @throws WC_Data_Exception
110 */
111 public function callback(): void {
112 $required_args = array( 'transactionid', 'timestamp' );
113 foreach ( $required_args as $arg ) {
114 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
115 if ( ! isset( $_GET[ $arg ] ) || empty( $_GET[ $arg ] ) ) {
116 wp_die( esc_html__( 'Invalid request', 'multisafepay' ), esc_html__( 'Invalid request', 'multisafepay' ), 400 );
117 }
118 }
119
120 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
121 if ( isset( $_GET['payload_type'] ) && 'pretransaction' === $_GET['payload_type'] ) {
122 wp_die( esc_html__( 'Invalid request', 'multisafepay' ), esc_html__( 'Invalid request', 'multisafepay' ), 400 );
123 }
124
125 // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotValidated
126 $transactionid = sanitize_text_field( (string) wp_unslash( $_GET['transactionid'] ) );
127 ( new PaymentMethodCallback( sanitize_text_field( (string) wp_unslash( $transactionid ) ) ) )->process_callback();
128 }
129
130 /**
131 * Process the POST notification
132 *
133 * @param WP_REST_Request $request
134 * @return WP_REST_Response
135 * @throws WC_Data_Exception
136 */
137 public function process_post_notification( WP_REST_Request $request ): WP_REST_Response {
138 $transactionid = $request->get_param( 'transactionid' );
139
140 if ( ! $request->sanitize_params() ) {
141 $this->logger->log_info( 'Notification for transactionid ' . $transactionid . ' has been received but could not be sanitized' );
142 return RestResponseBuilder::build_response();
143 }
144
145 $payload_type = $request->get_param( 'payload_type' ) ?? '';
146 if ( 'pretransaction' === $payload_type ) {
147 $this->logger->log_info( 'Notification for transactionid ' . $transactionid . ' has been received but is going to be ignored, because is pretransaction type' );
148 return RestResponseBuilder::build_response();
149 }
150
151 $auth = (string) ( $request->get_header( 'auth' ) ?? '' );
152 $body = $request->get_body();
153 $api_key = ( new SdkService() )->get_api_key();
154
155 if ( '' === $auth ) {
156 $this->logger->log_info( 'Notification for transactionid ' . $transactionid . ' has been received but auth header is missing' );
157 return RestResponseBuilder::build_response();
158 }
159
160 $verify_notification = Notification::verifyNotification( $body, $auth, $api_key );
161
162 if ( ! $verify_notification ) {
163 $this->logger->log_info( 'Notification for transactionid ' . $transactionid . ' has been received but is not validated' );
164 return RestResponseBuilder::build_response();
165 }
166
167 if ( get_option( 'multisafepay_debugmode', false ) ) {
168 $this->logger->log_info( 'Notification has been received and validated for transaction id ' . $transactionid );
169
170 if ( ! empty( $body ) ) {
171 $this->logger->log_info( 'Body of the POST notification: ' . wc_print_r( $body, true ) );
172 }
173 }
174
175 $multisafepay_transaction = new TransactionResponse( $request->get_json_params(), $body );
176 ( new PaymentMethodCallback( (string) $transactionid, $multisafepay_transaction ) )->process_callback();
177
178 return RestResponseBuilder::build_response();
179 }
180
181 /**
182 * Register the endpoint to handle the POST notification
183 *
184 * @return void
185 */
186 public function multisafepay_register_rest_route() {
187 $arguments = array(
188 'methods' => 'POST',
189 'callback' => array( $this, 'process_post_notification' ),
190 'permission_callback' => '__return_true',
191 );
192 register_rest_route(
193 'multisafepay/v1',
194 'notification',
195 $arguments
196 );
197 }
198
199 /**
200 * Action added to woocommerce_new_order hook.
201 * Takes an order generated in admin and pass the data to MultiSafepay to process the order request.
202 *
203 * @param int $order_id
204 *
205 * @return void
206 */
207 public function generate_orders_from_backend( int $order_id ): void {
208 $order = wc_get_order( $order_id );
209
210 // Check if the order is created in admin
211 if ( ! $order || ! $order->is_created_via( 'admin' ) ) {
212 return;
213 }
214
215 // Check if the payment method belongs to MultiSafepay
216 if ( ! OrderUtil::is_multisafepay_order( $order ) ) {
217 return;
218 }
219
220 // Create the order request and process the transaction
221 $sdk = new SdkService();
222 $transaction_manager = $sdk->get_transaction_manager();
223 $order_service = new OrderService();
224 $gateway_object = ( new PaymentMethodService() )->get_woocommerce_payment_gateway_by_id( $order->get_payment_method() );
225 if ( ! $gateway_object ) {
226 $this->logger->log_error( ' Gateway object is null ' );
227 return;
228 }
229 $gateway_code = $gateway_object->get_payment_method_gateway_code();
230 $order_request = $order_service->create_order_request( $order, $gateway_code, 'paymentlink' );
231
232 try {
233 $transaction = $transaction_manager->create( $order_request );
234 if ( $transaction->getPaymentUrl() ) {
235 // Update order metadata with the payment link
236 Hpos::update_meta( $order, 'payment_url', $transaction->getPaymentUrl() );
237 Hpos::update_meta( $order, 'send_payment_link', '1' );
238
239 if ( get_option( 'multisafepay_debugmode', false ) ) {
240 $message = 'Order details has been registered in MultiSafepay and a payment link has been generated: ' . esc_url( $transaction->getPaymentUrl() );
241 $this->logger->log_info( $message );
242 $order->add_order_note( $message );
243 }
244 }
245 } catch ( Exception |ApiException |ClientExceptionInterface $exception ) {
246 $this->logger->log_error( $exception->getMessage() );
247 }
248 }
249
250 /**
251 * Get the Apple Pay session arguments
252 *
253 * @return void
254 */
255 public function applepay_direct_validation(): void {
256 $apple_session_arguments = $this->get_apple_pay_session_arguments();
257
258 try {
259 $waller_manager = ( new SdkService() )->get_sdk()->getWalletManager();
260 $apple_pay_merchant_session_request = ( new MerchantSessionRequest() )
261 ->addValidationUrl( $apple_session_arguments[ self::VALIDATION_URL_KEY ] )
262 ->addOriginDomain( $apple_session_arguments[ self::ORIGIN_DOMAIN_KEY ] );
263
264 wp_send_json(
265 $waller_manager->createApplePayMerchantSession(
266 $apple_pay_merchant_session_request
267 )->getMerchantSession()
268 );
269 } catch ( ApiException |Exception |ClientExceptionInterface $exception ) {
270 $error_message = 'Error when trying to get the ApplePay session via MultiSafepay SDK';
271 $this->logger->log_error( $error_message . ': ' . $exception->getMessage() );
272 wp_send_json( array( 'message' => $error_message ) );
273 }
274 }
275
276 /**
277 * Get the updated total price to be used
278 * by Google Pay, and Apple Pay direct
279 *
280 * @return void
281 */
282 public function get_updated_total_price(): void {
283 $total_price_nonce = sanitize_key( $_POST['nonce'] ?? '' );
284 if ( ! wp_verify_nonce( wp_unslash( $total_price_nonce ), 'total_price_nonce' ) ) {
285 wp_send_json( array() );
286 }
287 wp_send_json(
288 array(
289 'totalPrice' => ( WC()->cart ) ? ( WC()->cart->get_total( '' ) * 100 ) : null,
290 )
291 );
292 }
293
294 /**
295 * Validate the required input and return the values
296 *
297 * @return array
298 */
299 private function get_apple_pay_session_arguments(): array {
300 $validation_url = esc_url_raw( wp_unslash( $_POST['validation_url'] ?? '' ) );
301 $origin_domain_parse = wp_parse_url( esc_url_raw( wp_unslash( $_POST['origin_domain'] ?? '' ) ) );
302 $origin_domain = $origin_domain_parse['host'];
303
304 if ( empty( $validation_url ) ) {
305 $this->logger->log_error( 'Error when trying to get the ApplePay session. Validation URL empty' );
306 exit;
307 }
308
309 if ( empty( $origin_domain ) ) {
310 $this->logger->log_error( 'Error when trying to get the ApplePay session. Origin domain empty' );
311 exit;
312 }
313
314 return array(
315 self::VALIDATION_URL_KEY => $validation_url,
316 self::ORIGIN_DOMAIN_KEY => $origin_domain,
317 );
318 }
319
320 /**
321 * Add a link to the MultiSafepay transaction ID in the order details page
322 *
323 * @param WC_Order $order
324 * @return void
325 */
326 public function add_multisafepay_transaction_link( WC_Order $order ): void {
327 $transaction_id = $order->get_transaction_id();
328 $environment = $order->get_meta( '_multisafepay_order_environment' );
329
330 if ( empty( $transaction_id ) || ! is_numeric( $transaction_id ) || empty( $environment ) ) {
331 return;
332 }
333
334 $test_mode = 'test' === $environment;
335 $url = 'https://' . ( $test_mode ? 'testmerchant' : 'merchant' ) . '.multisafepay.com/transaction/' . $transaction_id;
336
337 wp_enqueue_script(
338 'multisafepay-admin',
339 MULTISAFEPAY_PLUGIN_URL . '/assets/admin/js/multisafepay-admin.js',
340 array( 'jquery' ),
341 MULTISAFEPAY_PLUGIN_VERSION,
342 true
343 );
344
345 wp_localize_script(
346 'multisafepay-admin',
347 'multisafepayAdminData',
348 array(
349 'transactionUrl' => esc_url( $url ),
350 'transactionLinkTitle' => __( 'View transaction in the MultiSafepay dashboard', 'multisafepay' ),
351 )
352 );
353 }
354
355 }
356