From 18220769a2bd9b990bd830b97756d019eddba5b6 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 7 Mar 2022 12:54:02 +0100 Subject: [PATCH 001/163] Introduce pay upon invoice gateway (WIP) --- .../ppcp-wc-gateway/resources/js/fraudnet.js | 8 ++ modules/ppcp-wc-gateway/services.php | 17 +++ .../Gateway/PayUponInvoice/OrderEndpoint.php | 120 ++++++++++++++++++ .../PayUponInvoice/PayUponInvoiceGateway.php | 96 ++++++++++++++ .../ppcp-wc-gateway/src/WCGatewayModule.php | 22 ++++ modules/ppcp-wc-gateway/webpack.config.js | 1 + 6 files changed, 264 insertions(+) create mode 100644 modules/ppcp-wc-gateway/resources/js/fraudnet.js create mode 100644 modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php create mode 100644 modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php diff --git a/modules/ppcp-wc-gateway/resources/js/fraudnet.js b/modules/ppcp-wc-gateway/resources/js/fraudnet.js new file mode 100644 index 000000000..11a74b1c5 --- /dev/null +++ b/modules/ppcp-wc-gateway/resources/js/fraudnet.js @@ -0,0 +1,8 @@ +document.addEventListener('DOMContentLoaded', () => { + const script = document.createElement('script'); + script.setAttribute('src', 'https://c.paypal.com/da/r/fb.js'); + + console.log(script) + + document.body.append(script); +}); diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 22bb3715f..ca52026d1 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -29,6 +29,8 @@ use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint; use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\OrderEndpoint; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider; use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus; use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus; @@ -2118,4 +2120,19 @@ return array( $container->get( 'wcgateway.settings' ) ); }, + 'wcgateway.pay-upon-invoice-order-endpoint' => static function (ContainerInterface $container): OrderEndpoint { + return new OrderEndpoint( + $container->get( 'api.host' ), + $container->get( 'api.bearer' ), + $container->get( 'api.factory.order' ), + $container->get( 'woocommerce.logger.woocommerce' ) + ); + }, + 'wcgateway.pay-upon-invoice-gateway' => static function (ContainerInterface $container): PayUponInvoiceGateway { + return new PayUponInvoiceGateway( + $container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ), + $container->get( 'api.factory.purchase-unit' ), + $container->get( 'woocommerce.logger.woocommerce' ) + ); + }, ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php new file mode 100644 index 000000000..6ef341b6b --- /dev/null +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -0,0 +1,120 @@ +host = $host; + $this->bearer = $bearer; + $this->order_factory = $order_factory; + $this->logger = $logger; + } + + /** + * Creates an order. + * + * @param PurchaseUnit[] $items The purchase unit items for the order. + * @return Order + */ + public function create( array $items ): Order { + $data = array( + 'intent' => 'CAPTURE', + 'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL', + 'purchase_units' => array_map( + static function ( PurchaseUnit $item ): array { + return $item->to_array(); + }, + $items + ), + 'payment_source' => array ( + 'pay_upon_invoice' => array( + 'name' => array( + 'given_name' => 'John', + 'surname' => 'Doe', + ), + 'email' => 'buyer@example.com', + 'birth_date' => '1990-01-01', + 'phone' => array( + 'national_number' => '6912345678', + 'country_code' => '49', + ), + 'billing_address' => array( + 'address_line_1' => 'Schönhauser Allee 84', + 'admin_area_2' => 'Berlin', + 'postal_code' => '10439', + 'country_code' => 'DE', + ), + 'experience_context' => array( + 'locale' => 'en-DE', + 'brand_name' => 'EXAMPLE INC', + 'logo_url' => 'https://example.com/logoUrl.svg', + 'customer_service_instructions' => array( + 'Customer service phone is +49 6912345678.', + ), + ), + ), + ), + ); + + $bearer = $this->bearer->bearer(); + $url = trailingslashit( $this->host ) . 'v2/checkout/orders'; + $args = array( + 'method' => 'POST', + 'headers' => array( + 'Authorization' => 'Bearer ' . $bearer->token(), + 'Content-Type' => 'application/json', + 'Prefer' => 'return=representation', + 'PayPal-Client-Metadata-Id' => 'd4e0d7b9-4f75-43f9-9437-d8a57c901585', + 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), + ), + 'body' => wp_json_encode( $data ), + ); + + $response = $this->request( $url, $args ); + if ( is_wp_error( $response ) ) { + throw new RuntimeException($response->get_error_message()); + } + + $json = json_decode( $response['body'] ); + $status_code = (int) wp_remote_retrieve_response_code( $response ); + if ( 201 !== $status_code ) { + throw new PayPalApiException($json, $status_code); + } + + return $this->order_factory->from_paypal_response( $json ); + } +} diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php new file mode 100644 index 000000000..a81f7f535 --- /dev/null +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -0,0 +1,96 @@ +id = self::ID; + + $this->method_title = __('Pay Upon Invoice', 'woocommerce-paypal-payments'); + $this->method_description = __('Once you place an order, pay within 30 days. Our payment partner Ratepay will send you payment instructions.', 'woocommerce-paypal-payments'); + $this->title = $this->method_title; + $this->description = $this->method_description; + + $this->init_form_fields(); + $this->init_settings(); + + add_action( + 'woocommerce_update_options_payment_gateways_' . $this->id, + array( + $this, + 'process_admin_options', + ) + ); + + $this->order_endpoint = $order_endpoint; + $this->purchase_unit_factory = $purchase_unit_factory; + $this->logger = $logger; + } + + /** + * Initialize the form fields. + */ + public function init_form_fields() { + $this->form_fields = array( + 'enabled' => array( + 'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ), + 'type' => 'checkbox', + 'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ), + 'default' => 'yes' + ), + ); + } + + public function process_payment($order_id) + { + $wc_order = new WC_Order( $order_id ); + $wc_order->update_status('on-hold', __('Awaiting Pay Upon Invoice payment', 'woocommerce-paypal-payments')); + + $purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order ); + + try { + $this->order_endpoint->create(array( $purchase_unit )); + } catch (RuntimeException $exception) { + $error = $exception->getMessage(); + $this->logger->error($error); + + // TODO display error in the screen + } + } +} diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index 8ec2f9965..854da583d 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -205,6 +205,9 @@ class WCGatewayModule implements ModuleInterface { if ( $dcc_applies->for_country_currency() ) { $methods[] = $container->get( 'wcgateway.credit-card-gateway' ); } + + $methods[] = $container->get('wcgateway.pay-upon-invoice-gateway'); + return (array) $methods; } ); @@ -268,6 +271,25 @@ class WCGatewayModule implements ModuleInterface { return $disabler->handler( (array) $methods ); } ); + + add_action('wp_footer', function () { ?> + + get('wcgateway.url'); + wp_enqueue_script( + 'ppcp-fraudnet', + trailingslashit($gateway_module_url) . 'assets/js/fraudnet.js', + array(), + 1 + ); + }); } /** diff --git a/modules/ppcp-wc-gateway/webpack.config.js b/modules/ppcp-wc-gateway/webpack.config.js index c9c6c2b55..fcc5648bb 100644 --- a/modules/ppcp-wc-gateway/webpack.config.js +++ b/modules/ppcp-wc-gateway/webpack.config.js @@ -7,6 +7,7 @@ module.exports = { target: 'web', entry: { 'gateway-settings': path.resolve('./resources/js/gateway-settings.js'), + 'fraudnet': path.resolve('./resources/js/fraudnet.js'), }, output: { path: path.resolve(__dirname, 'assets/'), From da523884d63cf005fc9cc92a2766025ff56a8fb2 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 7 Mar 2022 14:49:41 +0100 Subject: [PATCH 002/163] Handle error when creating order --- .../Gateway/PayUponInvoice/OrderEndpoint.php | 56 +++++++++---------- .../PayUponInvoice/PayUponInvoiceGateway.php | 16 +++++- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php index 6ef341b6b..090aa72d5 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -37,11 +37,11 @@ class OrderEndpoint { */ protected $logger; - public function __construct( string $host, Bearer $bearer, OrderFactory $order_factory, LoggerInterface $logger) { - $this->host = $host; - $this->bearer = $bearer; + public function __construct( string $host, Bearer $bearer, OrderFactory $order_factory, LoggerInterface $logger ) { + $this->host = $host; + $this->bearer = $bearer; $this->order_factory = $order_factory; - $this->logger = $logger; + $this->logger = $logger; } /** @@ -52,36 +52,36 @@ class OrderEndpoint { */ public function create( array $items ): Order { $data = array( - 'intent' => 'CAPTURE', + 'intent' => 'CAPTURE', 'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL', - 'purchase_units' => array_map( + 'purchase_units' => array_map( static function ( PurchaseUnit $item ): array { return $item->to_array(); }, $items ), - 'payment_source' => array ( + 'payment_source' => array( 'pay_upon_invoice' => array( - 'name' => array( + 'name' => array( 'given_name' => 'John', - 'surname' => 'Doe', + 'surname' => 'Doe', ), - 'email' => 'buyer@example.com', - 'birth_date' => '1990-01-01', - 'phone' => array( + 'email' => 'buyer@example.com', + 'birth_date' => '1990-01-01', + 'phone' => array( 'national_number' => '6912345678', - 'country_code' => '49', + 'country_code' => '49', ), - 'billing_address' => array( + 'billing_address' => array( 'address_line_1' => 'Schönhauser Allee 84', - 'admin_area_2' => 'Berlin', - 'postal_code' => '10439', - 'country_code' => 'DE', + 'admin_area_2' => 'Berlin', + 'postal_code' => '10439', + 'country_code' => 'DE', ), 'experience_context' => array( - 'locale' => 'en-DE', - 'brand_name' => 'EXAMPLE INC', - 'logo_url' => 'https://example.com/logoUrl.svg', + 'locale' => 'en-DE', + 'brand_name' => 'EXAMPLE INC', + 'logo_url' => 'https://example.com/logoUrl.svg', 'customer_service_instructions' => array( 'Customer service phone is +49 6912345678.', ), @@ -91,28 +91,28 @@ class OrderEndpoint { ); $bearer = $this->bearer->bearer(); - $url = trailingslashit( $this->host ) . 'v2/checkout/orders'; - $args = array( + $url = trailingslashit( $this->host ) . 'v2/checkout/orders'; + $args = array( 'method' => 'POST', 'headers' => array( - 'Authorization' => 'Bearer ' . $bearer->token(), - 'Content-Type' => 'application/json', - 'Prefer' => 'return=representation', + 'Authorization' => 'Bearer ' . $bearer->token(), + 'Content-Type' => 'application/json', + 'Prefer' => 'return=representation', 'PayPal-Client-Metadata-Id' => 'd4e0d7b9-4f75-43f9-9437-d8a57c901585', - 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), + 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), ), 'body' => wp_json_encode( $data ), ); $response = $this->request( $url, $args ); if ( is_wp_error( $response ) ) { - throw new RuntimeException($response->get_error_message()); + throw new RuntimeException( $response->get_error_message() ); } $json = json_decode( $response['body'] ); $status_code = (int) wp_remote_retrieve_response_code( $response ); if ( 201 !== $status_code ) { - throw new PayPalApiException($json, $status_code); + throw new PayPalApiException( $json, $status_code ); } return $this->order_factory->from_paypal_response( $json ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index a81f7f535..0dd36afe1 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -79,7 +79,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { public function process_payment($order_id) { - $wc_order = new WC_Order( $order_id ); + $wc_order = wc_get_order( $order_id ); $wc_order->update_status('on-hold', __('Awaiting Pay Upon Invoice payment', 'woocommerce-paypal-payments')); $purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order ); @@ -88,9 +88,19 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { $this->order_endpoint->create(array( $purchase_unit )); } catch (RuntimeException $exception) { $error = $exception->getMessage(); - $this->logger->error($error); - // TODO display error in the screen + $this->logger->error($error); + wc_add_notice( $error, 'error' ); + + $wc_order->update_status( + 'failed', + $error + ); + + return array( + 'result' => 'failure', + 'redirect' => wc_get_checkout_url(), + ); } } } From 2e9cc0b8af5e91df2e0417e1bcbfa97372b65ce1 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Tue, 8 Mar 2022 11:43:05 +0100 Subject: [PATCH 003/163] Pass hardcoded session id to test order creation --- modules/ppcp-wc-gateway/resources/js/fraudnet.js | 3 --- .../src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php | 1 - modules/ppcp-wc-gateway/src/WCGatewayModule.php | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/modules/ppcp-wc-gateway/resources/js/fraudnet.js b/modules/ppcp-wc-gateway/resources/js/fraudnet.js index 11a74b1c5..a9b735fde 100644 --- a/modules/ppcp-wc-gateway/resources/js/fraudnet.js +++ b/modules/ppcp-wc-gateway/resources/js/fraudnet.js @@ -1,8 +1,5 @@ document.addEventListener('DOMContentLoaded', () => { const script = document.createElement('script'); script.setAttribute('src', 'https://c.paypal.com/da/r/fb.js'); - - console.log(script) - document.body.append(script); }); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index 0dd36afe1..864c83329 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -11,7 +11,6 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice; use Psr\Log\LoggerInterface; use RuntimeException; -use WC_Order; use WC_Payment_Gateway; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index 854da583d..0176e4362 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -275,7 +275,7 @@ class WCGatewayModule implements ModuleInterface { add_action('wp_footer', function () { ?> From 00de9de57e7661cca83cedc6a1df9bbe6ea646e7 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Tue, 8 Mar 2022 12:33:59 +0100 Subject: [PATCH 004/163] Display pay upon invoice gateway only if store country is germany --- .../ppcp-wc-gateway/src/WCGatewayModule.php | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index 0176e4362..2285a6cc7 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -206,7 +206,9 @@ class WCGatewayModule implements ModuleInterface { $methods[] = $container->get( 'wcgateway.credit-card-gateway' ); } - $methods[] = $container->get('wcgateway.pay-upon-invoice-gateway'); + if ( 'DE' === $container->get( 'api.shop.country' ) ) { + $methods[] = $container->get( 'wcgateway.pay-upon-invoice-gateway' ); + } return (array) $methods; } @@ -272,24 +274,35 @@ class WCGatewayModule implements ModuleInterface { } ); - add_action('wp_footer', function () { ?> + add_action( + 'wp_footer', + function () use ( $container ) { + if ( 'DE' === $container->get( 'api.shop.country' ) ) { ?> - get('wcgateway.url'); - wp_enqueue_script( - 'ppcp-fraudnet', - trailingslashit($gateway_module_url) . 'assets/js/fraudnet.js', - array(), - 1 - ); - }); + add_action( + 'wp_enqueue_scripts', + function () use ( $container ) { + if ( 'DE' === $container->get( 'api.shop.country' ) ) { + $gateway_module_url = $container->get( 'wcgateway.url' ); + wp_enqueue_script( + 'ppcp-fraudnet', + trailingslashit( $gateway_module_url ) . 'assets/js/fraudnet.js', + array(), + 1 + ); + } + } + ); } /** From 6c7eef4f58c47897b03f58d6f2e8689fd00518a0 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Wed, 9 Mar 2022 12:01:27 +0100 Subject: [PATCH 005/163] Display legal text under place order button --- .../ppcp-wc-gateway/resources/js/fraudnet.js | 5 -- .../resources/js/pay-upon-invoice.js | 12 ++++ .../ppcp-wc-gateway/src/WCGatewayModule.php | 70 +++++++++++-------- modules/ppcp-wc-gateway/webpack.config.js | 2 +- 4 files changed, 53 insertions(+), 36 deletions(-) delete mode 100644 modules/ppcp-wc-gateway/resources/js/fraudnet.js create mode 100644 modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js diff --git a/modules/ppcp-wc-gateway/resources/js/fraudnet.js b/modules/ppcp-wc-gateway/resources/js/fraudnet.js deleted file mode 100644 index a9b735fde..000000000 --- a/modules/ppcp-wc-gateway/resources/js/fraudnet.js +++ /dev/null @@ -1,5 +0,0 @@ -document.addEventListener('DOMContentLoaded', () => { - const script = document.createElement('script'); - script.setAttribute('src', 'https://c.paypal.com/da/r/fb.js'); - document.body.append(script); -}); diff --git a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js new file mode 100644 index 000000000..d5671fab9 --- /dev/null +++ b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js @@ -0,0 +1,12 @@ +document.addEventListener('DOMContentLoaded', () => { + const script = document.createElement('script'); + script.setAttribute('src', 'https://c.paypal.com/da/r/fb.js'); + document.body.append(script); + + jQuery(document.body).on('updated_checkout payment_method_selected', () => { + jQuery('#ppcp-pui-legal-text').hide(); + if(jQuery('input[name="payment_method"]:checked').val() === 'ppcp-pay-upon-invoice-gateway') { + jQuery('#ppcp-pui-legal-text').show(); + } + }); +}); diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index 2285a6cc7..5fbaa30f6 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -182,6 +182,46 @@ class WCGatewayModule implements ModuleInterface { } } ); + + if ( 'DE' === $c->get( 'api.shop.country' ) ) { + add_action( + 'wp_footer', + function () { + ?> + + get( 'wcgateway.url' ); + wp_enqueue_script( + 'ppcp-pay-upon-invoice', + trailingslashit( $gateway_module_url ) . 'assets/js/pay-upon-invoice.js', + array(), + 1 + ); + } + ); + + add_action( + 'woocommerce_review_order_after_submit', + function () { + // TODO show/hide via JS + ?> + + handler( (array) $methods ); } ); - - add_action( - 'wp_footer', - function () use ( $container ) { - if ( 'DE' === $container->get( 'api.shop.country' ) ) { ?> - - get( 'api.shop.country' ) ) { - $gateway_module_url = $container->get( 'wcgateway.url' ); - wp_enqueue_script( - 'ppcp-fraudnet', - trailingslashit( $gateway_module_url ) . 'assets/js/fraudnet.js', - array(), - 1 - ); - } - } - ); } /** diff --git a/modules/ppcp-wc-gateway/webpack.config.js b/modules/ppcp-wc-gateway/webpack.config.js index fcc5648bb..5abb1f94a 100644 --- a/modules/ppcp-wc-gateway/webpack.config.js +++ b/modules/ppcp-wc-gateway/webpack.config.js @@ -7,7 +7,7 @@ module.exports = { target: 'web', entry: { 'gateway-settings': path.resolve('./resources/js/gateway-settings.js'), - 'fraudnet': path.resolve('./resources/js/fraudnet.js'), + 'pay-upon-invoice': path.resolve('./resources/js/pay-upon-invoice.js'), }, output: { path: path.resolve(__dirname, 'assets/'), From f8d25a9357458b655878951701d9587af734271d Mon Sep 17 00:00:00 2001 From: dinamiko Date: Wed, 9 Mar 2022 12:51:11 +0100 Subject: [PATCH 006/163] Display legal text from gateway settings --- .../PayUponInvoice/PayUponInvoiceGateway.php | 5 ++ .../ppcp-wc-gateway/src/WCGatewayModule.php | 74 ++++++++++--------- 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index 864c83329..2504d8ff7 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -73,6 +73,11 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { 'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ), 'default' => 'yes' ), + 'legal_text' => array( + 'title' => __( 'Legal text', 'woocommerce-paypal-payments' ), + 'type' => 'textarea', + 'default' => 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', + ), ); } diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index 5fbaa30f6..280678937 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -183,45 +183,51 @@ class WCGatewayModule implements ModuleInterface { } ); - if ( 'DE' === $c->get( 'api.shop.country' ) ) { - add_action( - 'wp_footer', - function () { - ?> - + - get( 'wcgateway.url' ); + wp_enqueue_script( + 'ppcp-pay-upon-invoice', + trailingslashit( $gateway_module_url ) . 'assets/js/pay-upon-invoice.js', + array(), + 1 + ); + } + ); - add_action( - 'wp_enqueue_scripts', - function () use ( $c ) { - $gateway_module_url = $c->get( 'wcgateway.url' ); - wp_enqueue_script( - 'ppcp-pay-upon-invoice', - trailingslashit( $gateway_module_url ) . 'assets/js/pay-upon-invoice.js', - array(), - 1 + add_action( + 'woocommerce_review_order_after_submit', + function () { + $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' ); + ?> + + - - Date: Wed, 9 Mar 2022 16:23:03 +0100 Subject: [PATCH 007/163] Get fraudNet session id from WC session --- .../resources/js/pay-upon-invoice.js | 4 -- modules/ppcp-wc-gateway/services.php | 20 ++++++ .../src/Gateway/PayUponInvoice/FraudNet.php | 38 +++++++++++ .../PayUponInvoice/FraudNetSessionId.php | 18 ++++++ .../Gateway/PayUponInvoice/OrderEndpoint.php | 15 ++++- .../Gateway/PayUponInvoice/PayUponInvoice.php | 63 +++++++++++++++++++ .../ppcp-wc-gateway/src/WCGatewayModule.php | 43 +------------ 7 files changed, 155 insertions(+), 46 deletions(-) create mode 100644 modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNet.php create mode 100644 modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php create mode 100644 modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php diff --git a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js index d5671fab9..db862b962 100644 --- a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js +++ b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js @@ -1,8 +1,4 @@ document.addEventListener('DOMContentLoaded', () => { - const script = document.createElement('script'); - script.setAttribute('src', 'https://c.paypal.com/da/r/fb.js'); - document.body.append(script); - jQuery(document.body).on('updated_checkout payment_method_selected', () => { jQuery('#ppcp-pui-legal-text').hide(); if(jQuery('input[name="payment_method"]:checked').val() === 'ppcp-pay-upon-invoice-gateway') { diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index ca52026d1..9d635fab8 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -29,7 +29,10 @@ use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint; use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNet; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNetSessionId; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\OrderEndpoint; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoice; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider; use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus; @@ -2125,6 +2128,7 @@ return array( $container->get( 'api.host' ), $container->get( 'api.bearer' ), $container->get( 'api.factory.order' ), + $container->get('wcgateway.pay-upon-invoice-fraudnet'), $container->get( 'woocommerce.logger.woocommerce' ) ); }, @@ -2135,4 +2139,20 @@ return array( $container->get( 'woocommerce.logger.woocommerce' ) ); }, + 'wcgateway.pay-upon-invoice-fraudnet-session-id' => static function (ContainerInterface $container): FraudNetSessionId { + return new FraudNetSessionId(); + }, + 'wcgateway.pay-upon-invoice-fraudnet' => static function (ContainerInterface $container): FraudNet { + $session_id = $container->get('wcgateway.pay-upon-invoice-fraudnet-session-id'); + return new FraudNet( + (string)$session_id(), + 'bar' + ); + }, + 'wcgateway.pay-upon-invoice' => static function (ContainerInterface $container): PayUponInvoice { + return new PayUponInvoice( + $container->get('wcgateway.url'), + $container->get('wcgateway.pay-upon-invoice-fraudnet') + ); + } ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNet.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNet.php new file mode 100644 index 000000000..b6ddf43a1 --- /dev/null +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNet.php @@ -0,0 +1,38 @@ +session_id = $session_id; + $this->source_website_id = $source_website_id; + } + + /** + * @return string + */ + public function sessionId(): string + { + return $this->session_id; + } + + /** + * @return string + */ + public function sourceWebsiteId(): string + { + return $this->source_website_id; + } +} diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php new file mode 100644 index 000000000..7e138d13f --- /dev/null +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php @@ -0,0 +1,18 @@ +session->get( 'ppcp_fraudnet_session_id' )) { + return WC()->session->get( 'ppcp_fraudnet_session_id' ); + } + + $session_id = bin2hex(random_bytes(16)); + WC()->session->set( 'ppcp_fraudnet_session_id', $session_id); + + return bin2hex($session_id); + } +} diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php index 090aa72d5..74877be59 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -36,12 +36,23 @@ class OrderEndpoint { * @var LoggerInterface */ protected $logger; + /** + * @var FraudNet + */ + protected $fraudNet; - public function __construct( string $host, Bearer $bearer, OrderFactory $order_factory, LoggerInterface $logger ) { + public function __construct( + string $host, + Bearer $bearer, + OrderFactory $order_factory, + FraudNet $fraudNet, + LoggerInterface $logger + ) { $this->host = $host; $this->bearer = $bearer; $this->order_factory = $order_factory; $this->logger = $logger; + $this->fraudNet = $fraudNet; } /** @@ -98,7 +109,7 @@ class OrderEndpoint { 'Authorization' => 'Bearer ' . $bearer->token(), 'Content-Type' => 'application/json', 'Prefer' => 'return=representation', - 'PayPal-Client-Metadata-Id' => 'd4e0d7b9-4f75-43f9-9437-d8a57c901585', + 'PayPal-Client-Metadata-Id' => $this->fraudNet->sessionId(), 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), ), 'body' => wp_json_encode( $data ), diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php new file mode 100644 index 000000000..1a27480e0 --- /dev/null +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -0,0 +1,63 @@ +module_url = $module_url; + $this->fraud_net = $fraud_net; + } + + public function init() { + add_action( + 'wp_footer', + array( $this, 'add_parameter_block' ) + ); + + add_action( + 'woocommerce_review_order_after_submit', + array( $this, 'add_legal_text' ) + ); + + add_action( + 'wp_enqueue_scripts', + array( $this, 'register_assets' ) + ); + } + + public function add_parameter_block() { ?> + + + + + module_url ) . 'assets/js/pay-upon-invoice.js', + array(), + 1 + ); + } +} diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index 280678937..460863398 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -185,46 +185,9 @@ class WCGatewayModule implements ModuleInterface { add_action( 'init', - function() use ( $c ) { - if ( 'DE' === $c->get( 'api.shop.country' ) ) { // TODO && is_checkout() does not work, we are on admin-ajax.php - - add_action( - 'wp_footer', - function () { - ?> - - get( 'wcgateway.url' ); - wp_enqueue_script( - 'ppcp-pay-upon-invoice', - trailingslashit( $gateway_module_url ) . 'assets/js/pay-upon-invoice.js', - array(), - 1 - ); - } - ); - - add_action( - 'woocommerce_review_order_after_submit', - function () { - $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' ); - ?> - - get( 'api.shop.country' ) ) { + ($c->get('wcgateway.pay-upon-invoice'))->init(); } } ); From da3272e68762fcc1143b90945897cde2b9f87dcc Mon Sep 17 00:00:00 2001 From: dinamiko Date: Wed, 9 Mar 2022 17:22:17 +0100 Subject: [PATCH 008/163] Add pui payment source entity (WIP) --- modules/ppcp-wc-gateway/services.php | 93 ++++++------ .../src/Gateway/PayUponInvoice/FraudNet.php | 15 +- .../PayUponInvoice/FraudNetSessionId.php | 15 +- .../Gateway/PayUponInvoice/OrderEndpoint.php | 40 ++---- .../PayUponInvoice/PayUponInvoiceGateway.php | 54 +++---- .../Gateway/PayUponInvoice/PaymentSource.php | 135 ++++++++++++++++++ .../PayUponInvoice/PaymentSourceFactory.php | 13 ++ .../ppcp-wc-gateway/src/WCGatewayModule.php | 4 +- 8 files changed, 250 insertions(+), 119 deletions(-) create mode 100644 modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSource.php create mode 100644 modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 9d635fab8..816201e48 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -32,6 +32,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNet; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNetSessionId; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\OrderEndpoint; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PaymentSourceFactory; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoice; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider; @@ -50,7 +51,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer; use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage; return array( - 'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway { + 'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway { $order_processor = $container->get( 'wcgateway.order-processor' ); $settings_renderer = $container->get( 'wcgateway.settings.render' ); $funding_source_renderer = $container->get( 'wcgateway.funding-source.renderer' ); @@ -86,7 +87,7 @@ return array( $order_endpoint ); }, - 'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway { + 'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway { $order_processor = $container->get( 'wcgateway.order-processor' ); $settings_renderer = $container->get( 'wcgateway.settings.render' ); $authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' ); @@ -124,18 +125,18 @@ return array( $payments_endpoint ); }, - 'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways { + 'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways { $session_handler = $container->get( 'session.handler' ); $settings = $container->get( 'wcgateway.settings' ); return new DisableGateways( $session_handler, $settings ); }, - 'wcgateway.is-wc-payments-page' => static function ( ContainerInterface $container ): bool { + 'wcgateway.is-wc-payments-page' => static function ( ContainerInterface $container ): bool { $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; $tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : ''; return 'wc-settings' === $page && 'checkout' === $tab; }, - 'wcgateway.is-ppcp-settings-page' => static function ( ContainerInterface $container ): bool { + 'wcgateway.is-ppcp-settings-page' => static function ( ContainerInterface $container ): bool { if ( ! $container->get( 'wcgateway.is-wc-payments-page' ) ) { return false; } @@ -144,7 +145,7 @@ return array( return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID ), true ); }, - 'wcgateway.current-ppcp-settings-page-id' => static function ( ContainerInterface $container ): string { + 'wcgateway.current-ppcp-settings-page-id' => static function ( ContainerInterface $container ): string { if ( ! $container->get( 'wcgateway.is-ppcp-settings-page' ) ) { return ''; } @@ -155,33 +156,33 @@ return array( return $ppcp_tab ? $ppcp_tab : $section; }, - 'wcgateway.settings' => static function ( ContainerInterface $container ): Settings { + 'wcgateway.settings' => static function ( ContainerInterface $container ): Settings { return new Settings(); }, - 'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice { + 'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice { $state = $container->get( 'onboarding.state' ); $settings = $container->get( 'wcgateway.settings' ); return new ConnectAdminNotice( $state, $settings ); }, - 'wcgateway.notice.dcc-without-paypal' => static function ( ContainerInterface $container ): DccWithoutPayPalAdminNotice { + 'wcgateway.notice.dcc-without-paypal' => static function ( ContainerInterface $container ): DccWithoutPayPalAdminNotice { $state = $container->get( 'onboarding.state' ); $settings = $container->get( 'wcgateway.settings' ); $is_payments_page = $container->get( 'wcgateway.is-wc-payments-page' ); $is_ppcp_settings_page = $container->get( 'wcgateway.is-ppcp-settings-page' ); return new DccWithoutPayPalAdminNotice( $state, $settings, $is_payments_page, $is_ppcp_settings_page ); }, - 'wcgateway.notice.authorize-order-action' => + 'wcgateway.notice.authorize-order-action' => static function ( ContainerInterface $container ): AuthorizeOrderActionNotice { return new AuthorizeOrderActionNotice(); }, - 'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer { + 'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer { return new SectionsRenderer( $container->get( 'wcgateway.current-ppcp-settings-page-id' ) ); }, - 'wcgateway.settings.status' => static function ( ContainerInterface $container ): SettingsStatus { + 'wcgateway.settings.status' => static function ( ContainerInterface $container ): SettingsStatus { $settings = $container->get( 'wcgateway.settings' ); return new SettingsStatus( $settings ); }, - 'wcgateway.settings.render' => static function ( ContainerInterface $container ): SettingsRenderer { + 'wcgateway.settings.render' => static function ( ContainerInterface $container ): SettingsRenderer { $settings = $container->get( 'wcgateway.settings' ); $state = $container->get( 'onboarding.state' ); $fields = $container->get( 'wcgateway.settings.fields' ); @@ -201,7 +202,7 @@ return array( $page_id ); }, - 'wcgateway.settings.listener' => static function ( ContainerInterface $container ): SettingsListener { + 'wcgateway.settings.listener' => static function ( ContainerInterface $container ): SettingsListener { $settings = $container->get( 'wcgateway.settings' ); $fields = $container->get( 'wcgateway.settings.fields' ); $webhook_registrar = $container->get( 'webhook.registrar' ); @@ -211,7 +212,7 @@ return array( $page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' ); return new SettingsListener( $settings, $fields, $webhook_registrar, $cache, $state, $bearer, $page_id ); }, - 'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor { + 'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor { $session_handler = $container->get( 'session.handler' ); $order_endpoint = $container->get( 'api.endpoint.order' ); @@ -232,36 +233,36 @@ return array( $environment ); }, - 'wcgateway.processor.refunds' => static function ( ContainerInterface $container ): RefundProcessor { + 'wcgateway.processor.refunds' => static function ( ContainerInterface $container ): RefundProcessor { $order_endpoint = $container->get( 'api.endpoint.order' ); $payments_endpoint = $container->get( 'api.endpoint.payments' ); $logger = $container->get( 'woocommerce.logger.woocommerce' ); return new RefundProcessor( $order_endpoint, $payments_endpoint, $logger ); }, - 'wcgateway.processor.authorized-payments' => static function ( ContainerInterface $container ): AuthorizedPaymentsProcessor { + 'wcgateway.processor.authorized-payments' => static function ( ContainerInterface $container ): AuthorizedPaymentsProcessor { $order_endpoint = $container->get( 'api.endpoint.order' ); $payments_endpoint = $container->get( 'api.endpoint.payments' ); $logger = $container->get( 'woocommerce.logger.woocommerce' ); $notice = $container->get( 'wcgateway.notice.authorize-order-action' ); return new AuthorizedPaymentsProcessor( $order_endpoint, $payments_endpoint, $logger, $notice ); }, - 'wcgateway.admin.render-authorize-action' => static function ( ContainerInterface $container ): RenderAuthorizeAction { + 'wcgateway.admin.render-authorize-action' => static function ( ContainerInterface $container ): RenderAuthorizeAction { $column = $container->get( 'wcgateway.admin.orders-payment-status-column' ); return new RenderAuthorizeAction( $column ); }, - 'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail { + 'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail { $column = $container->get( 'wcgateway.admin.orders-payment-status-column' ); return new PaymentStatusOrderDetail( $column ); }, - 'wcgateway.admin.orders-payment-status-column' => static function ( ContainerInterface $container ): OrderTablePaymentStatusColumn { + 'wcgateway.admin.orders-payment-status-column' => static function ( ContainerInterface $container ): OrderTablePaymentStatusColumn { $settings = $container->get( 'wcgateway.settings' ); return new OrderTablePaymentStatusColumn( $settings ); }, - 'wcgateway.admin.fees-renderer' => static function ( ContainerInterface $container ): FeesRenderer { + 'wcgateway.admin.fees-renderer' => static function ( ContainerInterface $container ): FeesRenderer { return new FeesRenderer(); }, - 'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array { + 'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array { $state = $container->get( 'onboarding.state' ); assert( $state instanceof State ); @@ -2058,28 +2059,28 @@ return array( return $fields; }, - 'wcgateway.checkout.address-preset' => static function( ContainerInterface $container ): CheckoutPayPalAddressPreset { + 'wcgateway.checkout.address-preset' => static function( ContainerInterface $container ): CheckoutPayPalAddressPreset { return new CheckoutPayPalAddressPreset( $container->get( 'session.handler' ) ); }, - 'wcgateway.url' => static function ( ContainerInterface $container ): string { + 'wcgateway.url' => static function ( ContainerInterface $container ): string { return plugins_url( $container->get( 'wcgateway.relative-path' ), dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php' ); }, - 'wcgateway.relative-path' => static function( ContainerInterface $container ): string { + 'wcgateway.relative-path' => static function( ContainerInterface $container ): string { return 'modules/ppcp-wc-gateway/'; }, - 'wcgateway.absolute-path' => static function( ContainerInterface $container ): string { + 'wcgateway.absolute-path' => static function( ContainerInterface $container ): string { return plugin_dir_path( dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php' ) . $container->get( 'wcgateway.relative-path' ); }, - 'wcgateway.endpoint.return-url' => static function ( ContainerInterface $container ) : ReturnUrlEndpoint { + 'wcgateway.endpoint.return-url' => static function ( ContainerInterface $container ) : ReturnUrlEndpoint { $gateway = $container->get( 'wcgateway.paypal-gateway' ); $endpoint = $container->get( 'api.endpoint.order' ); $prefix = $container->get( 'api.prefix' ); @@ -2090,69 +2091,73 @@ return array( ); }, - 'wcgateway.transaction-url-sandbox' => static function ( ContainerInterface $container ): string { + 'wcgateway.transaction-url-sandbox' => static function ( ContainerInterface $container ): string { return 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s'; }, - 'wcgateway.transaction-url-live' => static function ( ContainerInterface $container ): string { + 'wcgateway.transaction-url-live' => static function ( ContainerInterface $container ): string { return 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s'; }, - 'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider { + 'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider { $sandbox_url_base = $container->get( 'wcgateway.transaction-url-sandbox' ); $live_url_base = $container->get( 'wcgateway.transaction-url-live' ); return new TransactionUrlProvider( $sandbox_url_base, $live_url_base ); }, - 'wcgateway.helper.dcc-product-status' => static function ( ContainerInterface $container ) : DCCProductStatus { + 'wcgateway.helper.dcc-product-status' => static function ( ContainerInterface $container ) : DCCProductStatus { $settings = $container->get( 'wcgateway.settings' ); $partner_endpoint = $container->get( 'api.endpoint.partners' ); return new DCCProductStatus( $settings, $partner_endpoint ); }, - 'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers { + 'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers { return new MessagesDisclaimers( $container->get( 'api.shop.country' ) ); }, - 'wcgateway.funding-source.renderer' => function ( ContainerInterface $container ) : FundingSourceRenderer { + 'wcgateway.funding-source.renderer' => function ( ContainerInterface $container ) : FundingSourceRenderer { return new FundingSourceRenderer( $container->get( 'wcgateway.settings' ) ); }, - 'wcgateway.pay-upon-invoice-order-endpoint' => static function (ContainerInterface $container): OrderEndpoint { + 'wcgateway.pay-upon-invoice-order-endpoint' => static function ( ContainerInterface $container ): OrderEndpoint { return new OrderEndpoint( $container->get( 'api.host' ), $container->get( 'api.bearer' ), $container->get( 'api.factory.order' ), - $container->get('wcgateway.pay-upon-invoice-fraudnet'), + $container->get( 'wcgateway.pay-upon-invoice-fraudnet' ), $container->get( 'woocommerce.logger.woocommerce' ) ); }, - 'wcgateway.pay-upon-invoice-gateway' => static function (ContainerInterface $container): PayUponInvoiceGateway { + 'wcgateway.pay-upon-invoice-payment-source-factory' => static function ( ContainerInterface $container ): PaymentSourceFactory { + return new PaymentSourceFactory(); + }, + 'wcgateway.pay-upon-invoice-gateway' => static function ( ContainerInterface $container ): PayUponInvoiceGateway { return new PayUponInvoiceGateway( $container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ), $container->get( 'api.factory.purchase-unit' ), + $container->get( 'wcgateway.pay-upon-invoice-payment-source-factory' ), $container->get( 'woocommerce.logger.woocommerce' ) ); }, - 'wcgateway.pay-upon-invoice-fraudnet-session-id' => static function (ContainerInterface $container): FraudNetSessionId { + 'wcgateway.pay-upon-invoice-fraudnet-session-id' => static function ( ContainerInterface $container ): FraudNetSessionId { return new FraudNetSessionId(); }, - 'wcgateway.pay-upon-invoice-fraudnet' => static function (ContainerInterface $container): FraudNet { - $session_id = $container->get('wcgateway.pay-upon-invoice-fraudnet-session-id'); + 'wcgateway.pay-upon-invoice-fraudnet' => static function ( ContainerInterface $container ): FraudNet { + $session_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-session-id' ); return new FraudNet( - (string)$session_id(), + (string) $session_id(), 'bar' ); }, - 'wcgateway.pay-upon-invoice' => static function (ContainerInterface $container): PayUponInvoice { + 'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice { return new PayUponInvoice( - $container->get('wcgateway.url'), - $container->get('wcgateway.pay-upon-invoice-fraudnet') + $container->get( 'wcgateway.url' ), + $container->get( 'wcgateway.pay-upon-invoice-fraudnet' ) ); - } + }, ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNet.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNet.php index b6ddf43a1..5591ebf54 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNet.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNet.php @@ -2,8 +2,8 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice; -class FraudNet -{ +class FraudNet { + /** * @var string */ @@ -14,25 +14,22 @@ class FraudNet */ protected $source_website_id; - public function __construct(string $session_id, string $source_website_id) - { - $this->session_id = $session_id; + public function __construct( string $session_id, string $source_website_id ) { + $this->session_id = $session_id; $this->source_website_id = $source_website_id; } /** * @return string */ - public function sessionId(): string - { + public function sessionId(): string { return $this->session_id; } /** * @return string */ - public function sourceWebsiteId(): string - { + public function sourceWebsiteId(): string { return $this->source_website_id; } } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php index 7e138d13f..9decb845f 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php @@ -2,17 +2,16 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice; -class FraudNetSessionId -{ - public function __invoke() - { - if(WC()->session->get( 'ppcp_fraudnet_session_id' )) { +class FraudNetSessionId { + + public function __invoke() { + if ( WC()->session->get( 'ppcp_fraudnet_session_id' ) ) { return WC()->session->get( 'ppcp_fraudnet_session_id' ); } - $session_id = bin2hex(random_bytes(16)); - WC()->session->set( 'ppcp_fraudnet_session_id', $session_id); + $session_id = bin2hex( random_bytes( 16 ) ); + WC()->session->set( 'ppcp_fraudnet_session_id', $session_id ); - return bin2hex($session_id); + return $session_id; } } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php index 74877be59..338a67351 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -32,15 +32,16 @@ class OrderEndpoint { */ protected $order_factory; - /** - * @var LoggerInterface - */ - protected $logger; /** * @var FraudNet */ protected $fraudNet; + /** + * @var LoggerInterface + */ + protected $logger; + public function __construct( string $host, Bearer $bearer, @@ -52,7 +53,7 @@ class OrderEndpoint { $this->bearer = $bearer; $this->order_factory = $order_factory; $this->logger = $logger; - $this->fraudNet = $fraudNet; + $this->fraudNet = $fraudNet; } /** @@ -61,7 +62,7 @@ class OrderEndpoint { * @param PurchaseUnit[] $items The purchase unit items for the order. * @return Order */ - public function create( array $items ): Order { + public function create( array $items, PaymentSource $payment_source ): Order { $data = array( 'intent' => 'CAPTURE', 'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL', @@ -72,32 +73,7 @@ class OrderEndpoint { $items ), 'payment_source' => array( - 'pay_upon_invoice' => array( - 'name' => array( - 'given_name' => 'John', - 'surname' => 'Doe', - ), - 'email' => 'buyer@example.com', - 'birth_date' => '1990-01-01', - 'phone' => array( - 'national_number' => '6912345678', - 'country_code' => '49', - ), - 'billing_address' => array( - 'address_line_1' => 'Schönhauser Allee 84', - 'admin_area_2' => 'Berlin', - 'postal_code' => '10439', - 'country_code' => 'DE', - ), - 'experience_context' => array( - 'locale' => 'en-DE', - 'brand_name' => 'EXAMPLE INC', - 'logo_url' => 'https://example.com/logoUrl.svg', - 'customer_service_instructions' => array( - 'Customer service phone is +49 6912345678.', - ), - ), - ), + 'pay_upon_invoice' => $payment_source->to_array(), ), ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index 2504d8ff7..5037ddc9b 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -28,6 +28,11 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { */ protected $purchase_unit_factory; + /** + * @var PaymentSourceFactory + */ + protected $payment_source_factory; + /** * @var LoggerInterface */ @@ -36,15 +41,15 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { public function __construct( OrderEndpoint $order_endpoint, PurchaseUnitFactory $purchase_unit_factory, + PaymentSourceFactory $payment_source_factory, LoggerInterface $logger - ) - { - $this->id = self::ID; + ) { + $this->id = self::ID; - $this->method_title = __('Pay Upon Invoice', 'woocommerce-paypal-payments'); - $this->method_description = __('Once you place an order, pay within 30 days. Our payment partner Ratepay will send you payment instructions.', 'woocommerce-paypal-payments'); - $this->title = $this->method_title; - $this->description = $this->method_description; + $this->method_title = __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' ); + $this->method_description = __( 'Once you place an order, pay within 30 days. Our payment partner Ratepay will send you payment instructions.', 'woocommerce-paypal-payments' ); + $this->title = $this->method_title; + $this->description = $this->method_description; $this->init_form_fields(); $this->init_settings(); @@ -57,9 +62,10 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { ) ); - $this->order_endpoint = $order_endpoint; - $this->purchase_unit_factory = $purchase_unit_factory; - $this->logger = $logger; + $this->order_endpoint = $order_endpoint; + $this->purchase_unit_factory = $purchase_unit_factory; + $this->payment_source_factory = $payment_source_factory; + $this->logger = $logger; } /** @@ -67,33 +73,33 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { */ public function init_form_fields() { $this->form_fields = array( - 'enabled' => array( - 'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ), - 'type' => 'checkbox', - 'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ), - 'default' => 'yes' + 'enabled' => array( + 'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ), + 'type' => 'checkbox', + 'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ), + 'default' => 'yes', ), 'legal_text' => array( - 'title' => __( 'Legal text', 'woocommerce-paypal-payments' ), - 'type' => 'textarea', + 'title' => __( 'Legal text', 'woocommerce-paypal-payments' ), + 'type' => 'textarea', 'default' => 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', ), ); } - public function process_payment($order_id) - { + public function process_payment( $order_id ) { $wc_order = wc_get_order( $order_id ); - $wc_order->update_status('on-hold', __('Awaiting Pay Upon Invoice payment', 'woocommerce-paypal-payments')); + $wc_order->update_status( 'on-hold', __( 'Awaiting Pay Upon Invoice payment', 'woocommerce-paypal-payments' ) ); - $purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order ); + $purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order ); + $payment_source = $this->payment_source_factory->from_wc_order( $wc_order ); try { - $this->order_endpoint->create(array( $purchase_unit )); - } catch (RuntimeException $exception) { + $this->order_endpoint->create( array( $purchase_unit ), $payment_source ); + } catch ( RuntimeException $exception ) { $error = $exception->getMessage(); - $this->logger->error($error); + $this->logger->error( $error ); wc_add_notice( $error, 'error' ); $wc_order->update_status( diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSource.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSource.php new file mode 100644 index 000000000..8b7cf5aeb --- /dev/null +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSource.php @@ -0,0 +1,135 @@ +given_name = $given_name; + $this->surname = $surname; + $this->email = $email; + $this->birth_date = $birth_date; + $this->national_number = $national_number; + $this->phone_country_code = $phone_country_code; + $this->address_line_1 = $address_line_1; + $this->admin_area_2 = $admin_area_2; + $this->postal_code = $postal_code; + $this->country_code = $country_code; + $this->locale = $locale; + $this->brand_name = $brand_name; + $this->logo_url = $logo_url; + $this->customer_service_instructions = $customer_service_instructions; + } + + public function to_array(): array { + return array( + 'name' => array( + 'given_name' => $this->given_name, + 'surname' => $this->surname, + ), + 'email' => $this->email, + 'birth_date' => $this->birth_date, + 'phone' => array( + 'national_number' => $this->national_number, + 'country_code' => $this->phone_country_code, + ), + 'billing_address' => array( + 'address_line_1' => $this->address_line_1, + 'admin_area_2' => $this->admin_area_2, + 'postal_code' => $this->postal_code, + 'country_code' => $this->country_code, + ), + 'experience_context' => array( + 'locale' => $this->locale, + 'brand_name' => $this->brand_name, + 'logo_url' => $this->logo_url, + 'customer_service_instructions' => $this->customer_service_instructions, + ), + ); + } +} diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php new file mode 100644 index 000000000..e9b05a8e6 --- /dev/null +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php @@ -0,0 +1,13 @@ +get( 'api.shop.country' ) ) { - ($c->get('wcgateway.pay-upon-invoice'))->init(); + ( $c->get( 'wcgateway.pay-upon-invoice' ) )->init(); } } ); From 19e4a6444554abd6f44ed60a9864c8b764e9436d Mon Sep 17 00:00:00 2001 From: dinamiko Date: Thu, 10 Mar 2022 14:41:07 +0100 Subject: [PATCH 009/163] Add birth date field to checkout form --- .../PayUponInvoice/FraudNetSessionId.php | 4 + .../Gateway/PayUponInvoice/PayUponInvoice.php | 12 ++ .../Gateway/PayUponInvoice/PaymentSource.php | 140 ++++++++++++++++-- .../PayUponInvoice/PaymentSourceFactory.php | 20 ++- 4 files changed, 161 insertions(+), 15 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php index 9decb845f..701ad3292 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSessionId.php @@ -5,6 +5,10 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice; class FraudNetSessionId { public function __invoke() { + if(WC()->session === null) { + return ''; + } + if ( WC()->session->get( 'ppcp_fraudnet_session_id' ) ) { return WC()->session->get( 'ppcp_fraudnet_session_id' ); } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 1a27480e0..d2d76241a 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -36,6 +36,18 @@ class PayUponInvoice { 'wp_enqueue_scripts', array( $this, 'register_assets' ) ); + + add_filter( 'woocommerce_billing_fields', function($billing_fields) { + $billing_fields['billing_birth_date'] = array( + 'type' => 'date', + 'label' => __('Birth date', 'woocommerce-paypal-payments'), + 'class' => array('form-row-wide'), + 'required' => true, + 'clear' => true, + ); + + return $billing_fields; + }); } public function add_parameter_block() { ?> diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSource.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSource.php index 8b7cf5aeb..bfd51ed44 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSource.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSource.php @@ -106,29 +106,141 @@ class PaymentSource { $this->customer_service_instructions = $customer_service_instructions; } + /** + * @return string + */ + public function given_name(): string + { + return $this->given_name; + } + + /** + * @return string + */ + public function surname(): string + { + return $this->surname; + } + + /** + * @return string + */ + public function email(): string + { + return $this->email; + } + + /** + * @return string + */ + public function birth_date(): string + { + return $this->birth_date; + } + + /** + * @return string + */ + public function national_number(): string + { + return $this->national_number; + } + + /** + * @return string + */ + public function phone_country_code(): string + { + return $this->phone_country_code; + } + + /** + * @return string + */ + public function address_line_1(): string + { + return $this->address_line_1; + } + + /** + * @return string + */ + public function admin_area_2(): string + { + return $this->admin_area_2; + } + + /** + * @return string + */ + public function postal_code(): string + { + return $this->postal_code; + } + + /** + * @return string + */ + public function country_code(): string + { + return $this->country_code; + } + + /** + * @return string + */ + public function locale(): string + { + return $this->locale; + } + + /** + * @return string + */ + public function brand_name(): string + { + return $this->brand_name; + } + + /** + * @return string + */ + public function logo_url(): string + { + return $this->logo_url; + } + + /** + * @return array + */ + public function customer_service_instructions(): array + { + return $this->customer_service_instructions; + } + public function to_array(): array { return array( 'name' => array( - 'given_name' => $this->given_name, - 'surname' => $this->surname, + 'given_name' => $this->given_name(), + 'surname' => $this->surname(), ), - 'email' => $this->email, - 'birth_date' => $this->birth_date, + 'email' => $this->email(), + 'birth_date' => $this->birth_date(), 'phone' => array( - 'national_number' => $this->national_number, - 'country_code' => $this->phone_country_code, + 'national_number' => $this->national_number(), + 'country_code' => $this->phone_country_code(), ), 'billing_address' => array( - 'address_line_1' => $this->address_line_1, - 'admin_area_2' => $this->admin_area_2, - 'postal_code' => $this->postal_code, - 'country_code' => $this->country_code, + 'address_line_1' => $this->address_line_1(), + 'admin_area_2' => $this->admin_area_2(), + 'postal_code' => $this->postal_code(), + 'country_code' => $this->country_code(), ), 'experience_context' => array( - 'locale' => $this->locale, - 'brand_name' => $this->brand_name, - 'logo_url' => $this->logo_url, - 'customer_service_instructions' => $this->customer_service_instructions, + 'locale' => $this->locale(), + 'brand_name' => $this->brand_name(), + 'logo_url' => $this->logo_url(), + 'customer_service_instructions' => $this->customer_service_instructions(), ), ); } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php index e9b05a8e6..81c005bd7 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php @@ -8,6 +8,24 @@ class PaymentSourceFactory { public function from_wc_order( WC_Order $order ) { - return new PaymentSource(); + $address = $order->get_address(); + $birth_date = filter_input( INPUT_POST, 'billing_birth_date', FILTER_SANITIZE_STRING ); + + return new PaymentSource( + $address['first_name'] ?? '', + $address['last_name'] ?? '', + $address['email'] ?? '', + $birth_date, + $address['phone'] ?? '', + '49', + $address['address_1'] ?? '', + $address['city'] ?? '', + $address['postcode'] ?? '', + $address['country'] ?? '', + 'en-DE', + 'EXAMPLE INC', + 'https://example.com/logoUrl.svg', + array('Customer service phone is +49 6912345678.') + ); } } From 9dfa15acfc6965c7f96792a9ee70fb038739d3b7 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 11 Mar 2022 12:33:49 +0100 Subject: [PATCH 010/163] Add `PAY_UPON_INVOICE` into `capabiliies` (WIP) --- .../src/Entity/OrderStatus.php | 8 +++---- .../src/Repository/PartnerReferralsData.php | 23 ++++++++++++++++++- .../Gateway/PayUponInvoice/OrderEndpoint.php | 11 ++++++++- .../PayUponInvoice/PayUponInvoiceGateway.php | 7 ++++++ .../PayUponInvoice/PaymentSourceFactory.php | 3 +-- 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/modules/ppcp-api-client/src/Entity/OrderStatus.php b/modules/ppcp-api-client/src/Entity/OrderStatus.php index e8e33cba8..397ae8b64 100644 --- a/modules/ppcp-api-client/src/Entity/OrderStatus.php +++ b/modules/ppcp-api-client/src/Entity/OrderStatus.php @@ -15,21 +15,21 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; * Class OrderStatus */ class OrderStatus { - - const INTERNAL = 'INTERNAL'; const CREATED = 'CREATED'; const SAVED = 'SAVED'; const APPROVED = 'APPROVED'; const VOIDED = 'VOIDED'; const COMPLETED = 'COMPLETED'; - const VALID_STATI = array( + const PENDING_APPROVAL = 'PENDING_APPROVAL'; + const VALID_STATUS = array( self::INTERNAL, self::CREATED, self::SAVED, self::APPROVED, self::VOIDED, self::COMPLETED, + self::PENDING_APPROVAL, ); /** @@ -46,7 +46,7 @@ class OrderStatus { * @throws RuntimeException When the status is not valid. */ public function __construct( string $status ) { - if ( ! in_array( $status, self::VALID_STATI, true ) ) { + if ( ! in_array( $status, self::VALID_STATUS, true ) ) { throw new RuntimeException( sprintf( // translators: %s is the current status. diff --git a/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php b/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php index e2a13c949..307317711 100644 --- a/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php +++ b/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php @@ -91,7 +91,7 @@ class PartnerReferralsData { ), 'show_add_credit_card' => true, ), - 'products' => $this->products, + //'products' => $this->products, 'legal_consents' => array( array( 'type' => 'SHARE_DATA_CONSENT', @@ -119,6 +119,27 @@ class PartnerReferralsData { ), ), ), + "products" => [ + "PAYMENT_METHODS" + ], + "capabilities" => [ + "PAY_UPON_INVOICE" + ], + "business_entity" => array( + "business_type" => array( + "type" => "INDIVIDUAL" + ), + "addresses" => array( + array( + "address_line_1" => "Parkstr. 26", + "admin_area_1" => "Berlin", + "postal_code" => "90409", + "country_code" => "DE", + "type" => "WORK", + ), + ), + ), + "tracking_id" => "testenterprices123122", ); } } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php index 338a67351..2ad775049 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -77,6 +77,15 @@ class OrderEndpoint { ), ); + $data['purchase_units'][0]['items'][0]['tax_rate'] = '19.00'; + $data['purchase_units'][0]['shipping']['name']['full_name'] = 'John Doe'; + $data['purchase_units'][0]['shipping']['address'] = array( + 'address_line_1' => 'Taunusanlage 12', + 'admin_area_2' => 'FRANKFURT AM MAIN', + 'postal_code' => '60325', + 'country_code' => 'DE', + ); + $bearer = $this->bearer->bearer(); $url = trailingslashit( $this->host ) . 'v2/checkout/orders'; $args = array( @@ -98,7 +107,7 @@ class OrderEndpoint { $json = json_decode( $response['body'] ); $status_code = (int) wp_remote_retrieve_response_code( $response ); - if ( 201 !== $status_code ) { + if ( ! in_array($status_code, [200,201] ) ) { throw new PayPalApiException( $json, $status_code ); } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index 5037ddc9b..5a6e147d0 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -96,6 +96,13 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { try { $this->order_endpoint->create( array( $purchase_unit ), $payment_source ); + + WC()->cart->empty_cart(); + + return array( + 'result' => 'success', + 'redirect' => $this->get_return_url( $wc_order ), + ); } catch ( RuntimeException $exception ) { $error = $exception->getMessage(); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php index 81c005bd7..378e1e618 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php @@ -7,7 +7,6 @@ use WC_Order; class PaymentSourceFactory { public function from_wc_order( WC_Order $order ) { - $address = $order->get_address(); $birth_date = filter_input( INPUT_POST, 'billing_birth_date', FILTER_SANITIZE_STRING ); @@ -15,7 +14,7 @@ class PaymentSourceFactory { $address['first_name'] ?? '', $address['last_name'] ?? '', $address['email'] ?? '', - $birth_date, + $birth_date ?? '', $address['phone'] ?? '', '49', $address['address_1'] ?? '', From 61973a62234daa02eafdbdbb0cf87a74d35fd40a Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 11 Mar 2022 15:21:48 +0100 Subject: [PATCH 011/163] Set pui partner referrals config through filter --- .../src/Repository/PartnerReferralsData.php | 104 ++++++++---------- .../Gateway/PayUponInvoice/PayUponInvoice.php | 7 ++ 2 files changed, 50 insertions(+), 61 deletions(-) diff --git a/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php b/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php index 307317711..d8ada8567 100644 --- a/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php +++ b/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php @@ -72,74 +72,56 @@ class PartnerReferralsData { * @return array */ public function data(): array { - return array( - 'partner_config_override' => array( - 'partner_logo_url' => 'https://connect.woocommerce.com/images/woocommerce_logo.png', - /** - * Returns the URL which will be opened at the end of onboarding. - */ - 'return_url' => apply_filters( - 'woocommerce_paypal_payments_partner_config_override_return_url', - admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' ) + return apply_filters( + 'ppcp_partner_referrals_data', + array( + 'partner_config_override' => array( + 'partner_logo_url' => 'https://connect.woocommerce.com/images/woocommerce_logo.png', + /** + * Returns the URL which will be opened at the end of onboarding. + */ + 'return_url' => apply_filters( + 'woocommerce_paypal_payments_partner_config_override_return_url', + admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' ) + ), + /** + * Returns the description of the URL which will be opened at the end of onboarding. + */ + 'return_url_description' => apply_filters( + 'woocommerce_paypal_payments_partner_config_override_return_url_description', + __( 'Return to your shop.', 'woocommerce-paypal-payments' ) + ), + 'show_add_credit_card' => true, ), - /** - * Returns the description of the URL which will be opened at the end of onboarding. - */ - 'return_url_description' => apply_filters( - 'woocommerce_paypal_payments_partner_config_override_return_url_description', - __( 'Return to your shop.', 'woocommerce-paypal-payments' ) + 'products' => $this->products, + 'legal_consents' => array( + array( + 'type' => 'SHARE_DATA_CONSENT', + 'granted' => true, + ), ), - 'show_add_credit_card' => true, - ), - //'products' => $this->products, - 'legal_consents' => array( - array( - 'type' => 'SHARE_DATA_CONSENT', - 'granted' => true, - ), - ), - 'operations' => array( - array( - 'operation' => 'API_INTEGRATION', - 'api_integration_preference' => array( - 'rest_api_integration' => array( - 'integration_method' => 'PAYPAL', - 'integration_type' => 'FIRST_PARTY', - 'first_party_details' => array( - 'features' => array( - 'PAYMENT', - 'FUTURE_PAYMENT', - 'REFUND', - 'ADVANCED_TRANSACTIONS_SEARCH', - 'VAULT', + 'operations' => array( + array( + 'operation' => 'API_INTEGRATION', + 'api_integration_preference' => array( + 'rest_api_integration' => array( + 'integration_method' => 'PAYPAL', + 'integration_type' => 'FIRST_PARTY', + 'first_party_details' => array( + 'features' => array( + 'PAYMENT', + 'FUTURE_PAYMENT', + 'REFUND', + 'ADVANCED_TRANSACTIONS_SEARCH', + 'VAULT', + ), + 'seller_nonce' => $this->nonce(), ), - 'seller_nonce' => $this->nonce(), ), ), ), ), - ), - "products" => [ - "PAYMENT_METHODS" - ], - "capabilities" => [ - "PAY_UPON_INVOICE" - ], - "business_entity" => array( - "business_type" => array( - "type" => "INDIVIDUAL" - ), - "addresses" => array( - array( - "address_line_1" => "Parkstr. 26", - "admin_area_1" => "Berlin", - "postal_code" => "90409", - "country_code" => "DE", - "type" => "WORK", - ), - ), - ), - "tracking_id" => "testenterprices123122", + ) ); } } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index d2d76241a..edcd98fcb 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -22,6 +22,13 @@ class PayUponInvoice { } public function init() { + add_filter('ppcp_partner_referrals_data', function ($data) { + $data['products'][] = 'PAYMENT_METHODS'; + $data['capabilities'][] = 'PAY_UPON_INVOICE'; + + return $data; + }); + add_action( 'wp_footer', array( $this, 'add_parameter_block' ) From f166c1fff2353624757f3deecfe847d6165d73e9 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 11 Mar 2022 15:36:25 +0100 Subject: [PATCH 012/163] Add fraudnet source website id value --- modules/ppcp-wc-gateway/services.php | 7 ++++++- .../FraudNetSourceWebsiteId.php | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSourceWebsiteId.php diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 816201e48..ee2955df0 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -31,6 +31,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNet; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNetSessionId; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNetSourceWebsiteId; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\OrderEndpoint; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PaymentSourceFactory; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoice; @@ -2147,11 +2148,15 @@ return array( 'wcgateway.pay-upon-invoice-fraudnet-session-id' => static function ( ContainerInterface $container ): FraudNetSessionId { return new FraudNetSessionId(); }, + 'wcgateway.pay-upon-invoice-fraudnet-source-website-id' => static function ( ContainerInterface $container ): FraudNetSourceWebsiteId { + return new FraudNetSourceWebsiteId($container->get('api.merchant_id')); + }, 'wcgateway.pay-upon-invoice-fraudnet' => static function ( ContainerInterface $container ): FraudNet { $session_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-session-id' ); + $source_website_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-source-website-id' ); return new FraudNet( (string) $session_id(), - 'bar' + (string) $source_website_id() ); }, 'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice { diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSourceWebsiteId.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSourceWebsiteId.php new file mode 100644 index 000000000..8d0570cbc --- /dev/null +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/FraudNetSourceWebsiteId.php @@ -0,0 +1,21 @@ +api_merchant_id = $api_merchant_id; + } + + public function __invoke() + { + return "{$this->api_merchant_id}_checkout-page"; + } +} From 9b881e7189d9ba028ad7e901aac6c282a3f796cd Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 14 Mar 2022 11:42:51 +0100 Subject: [PATCH 013/163] Add german button legal text --- .../src/Gateway/PayUponInvoice/PayUponInvoice.php | 4 ++-- .../Gateway/PayUponInvoice/PayUponInvoiceGateway.php | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index edcd98fcb..839489375 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -58,7 +58,7 @@ class PayUponInvoice { } public function add_parameter_block() { ?> - + + style="display:none;">

__( 'Enable/Disable', 'woocommerce-paypal-payments' ), 'type' => 'checkbox', 'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ), - 'default' => 'yes', + 'default' => 'no', ), - 'legal_text' => array( - 'title' => __( 'Legal text', 'woocommerce-paypal-payments' ), + 'button_legal_text_en' => array( + 'title' => __( 'Button legal text (English)', 'woocommerce-paypal-payments' ), 'type' => 'textarea', 'default' => 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', ), + 'button_legal_text_de' => array( + 'title' => __( 'Button legal text (German)', 'woocommerce-paypal-payments' ), + 'type' => 'textarea', + 'default' => 'Mit Klicken auf den Button akzeptieren Sie die Ratepay Zahlungsbedingungen und erklären sich mit der Durchführung einer Risikoprüfung durch Ratepay, unseren Partner, einverstanden. Sie akzeptieren auch PayPals Datenschutzerklärung. Falls Ihre Transaktion per Kauf auf Rechnung erfolgreich abgewickelt werden kann, wird der Kaufpreis an Ratepay abgetreten und Sie dürfen nur an Ratepay überweisen, nicht an den Händler.', + ), ); } From 9dc5aa43e6ec30e5acfcadae61169194c6352dcf Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 14 Mar 2022 12:24:35 +0100 Subject: [PATCH 014/163] Add error details on create order --- .../Gateway/PayUponInvoice/PayUponInvoiceGateway.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index cc3e4b25c..160d3e3d9 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -111,6 +111,18 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { } catch ( RuntimeException $exception ) { $error = $exception->getMessage(); + if(is_array($exception->details())) { + $details = ''; + foreach ($exception->details() as $detail) { + $issue = $detail->issue ?? ''; + $field = $detail->field ?? ''; + $description = $detail->description ?? ''; + $details .= $issue . ' ' . $field . ' ' . $description . '
'; + } + + $error = $details; + } + $this->logger->error( $error ); wc_add_notice( $error, 'error' ); From 28edfcbebc082a05b870a655238a877f6acb82d4 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Wed, 16 Mar 2022 16:29:22 +0100 Subject: [PATCH 015/163] Get tax rate from item --- modules/ppcp-api-client/src/Entity/Item.php | 30 ++++++++++++++++--- .../src/Factory/ItemFactory.php | 9 ++++-- .../Gateway/PayUponInvoice/OrderEndpoint.php | 1 - 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/modules/ppcp-api-client/src/Entity/Item.php b/modules/ppcp-api-client/src/Entity/Item.php index 218bf3fa3..dd661301e 100644 --- a/modules/ppcp-api-client/src/Entity/Item.php +++ b/modules/ppcp-api-client/src/Entity/Item.php @@ -14,7 +14,6 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Entity; */ class Item { - const PHYSICAL_GOODS = 'PHYSICAL_GOODS'; const DIGITAL_GOODS = 'DIGITAL_GOODS'; @@ -67,6 +66,13 @@ class Item { */ private $category; + /** + * The tax rate. + * + * @var float|int + */ + protected $tax_rate; + /** * Item constructor. * @@ -85,7 +91,8 @@ class Item { string $description = '', Money $tax = null, string $sku = '', - string $category = 'PHYSICAL_GOODS' + string $category = 'PHYSICAL_GOODS', + float $tax_rate = 0 ) { $this->name = $name; @@ -94,8 +101,9 @@ class Item { $this->description = $description; $this->tax = $tax; $this->sku = $sku; - $this->category = ( self::DIGITAL_GOODS === $category ) ? - self::DIGITAL_GOODS : self::PHYSICAL_GOODS; + $this->category = ( self::DIGITAL_GOODS === $category ) ? self::DIGITAL_GOODS : self::PHYSICAL_GOODS; + $this->category = $category; + $this->tax_rate = $tax_rate; } /** @@ -161,6 +169,16 @@ class Item { return $this->category; } + /** + * Returns the tax rate. + * + * @return float + */ + public function tax_rate():float + { + return round((float) $this->tax_rate, 2); + } + /** * Returns the object as array. * @@ -180,6 +198,10 @@ class Item { $item['tax'] = $this->tax()->to_array(); } + if ($this->tax_rate()) { + $item['tax_rate'] = (string) $this->tax_rate(); + } + return $item; } } diff --git a/modules/ppcp-api-client/src/Factory/ItemFactory.php b/modules/ppcp-api-client/src/Factory/ItemFactory.php index 10aa40ff8..a292d90bd 100644 --- a/modules/ppcp-api-client/src/Factory/ItemFactory.php +++ b/modules/ppcp-api-client/src/Factory/ItemFactory.php @@ -9,6 +9,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\ApiClient\Factory; +use WC_Tax; use WooCommerce\PayPalCommerce\ApiClient\Entity\Item; use WooCommerce\PayPalCommerce\ApiClient\Entity\Money; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; @@ -57,6 +58,7 @@ class ItemFactory { $price_without_tax_rounded = round( $price_without_tax, 2 ); $tax = round( $price - $price_without_tax_rounded, 2 ); $tax = new Money( $tax, $this->currency ); + $tax_rates = WC_Tax::get_rates($product->get_tax_class()); return new Item( mb_substr( $product->get_name(), 0, 127 ), new Money( $price_without_tax_rounded, $this->currency ), @@ -64,7 +66,8 @@ class ItemFactory { mb_substr( wp_strip_all_tags( $product->get_description() ), 0, 127 ), $tax, $product->get_sku(), - ( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS + ( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS, + reset($tax_rates)['rate'] ?? 0 ); }, $cart->get_cart_contents() @@ -138,6 +141,7 @@ class ItemFactory { $price_without_tax_rounded = round( $price_without_tax, 2 ); $tax = round( $price - $price_without_tax_rounded, 2 ); $tax = new Money( $tax, $currency ); + $tax_rates = WC_Tax::get_rates($product->get_tax_class()); return new Item( mb_substr( $product->get_name(), 0, 127 ), new Money( $price_without_tax_rounded, $currency ), @@ -145,7 +149,8 @@ class ItemFactory { mb_substr( wp_strip_all_tags( $product->get_description() ), 0, 127 ), $tax, $product->get_sku(), - ( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS + ( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS, + reset($tax_rates)['rate'] ?? 0 ); } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php index 2ad775049..1349d9f45 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -77,7 +77,6 @@ class OrderEndpoint { ), ); - $data['purchase_units'][0]['items'][0]['tax_rate'] = '19.00'; $data['purchase_units'][0]['shipping']['name']['full_name'] = 'John Doe'; $data['purchase_units'][0]['shipping']['address'] = array( 'address_line_1' => 'Taunusanlage 12', From 07ec6ab542d71c6898d6b386e295241b6f410653 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 18 Mar 2022 12:44:09 +0100 Subject: [PATCH 016/163] Add PayPal order id to wc order and disable email on-hold notification for pui payment --- modules/ppcp-wc-gateway/services.php | 1 + .../Gateway/PayUponInvoice/PayUponInvoice.php | 8 ++++++++ .../PayUponInvoice/PayUponInvoiceGateway.php | 16 ++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index ee2955df0..c7c421ab7 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -2142,6 +2142,7 @@ return array( $container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ), $container->get( 'api.factory.purchase-unit' ), $container->get( 'wcgateway.pay-upon-invoice-payment-source-factory' ), + $container->get( 'onboarding.environment' ), $container->get( 'woocommerce.logger.woocommerce' ) ); }, diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 839489375..fe7559f0d 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -55,6 +55,14 @@ class PayUponInvoice { return $billing_fields; }); + + add_filter( 'woocommerce_email_recipient_customer_on_hold_order', function( $recipient, $order, $email) { + if($order->get_payment_method() === PayUponInvoiceGateway::ID) { + return ''; + } + + return $recipient; + }, 10, 3 ); } public function add_parameter_block() { ?> diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index 160d3e3d9..09b71ebdf 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -13,9 +13,13 @@ use Psr\Log\LoggerInterface; use RuntimeException; use WC_Payment_Gateway; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; +use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait; class PayUponInvoiceGateway extends WC_Payment_Gateway { + use OrderMetaTrait; + const ID = 'ppcp-pay-upon-invoice-gateway'; /** @@ -33,6 +37,11 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { */ protected $payment_source_factory; + /** + * @var Environment + */ + protected $environment; + /** * @var LoggerInterface */ @@ -42,6 +51,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { OrderEndpoint $order_endpoint, PurchaseUnitFactory $purchase_unit_factory, PaymentSourceFactory $payment_source_factory, + Environment $environment, LoggerInterface $logger ) { $this->id = self::ID; @@ -66,6 +76,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { $this->purchase_unit_factory = $purchase_unit_factory; $this->payment_source_factory = $payment_source_factory; $this->logger = $logger; + $this->environment = $environment; } /** @@ -94,13 +105,14 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { public function process_payment( $order_id ) { $wc_order = wc_get_order( $order_id ); - $wc_order->update_status( 'on-hold', __( 'Awaiting Pay Upon Invoice payment', 'woocommerce-paypal-payments' ) ); + $wc_order->update_status( 'on-hold', __( 'Awaiting Pay Upon Invoice payment.', 'woocommerce-paypal-payments' ) ); $purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order ); $payment_source = $this->payment_source_factory->from_wc_order( $wc_order ); try { - $this->order_endpoint->create( array( $purchase_unit ), $payment_source ); + $order = $this->order_endpoint->create( array( $purchase_unit ), $payment_source ); + $this->add_paypal_meta( $wc_order, $order, $this->environment ); WC()->cart->empty_cart(); From e53384f460a63a08a54d9b2ce5c64b16561f3b17 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 18 Mar 2022 17:10:56 +0100 Subject: [PATCH 017/163] Remove hardcoded shipping address for testing --- .../src/Gateway/PayUponInvoice/OrderEndpoint.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php index 1349d9f45..aef5df4a2 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -77,14 +77,6 @@ class OrderEndpoint { ), ); - $data['purchase_units'][0]['shipping']['name']['full_name'] = 'John Doe'; - $data['purchase_units'][0]['shipping']['address'] = array( - 'address_line_1' => 'Taunusanlage 12', - 'admin_area_2' => 'FRANKFURT AM MAIN', - 'postal_code' => '60325', - 'country_code' => 'DE', - ); - $bearer = $this->bearer->bearer(); $url = trailingslashit( $this->host ) . 'v2/checkout/orders'; $args = array( From 8eb320c5995644e45dfa01f41bfd608da35b16e8 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Sun, 20 Mar 2022 14:15:56 +0100 Subject: [PATCH 018/163] Get Ratepay payment instructions from order --- modules/ppcp-wc-gateway/services.php | 4 ++- .../Gateway/PayUponInvoice/OrderEndpoint.php | 28 +++++++++++++++++++ .../Gateway/PayUponInvoice/PayUponInvoice.php | 26 ++++++++++++++++- .../src/Handler/PaymentCaptureCompleted.php | 3 ++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index c7c421ab7..8f6e097fb 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -2163,7 +2163,9 @@ return array( 'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice { return new PayUponInvoice( $container->get( 'wcgateway.url' ), - $container->get( 'wcgateway.pay-upon-invoice-fraudnet' ) + $container->get( 'wcgateway.pay-upon-invoice-fraudnet' ), + $container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ), + $container->get( 'woocommerce.logger.woocommerce' ) ); }, ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php index aef5df4a2..9e5122834 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -104,4 +104,32 @@ class OrderEndpoint { return $this->order_factory->from_paypal_response( $json ); } + + public function order_payment_instructions(string $id) { + $bearer = $this->bearer->bearer(); + $url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $id; + $args = array( + 'headers' => array( + 'Authorization' => 'Bearer ' . $bearer->token(), + 'Content-Type' => 'application/json', + 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), + ), + ); + + $response = $this->request( $url, $args ); + + if ( is_wp_error( $response ) ) { + throw new RuntimeException( $response->get_error_message() ); + } + + $json = json_decode( $response['body'] ); + $status_code = (int) wp_remote_retrieve_response_code( $response ); + if ( 200 !== $status_code ) { + throw new PayPalApiException( $json, $status_code ); + } + + $this->logger->info('Payment instructions'); + $this->logger->info($json->payment_source->pay_upon_invoice->payment_reference); + $this->logger->info(wc_print_r($json->payment_source->pay_upon_invoice->deposit_bank_details, true)); + } } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index fe7559f0d..f933a0220 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -4,6 +4,9 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice; +use Psr\Log\LoggerInterface; +use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; + class PayUponInvoice { /** @@ -16,9 +19,26 @@ class PayUponInvoice { */ protected $fraud_net; - public function __construct( string $module_url, FraudNet $fraud_net ) { + /** + * @var OrderEndpoint + */ + protected $order_endpoint; + + /** + * @var LoggerInterface + */ + protected $logger; + + public function __construct( + string $module_url, + FraudNet $fraud_net, + OrderEndpoint $order_endpoint, + LoggerInterface $logger + ) { $this->module_url = $module_url; $this->fraud_net = $fraud_net; + $this->order_endpoint = $order_endpoint; + $this->logger = $logger; } public function init() { @@ -63,6 +83,10 @@ class PayUponInvoice { return $recipient; }, 10, 3 ); + + add_action('ppcp_payment_capture_completed_webhook_handler', function (string $order_id) { + $this->order_endpoint->order_payment_instructions($order_id); + }); } public function add_parameter_block() { ?> diff --git a/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php b/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php index 325541671..252e0d051 100644 --- a/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php +++ b/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php @@ -149,6 +149,9 @@ class PaymentCaptureCompleted implements RequestHandler { if ( $transaction_id ) { $this->update_transaction_id( $transaction_id, $wc_order, $this->logger ); } + + do_action('ppcp_payment_capture_completed_webhook_handler', (string) $order_id); + } catch ( Exception $exception ) { $this->logger->warning( 'Failed to get transaction ID: ' . $exception->getMessage() ); } From 21522fb8c1c95c8663230952cc62d069b9dd0866 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Tue, 22 Mar 2022 09:19:07 +0100 Subject: [PATCH 019/163] Move capture action hook up before wc order status update --- .../src/Gateway/PayUponInvoice/OrderEndpoint.php | 8 ++++++-- .../src/Gateway/PayUponInvoice/PayUponInvoice.php | 15 ++++++++++++--- .../src/Handler/PaymentCaptureCompleted.php | 8 ++++---- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php index 9e5122834..3bc6a39de 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -105,7 +105,7 @@ class OrderEndpoint { return $this->order_factory->from_paypal_response( $json ); } - public function order_payment_instructions(string $id) { + public function order_payment_instructions(string $id): array { $bearer = $this->bearer->bearer(); $url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $id; $args = array( @@ -117,7 +117,6 @@ class OrderEndpoint { ); $response = $this->request( $url, $args ); - if ( is_wp_error( $response ) ) { throw new RuntimeException( $response->get_error_message() ); } @@ -131,5 +130,10 @@ class OrderEndpoint { $this->logger->info('Payment instructions'); $this->logger->info($json->payment_source->pay_upon_invoice->payment_reference); $this->logger->info(wc_print_r($json->payment_source->pay_upon_invoice->deposit_bank_details, true)); + + return array( + $json->payment_source->pay_upon_invoice->payment_reference, + $json->payment_source->pay_upon_invoice->deposit_bank_details + ); } } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index f933a0220..3eaccfb2d 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -5,7 +5,10 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice; use Psr\Log\LoggerInterface; +use WC_Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; +use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; +use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException; class PayUponInvoice { @@ -84,9 +87,15 @@ class PayUponInvoice { return $recipient; }, 10, 3 ); - add_action('ppcp_payment_capture_completed_webhook_handler', function (string $order_id) { - $this->order_endpoint->order_payment_instructions($order_id); - }); + add_action('ppcp_payment_capture_completed_webhook_handler', function (WC_Order $wc_order, string $order_id) { + try { + $payment_instructions = $this->order_endpoint->order_payment_instructions($order_id); + $wc_order->update_meta_data( 'ppcp_ratepay_payment_instructions_payment_reference', $payment_instructions ); + $this->logger->info("Ratepay payment instructions added to order #{$wc_order->get_id()}."); + } catch (RuntimeException $exception) { + $this->logger->error($exception->getMessage()); + } + }, 10, 2); } public function add_parameter_block() { ?> diff --git a/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php b/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php index 252e0d051..5ed5a41aa 100644 --- a/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php +++ b/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php @@ -112,6 +112,10 @@ class PaymentCaptureCompleted implements RequestHandler { return new WP_REST_Response( $response ); } + $order_id = $resource['supplementary_data']['related_ids']['order_id'] ?? null; + + do_action('ppcp_payment_capture_completed_webhook_handler', $wc_order, $order_id); + if ( $wc_order->get_status() !== 'on-hold' ) { $response['success'] = true; return new WP_REST_Response( $response ); @@ -139,8 +143,6 @@ class PaymentCaptureCompleted implements RequestHandler { ) ); - $order_id = $resource['supplementary_data']['related_ids']['order_id'] ?? null; - if ( $order_id ) { try { $order = $this->order_endpoint->order( (string) $order_id ); @@ -150,8 +152,6 @@ class PaymentCaptureCompleted implements RequestHandler { $this->update_transaction_id( $transaction_id, $wc_order, $this->logger ); } - do_action('ppcp_payment_capture_completed_webhook_handler', (string) $order_id); - } catch ( Exception $exception ) { $this->logger->warning( 'Failed to get transaction ID: ' . $exception->getMessage() ); } From 2024f2c0ab472c072edd32299c9bf1fc2c5dc52e Mon Sep 17 00:00:00 2001 From: dinamiko Date: Thu, 24 Mar 2022 16:27:03 +0100 Subject: [PATCH 020/163] Add button legal text inside gateway box description --- .../resources/js/pay-upon-invoice.js | 10 ++-------- .../Gateway/PayUponInvoice/PayUponInvoice.php | 20 +++++++------------ .../PayUponInvoice/PayUponInvoiceGateway.php | 14 ++----------- 3 files changed, 11 insertions(+), 33 deletions(-) diff --git a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js index db862b962..139597f9c 100644 --- a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js +++ b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js @@ -1,8 +1,2 @@ -document.addEventListener('DOMContentLoaded', () => { - jQuery(document.body).on('updated_checkout payment_method_selected', () => { - jQuery('#ppcp-pui-legal-text').hide(); - if(jQuery('input[name="payment_method"]:checked').val() === 'ppcp-pay-upon-invoice-gateway') { - jQuery('#ppcp-pui-legal-text').show(); - } - }); -}); + + diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 3eaccfb2d..28e9ccb34 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -57,11 +57,6 @@ class PayUponInvoice { array( $this, 'add_parameter_block' ) ); - add_action( - 'woocommerce_review_order_after_submit', - array( $this, 'add_legal_text' ) - ); - add_action( 'wp_enqueue_scripts', array( $this, 'register_assets' ) @@ -96,6 +91,13 @@ class PayUponInvoice { $this->logger->error($exception->getMessage()); } }, 10, 2); + + add_filter( 'woocommerce_gateway_description', function($description, $id) { + if(PayUponInvoiceGateway::ID === $id) { + $description .= __( 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments'); + } + return $description; + }, 10, 2); } public function add_parameter_block() { ?> @@ -104,14 +106,6 @@ class PayUponInvoice { - - id = self::ID; $this->method_title = __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' ); - $this->method_description = __( 'Once you place an order, pay within 30 days. Our payment partner Ratepay will send you payment instructions.', 'woocommerce-paypal-payments' ); + $this->method_description = __( 'Pay upon Invoice is an invoice payment method in Germany. It is a local buy now, pay later payment method that allows the buyer to place an order, receive the goods, try them, verify they are in good order, and then pay the invoice within 30 days.', 'woocommerce-paypal-payments' );; $this->title = $this->method_title; - $this->description = $this->method_description; + $this->description = __( 'Once you place an order, pay within 30 days. Our payment partner Ratepay will send you payment instructions.', 'woocommerce-paypal-payments' );; $this->init_form_fields(); $this->init_settings(); @@ -90,16 +90,6 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { 'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ), 'default' => 'no', ), - 'button_legal_text_en' => array( - 'title' => __( 'Button legal text (English)', 'woocommerce-paypal-payments' ), - 'type' => 'textarea', - 'default' => 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', - ), - 'button_legal_text_de' => array( - 'title' => __( 'Button legal text (German)', 'woocommerce-paypal-payments' ), - 'type' => 'textarea', - 'default' => 'Mit Klicken auf den Button akzeptieren Sie die Ratepay Zahlungsbedingungen und erklären sich mit der Durchführung einer Risikoprüfung durch Ratepay, unseren Partner, einverstanden. Sie akzeptieren auch PayPals Datenschutzerklärung. Falls Ihre Transaktion per Kauf auf Rechnung erfolgreich abgewickelt werden kann, wird der Kaufpreis an Ratepay abgetreten und Sie dürfen nur an Ratepay überweisen, nicht an den Händler.', - ), ); } From 5089b6335fd8a78ac470aa9947c4cab4860eaff7 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 25 Mar 2022 10:14:54 +0100 Subject: [PATCH 021/163] Add custom checkout validation (WIP) --- .../src/Gateway/PayUponInvoice/PayUponInvoice.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 28e9ccb34..dbec919d0 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -98,6 +98,14 @@ class PayUponInvoice { } return $description; }, 10, 2); + + add_action('woocommerce_checkout_order_processed', function($order_id, $posted_data, $order) { + if($order->get_billing_country() !== 'DE') { + wp_send_json_error(array( + 'result' => 'failure', + )); + } + }, 10, 3); } public function add_parameter_block() { ?> From b6c2396e329c12378ad5358295d8e88c2b8d509a Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 25 Mar 2022 14:28:27 +0100 Subject: [PATCH 022/163] Grab fraudnet session id from form hidden field (WIP) --- .../resources/js/pay-upon-invoice.js | 15 +++++++++++++++ .../src/Gateway/PayUponInvoice/OrderEndpoint.php | 4 ++-- .../PayUponInvoice/PayUponInvoiceGateway.php | 4 +++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js index 139597f9c..7d1ee70b9 100644 --- a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js +++ b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js @@ -1,2 +1,17 @@ +window.addEventListener('load', function() { + setTimeout(() => { + const fncls = document.querySelector("[fncls='fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99']"); + const fncls_params = JSON.parse(fncls.textContent); + const fraudnetSessionId = document.createElement('input'); + fraudnetSessionId.setAttribute('type', 'hidden'); + fraudnetSessionId.setAttribute('name', 'fraudnet-session-id'); + fraudnetSessionId.setAttribute('value', fncls_params.f); + + const form = document.querySelector('form.checkout'); + form.appendChild(fraudnetSessionId); + + console.log(fncls_params.f) + }, 3000) +}) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php index 3bc6a39de..42e1d1e2b 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -62,7 +62,7 @@ class OrderEndpoint { * @param PurchaseUnit[] $items The purchase unit items for the order. * @return Order */ - public function create( array $items, PaymentSource $payment_source ): Order { + public function create( array $items, PaymentSource $payment_source, $fraudnet_session_id = '' ): Order { $data = array( 'intent' => 'CAPTURE', 'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL', @@ -85,7 +85,7 @@ class OrderEndpoint { 'Authorization' => 'Bearer ' . $bearer->token(), 'Content-Type' => 'application/json', 'Prefer' => 'return=representation', - 'PayPal-Client-Metadata-Id' => $this->fraudNet->sessionId(), + 'PayPal-Client-Metadata-Id' => $fraudnet_session_id ?: $this->fraudNet->sessionId(), 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), ), 'body' => wp_json_encode( $data ), diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index 9db4987f6..495dae912 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -101,7 +101,9 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { $payment_source = $this->payment_source_factory->from_wc_order( $wc_order ); try { - $order = $this->order_endpoint->create( array( $purchase_unit ), $payment_source ); + $fraudnet_session_id = filter_input(INPUT_POST, 'fraudnet-session-id', FILTER_SANITIZE_STRING) ?? ''; + + $order = $this->order_endpoint->create( array( $purchase_unit ), $payment_source, $fraudnet_session_id ); $this->add_paypal_meta( $wc_order, $order, $this->environment ); WC()->cart->empty_cart(); From 077203dd8efc70e21af71169b182fd8f1c7aab7e Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 25 Mar 2022 16:37:58 +0100 Subject: [PATCH 023/163] Only add pui referrals data when ppcp in products --- .../Gateway/PayUponInvoice/PayUponInvoice.php | 125 +++++++++++------- 1 file changed, 77 insertions(+), 48 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index dbec919d0..6099d1330 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -38,19 +38,23 @@ class PayUponInvoice { OrderEndpoint $order_endpoint, LoggerInterface $logger ) { - $this->module_url = $module_url; - $this->fraud_net = $fraud_net; + $this->module_url = $module_url; + $this->fraud_net = $fraud_net; $this->order_endpoint = $order_endpoint; - $this->logger = $logger; + $this->logger = $logger; } public function init() { - add_filter('ppcp_partner_referrals_data', function ($data) { - $data['products'][] = 'PAYMENT_METHODS'; - $data['capabilities'][] = 'PAY_UPON_INVOICE'; - - return $data; - }); + add_filter( + 'ppcp_partner_referrals_data', + function ( $data ) { + if ( in_array( 'PPCP', $data['products'] ) ) { + $data['products'][] = 'PAYMENT_METHODS'; + $data['capabilities'][] = 'PAY_UPON_INVOICE'; + } + return $data; + } + ); add_action( 'wp_footer', @@ -62,54 +66,79 @@ class PayUponInvoice { array( $this, 'register_assets' ) ); - add_filter( 'woocommerce_billing_fields', function($billing_fields) { - $billing_fields['billing_birth_date'] = array( - 'type' => 'date', - 'label' => __('Birth date', 'woocommerce-paypal-payments'), - 'class' => array('form-row-wide'), - 'required' => true, - 'clear' => true, - ); + add_filter( + 'woocommerce_billing_fields', + function( $billing_fields ) { + $billing_fields['billing_birth_date'] = array( + 'type' => 'date', + 'label' => __( 'Birth date', 'woocommerce-paypal-payments' ), + 'class' => array( 'form-row-wide' ), + 'required' => true, + 'clear' => true, + ); - return $billing_fields; - }); - - add_filter( 'woocommerce_email_recipient_customer_on_hold_order', function( $recipient, $order, $email) { - if($order->get_payment_method() === PayUponInvoiceGateway::ID) { - return ''; + return $billing_fields; } + ); - return $recipient; - }, 10, 3 ); + add_filter( + 'woocommerce_email_recipient_customer_on_hold_order', + function( $recipient, $order, $email ) { + if ( $order->get_payment_method() === PayUponInvoiceGateway::ID ) { + return ''; + } - add_action('ppcp_payment_capture_completed_webhook_handler', function (WC_Order $wc_order, string $order_id) { - try { - $payment_instructions = $this->order_endpoint->order_payment_instructions($order_id); - $wc_order->update_meta_data( 'ppcp_ratepay_payment_instructions_payment_reference', $payment_instructions ); - $this->logger->info("Ratepay payment instructions added to order #{$wc_order->get_id()}."); - } catch (RuntimeException $exception) { - $this->logger->error($exception->getMessage()); - } - }, 10, 2); + return $recipient; + }, + 10, + 3 + ); - add_filter( 'woocommerce_gateway_description', function($description, $id) { - if(PayUponInvoiceGateway::ID === $id) { - $description .= __( 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments'); - } - return $description; - }, 10, 2); + add_action( + 'ppcp_payment_capture_completed_webhook_handler', + function ( WC_Order $wc_order, string $order_id ) { + try { + $payment_instructions = $this->order_endpoint->order_payment_instructions( $order_id ); + $wc_order->update_meta_data( 'ppcp_ratepay_payment_instructions_payment_reference', $payment_instructions ); + $this->logger->info( "Ratepay payment instructions added to order #{$wc_order->get_id()}." ); + } catch ( RuntimeException $exception ) { + $this->logger->error( $exception->getMessage() ); + } + }, + 10, + 2 + ); - add_action('woocommerce_checkout_order_processed', function($order_id, $posted_data, $order) { - if($order->get_billing_country() !== 'DE') { - wp_send_json_error(array( - 'result' => 'failure', - )); - } - }, 10, 3); + add_filter( + 'woocommerce_gateway_description', + function( $description, $id ) { + if ( PayUponInvoiceGateway::ID === $id ) { + $description .= __( 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); + } + return $description; + }, + 10, + 2 + ); + + add_action( + 'woocommerce_checkout_order_processed', + function( $order_id, $posted_data, $order ) { + if ( $order->get_billing_country() !== 'DE' ) { + wp_send_json_error( + array( + 'result' => 'failure', + ) + ); + } + }, + 10, + 3 + ); } public function add_parameter_block() { ?> - + Date: Mon, 28 Mar 2022 10:42:11 +0200 Subject: [PATCH 024/163] Move birth date field into pui gateway box --- .../Gateway/PayUponInvoice/PayUponInvoice.php | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 6099d1330..4175cf6d5 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -66,21 +66,6 @@ class PayUponInvoice { array( $this, 'register_assets' ) ); - add_filter( - 'woocommerce_billing_fields', - function( $billing_fields ) { - $billing_fields['billing_birth_date'] = array( - 'type' => 'date', - 'label' => __( 'Birth date', 'woocommerce-paypal-payments' ), - 'class' => array( 'form-row-wide' ), - 'required' => true, - 'clear' => true, - ); - - return $billing_fields; - } - ); - add_filter( 'woocommerce_email_recipient_customer_on_hold_order', function( $recipient, $order, $email ) { @@ -113,8 +98,27 @@ class PayUponInvoice { 'woocommerce_gateway_description', function( $description, $id ) { if ( PayUponInvoiceGateway::ID === $id ) { - $description .= __( 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); + ob_start(); + echo '
'; + + woocommerce_form_field( + 'billing_birth_date', + array( + 'type' => 'date', + 'label' => __('Birth date', 'woocommerce-paypal-payments'), + 'class' => array('form-row-wide'), + 'required' => true, + 'clear' => true, + ) + ); + + echo '
'; + _e( 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); + echo '
'; + + $description .= ob_get_clean(); } + return $description; }, 10, From 7f8ce720e0dd24e373dd869ede6e2c66ce840341 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 28 Mar 2022 12:31:59 +0200 Subject: [PATCH 025/163] Add title and description to pui gateway settings --- .../PayUponInvoice/PayUponInvoiceGateway.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index 495dae912..0a1306087 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -57,9 +57,11 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { $this->id = self::ID; $this->method_title = __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' ); - $this->method_description = __( 'Pay upon Invoice is an invoice payment method in Germany. It is a local buy now, pay later payment method that allows the buyer to place an order, receive the goods, try them, verify they are in good order, and then pay the invoice within 30 days.', 'woocommerce-paypal-payments' );; - $this->title = $this->method_title; - $this->description = __( 'Once you place an order, pay within 30 days. Our payment partner Ratepay will send you payment instructions.', 'woocommerce-paypal-payments' );; + $this->method_description = __( 'Pay upon Invoice is an invoice payment method in Germany. It is a local buy now, pay later payment method that allows the buyer to place an order, receive the goods, try them, verify they are in good order, and then pay the invoice within 30 days.', 'woocommerce-paypal-payments' ); + + $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' ); + $this->title = $gateway_settings['title'] ?? $this->method_title; + $this->description = $gateway_settings['description'] ?? __( 'Once you place an order, pay within 30 days. Our payment partner Ratepay will send you payment instructions.', 'woocommerce-paypal-payments' ); $this->init_form_fields(); $this->init_settings(); @@ -90,6 +92,16 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { 'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ), 'default' => 'no', ), + 'title' => array( + 'title' => __( 'Title', 'woocommerce-paypal-payments' ), + 'type' => 'text', + 'default' => $this->title, + ), + 'description' => array( + 'title' => __( 'Description', 'woocommerce-paypal-payments' ), + 'type' => 'text', + 'default' => $this->description, + ), ); } From b05d15437ff45b37f0c3a8308cbb597f3bc04335 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 28 Mar 2022 12:42:49 +0200 Subject: [PATCH 026/163] Add tooltip description to gateway settings fields --- .../src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index 0a1306087..440a788ed 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -91,16 +91,22 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { 'type' => 'checkbox', 'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ), 'default' => 'no', + 'desc_tip' => true, + 'description' => __('Enable/Disable Pay Upon Invoice payment gateway.', 'woocommerce-paypal-payments'), ), 'title' => array( 'title' => __( 'Title', 'woocommerce-paypal-payments' ), 'type' => 'text', 'default' => $this->title, + 'desc_tip' => true, + 'description' => __('This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments'), ), 'description' => array( 'title' => __( 'Description', 'woocommerce-paypal-payments' ), 'type' => 'text', 'default' => $this->description, + 'desc_tip' => true, + 'description' => __('This controls the descriptiong which the user sees during checkout.', 'woocommerce-paypal-payments'), ), ); } From d99fdb15d35f0c111e0364f61d5ea5dadfa6b5b4 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Tue, 29 Mar 2022 11:15:36 +0200 Subject: [PATCH 027/163] Add phone country code field to pui gateway box --- .../src/Gateway/PayUponInvoice/PayUponInvoice.php | 10 ++++++++++ .../Gateway/PayUponInvoice/PaymentSourceFactory.php | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 4175cf6d5..939618881 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -111,6 +111,16 @@ class PayUponInvoice { 'clear' => true, ) ); + woocommerce_form_field( + 'phone_country_code', + array( + 'type' => 'number', + 'label' => __('Phone country code (ex. 49)', 'woocommerce-paypal-payments'), + 'class' => array('form-row-wide'), + 'required' => true, + 'clear' => true, + ) + ); echo '
'; _e( 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php index 378e1e618..e1943f977 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php @@ -9,6 +9,7 @@ class PaymentSourceFactory { public function from_wc_order( WC_Order $order ) { $address = $order->get_address(); $birth_date = filter_input( INPUT_POST, 'billing_birth_date', FILTER_SANITIZE_STRING ); + $phone_country_code = filter_input( INPUT_POST, 'phone_country_code', FILTER_SANITIZE_STRING ); return new PaymentSource( $address['first_name'] ?? '', @@ -16,7 +17,7 @@ class PaymentSourceFactory { $address['email'] ?? '', $birth_date ?? '', $address['phone'] ?? '', - '49', + $phone_country_code ?? '', $address['address_1'] ?? '', $address['city'] ?? '', $address['postcode'] ?? '', From 72efcbb71dc129a0384e9a2c36e9086e7cc60f10 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Tue, 29 Mar 2022 11:37:22 +0200 Subject: [PATCH 028/163] Only init pui if gateway is enabled --- modules/ppcp-wc-gateway/src/WCGatewayModule.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index 30fb8061d..697d90654 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -173,7 +173,7 @@ class WCGatewayModule implements ModuleInterface { assert( $settings instanceof Settings ); try { - if ( $settings->get( '3d_secure_contingency' ) === '3D_SECURE' ) { + if ( $settings->has( '3d_secure_contingency' ) && $settings->get( '3d_secure_contingency' ) === '3D_SECURE' ) { $settings->set( '3d_secure_contingency', 'SCA_ALWAYS' ); $settings->persist(); } @@ -186,7 +186,10 @@ class WCGatewayModule implements ModuleInterface { add_action( 'init', function () use ( $c ) { - if ( 'DE' === $c->get( 'api.shop.country' ) ) { + $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' ); + $gateway_enabled = $gateway_settings['enabled'] ?? ''; + + if ( 'yes' === $gateway_enabled && 'DE' === $c->get( 'api.shop.country' ) ) { ( $c->get( 'wcgateway.pay-upon-invoice' ) )->init(); } } From 6c216ad7bb314f531b3419b0dc8f32931f300ff3 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Wed, 30 Mar 2022 09:54:03 +0200 Subject: [PATCH 029/163] Get phone country code from billing country code --- .../Gateway/PayUponInvoice/PayUponInvoice.php | 32 ++++++------------- .../PayUponInvoice/PaymentSourceFactory.php | 4 +-- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 939618881..cf9b525f9 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -104,21 +104,11 @@ class PayUponInvoice { woocommerce_form_field( 'billing_birth_date', array( - 'type' => 'date', - 'label' => __('Birth date', 'woocommerce-paypal-payments'), - 'class' => array('form-row-wide'), + 'type' => 'date', + 'label' => __( 'Birth date', 'woocommerce-paypal-payments' ), + 'class' => array( 'form-row-wide' ), 'required' => true, - 'clear' => true, - ) - ); - woocommerce_form_field( - 'phone_country_code', - array( - 'type' => 'number', - 'label' => __('Phone country code (ex. 49)', 'woocommerce-paypal-payments'), - 'class' => array('form-row-wide'), - 'required' => true, - 'clear' => true, + 'clear' => true, ) ); @@ -136,18 +126,14 @@ class PayUponInvoice { ); add_action( - 'woocommerce_checkout_order_processed', - function( $order_id, $posted_data, $order ) { - if ( $order->get_billing_country() !== 'DE' ) { - wp_send_json_error( - array( - 'result' => 'failure', - ) - ); + 'woocommerce_after_checkout_validation', + function( $fields, $errors ) { + if ( $fields['billing_country'] !== 'DE' ) { + $errors->add( 'validation', __( 'Billing country not available.', 'woocommerce-paypal-payments' ) ); } }, 10, - 3 + 2 ); } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php index e1943f977..ccacd8a16 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php @@ -9,7 +9,7 @@ class PaymentSourceFactory { public function from_wc_order( WC_Order $order ) { $address = $order->get_address(); $birth_date = filter_input( INPUT_POST, 'billing_birth_date', FILTER_SANITIZE_STRING ); - $phone_country_code = filter_input( INPUT_POST, 'phone_country_code', FILTER_SANITIZE_STRING ); + $phone_country_code = WC()->countries->get_country_calling_code( $address['country'] ?? '' ); return new PaymentSource( $address['first_name'] ?? '', @@ -17,7 +17,7 @@ class PaymentSourceFactory { $address['email'] ?? '', $birth_date ?? '', $address['phone'] ?? '', - $phone_country_code ?? '', + substr($phone_country_code, strlen('+')) ?? '', $address['address_1'] ?? '', $address['city'] ?? '', $address['postcode'] ?? '', From 3dd46c7258fa87a569bb53725386f4380e8725c1 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Thu, 31 Mar 2022 12:47:05 +0200 Subject: [PATCH 030/163] Add RatePay payment instructions into processing order email notification (WIP) --- .../Gateway/PayUponInvoice/PayUponInvoice.php | 42 ++++++++++++++++++- .../PayUponInvoice/PayUponInvoiceGateway.php | 14 ++++++- .../src/Handler/CheckoutOrderApproved.php | 5 +++ .../src/Handler/CheckoutOrderCompleted.php | 5 +++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index cf9b525f9..ef6645056 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -94,6 +94,46 @@ class PayUponInvoice { 2 ); + add_action( 'woocommerce_email_before_order_table', function(WC_Order $order, $sent_to_admin) { + if(! $sent_to_admin && PayUponInvoiceGateway::ID === $order->get_payment_method() && $order->has_status( 'processing' )) { + $this->logger->info( "Adding Ratepay payment instructions to email for order #{$order->get_id()}." ); + + $instructions = $order->get_meta('ppcp_ratepay_payment_instructions_payment_reference'); + + $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' ); + $merchant_name = $gateway_settings['brand_name'] ?? ''; + + $order_date = $order->get_date_created(); + $order_purchase_date = $order_date->date('d-m-Y'); + $order_time = $order_date->date('H:i:s'); + $order_date = $order_date->date('d-m-Y H:i:s'); + $order_date_30d = date( 'd-m-Y', strtotime( $order_date . ' +30 days' )); + + $payment_reference = $instructions[0] ?? ''; + $bic = $instructions[1]->bic ?? ''; + $bank_name = $instructions[1]->bank_name ?? ''; + $iban = $instructions[1]->iban ?? ''; + $account_holder_name = $instructions[1]->account_holder_name ?? ''; + + echo "

Für Ihre Bestellung #{$order->get_id()} ({$order_purchase_date} $order_time) bei {$merchant_name} haben Sie die Zahlung mittels “Rechnungskauf mit Ratepay“ gewählt."; + echo "
Bitte benutzen Sie die folgenden Informationen für Ihre Überweisung:
"; + echo "

Bitte überweisen Sie den Betrag in Höhe von {$order->get_total()} bis zum {$order_date_30d} auf das unten angegebene Konto. Wichtig: Bitte geben Sie unbedingt als Verwendungszweck {$payment_reference} an, sonst kann die Zahlung nicht zugeordnet werden.

"; + echo "
    "; + echo "
  • Empfänger: {$account_holder_name}
  • "; + echo "
  • IBAN: {$iban}
  • "; + echo "
  • BIC: {$bic}
  • "; + echo "
  • Name der Bank: {$bank_name}
  • "; + echo "
  • Verwendungszweck: {$payment_reference}
  • "; + echo "
"; + + echo "

{$merchant_name} hat die Forderung gegen Sie an die PayPal (Europe) S.à r.l. et Cie, S.C.A. abgetreten, die wiederum die Forderung an Ratepay GmbH abgetreten hat. Zahlungen mit schuldbefreiender Wirkung können nur an die Ratepay GmbH geleistet werden.

"; + + echo "

Mit freundlichen Grüßen"; + echo "
"; + echo "{$merchant_name}

"; + } + }, 10, 3 ); + add_filter( 'woocommerce_gateway_description', function( $description, $id ) { @@ -138,7 +178,7 @@ class PayUponInvoice { } public function add_parameter_block() { ?> - + 'text', 'default' => $this->description, 'desc_tip' => true, - 'description' => __('This controls the descriptiong which the user sees during checkout.', 'woocommerce-paypal-payments'), + 'description' => __('This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments'), + ), + 'experience_context' => array( + 'title' => __( 'Experience Context', 'woocommerce' ), + 'type' => 'title', + 'description' => __("Specify brand name, logo and customer service instructions to be presented on Ratepay's payment instruction email sent to the buyer.", 'woocommerce-paypal-payments'), + ), + 'brand_name' => array( + 'title' => __( 'Brand name', 'woocommerce-paypal-payments' ), + 'type' => 'text', + 'default' => '', + 'desc_tip' => true, + 'description' => __('Merchant name displayed in the email.', 'woocommerce-paypal-payments'), ), ); } diff --git a/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php b/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php index 45d49762b..03fc21412 100644 --- a/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php +++ b/modules/ppcp-webhooks/src/Handler/CheckoutOrderApproved.php @@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Webhooks\Handler; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; use Psr\Log\LoggerInterface; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway; /** * Class CheckoutOrderApproved @@ -188,6 +189,10 @@ class CheckoutOrderApproved implements RequestHandler { } foreach ( $wc_orders as $wc_order ) { + if(PayUponInvoiceGateway::ID === $wc_order->get_payment_method()) { + continue; + } + if ( ! in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) { continue; } diff --git a/modules/ppcp-webhooks/src/Handler/CheckoutOrderCompleted.php b/modules/ppcp-webhooks/src/Handler/CheckoutOrderCompleted.php index 4b1eea7b7..44f9ca6e6 100644 --- a/modules/ppcp-webhooks/src/Handler/CheckoutOrderCompleted.php +++ b/modules/ppcp-webhooks/src/Handler/CheckoutOrderCompleted.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Webhooks\Handler; use Psr\Log\LoggerInterface; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway; /** * Class CheckoutOrderCompleted @@ -131,6 +132,10 @@ class CheckoutOrderCompleted implements RequestHandler { } foreach ( $wc_orders as $wc_order ) { + if(PayUponInvoiceGateway::ID === $wc_order->get_payment_method()) { + continue; + } + if ( ! in_array( $wc_order->get_status(), array( 'pending', 'on-hold' ), true ) ) { continue; } From 2f87f90c9aa6509f7310e1b8513e5efd801e5705 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 4 Apr 2022 12:58:44 +0200 Subject: [PATCH 031/163] Add error messages for pui error codes --- .../src/Gateway/PayUponInvoice/OrderEndpoint.php | 8 ++++++++ .../src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php index 42e1d1e2b..d57a85a36 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -99,6 +99,14 @@ class OrderEndpoint { $json = json_decode( $response['body'] ); $status_code = (int) wp_remote_retrieve_response_code( $response ); if ( ! in_array($status_code, [200,201] ) ) { + $issue = $json->details[0]->issue ?? null; + if($issue === 'PAYMENT_SOURCE_INFO_CANNOT_BE_VERIFIED') { + throw new RuntimeException('The combination of your name and address could not be validated. Please correct your data and try again. You can find further information in the Ratepay Data Privacy Statement or you can contact Ratepay using this contact form.'); + } + if($issue === 'PAYMENT_SOURCE_DECLINED_BY_PROCESSOR') { + throw new RuntimeException('It is not possible to use the selected payment method. This decision is based on automated data processing. You can find further information in the Ratepay Data Privacy Statement or you can contact Ratepay using this contact form.'); + } + throw new PayPalApiException( $json, $status_code ); } diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index 122f554cf..dab06489c 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice; use Psr\Log\LoggerInterface; use RuntimeException; use WC_Payment_Gateway; +use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use WooCommerce\PayPalCommerce\Onboarding\Environment; use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait; @@ -145,7 +146,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { } catch ( RuntimeException $exception ) { $error = $exception->getMessage(); - if(is_array($exception->details())) { + if(is_a($exception, PayPalApiException::class) && is_array($exception->details())) { $details = ''; foreach ($exception->details() as $detail) { $issue = $detail->issue ?? ''; From 201b359abb53d09291a2f0111639995402d8c534 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 4 Apr 2022 16:55:04 +0200 Subject: [PATCH 032/163] Do not remove on-hold notification email --- .../Gateway/PayUponInvoice/PayUponInvoice.php | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index ef6645056..12636687d 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -66,19 +66,6 @@ class PayUponInvoice { array( $this, 'register_assets' ) ); - add_filter( - 'woocommerce_email_recipient_customer_on_hold_order', - function( $recipient, $order, $email ) { - if ( $order->get_payment_method() === PayUponInvoiceGateway::ID ) { - return ''; - } - - return $recipient; - }, - 10, - 3 - ); - add_action( 'ppcp_payment_capture_completed_webhook_handler', function ( WC_Order $wc_order, string $order_id ) { @@ -117,7 +104,7 @@ class PayUponInvoice { echo "

Für Ihre Bestellung #{$order->get_id()} ({$order_purchase_date} $order_time) bei {$merchant_name} haben Sie die Zahlung mittels “Rechnungskauf mit Ratepay“ gewählt."; echo "
Bitte benutzen Sie die folgenden Informationen für Ihre Überweisung:
"; - echo "

Bitte überweisen Sie den Betrag in Höhe von {$order->get_total()} bis zum {$order_date_30d} auf das unten angegebene Konto. Wichtig: Bitte geben Sie unbedingt als Verwendungszweck {$payment_reference} an, sonst kann die Zahlung nicht zugeordnet werden.

"; + echo "

Bitte überweisen Sie den Betrag in Höhe von {$order->get_currency()}{$order->get_total()} bis zum {$order_date_30d} auf das unten angegebene Konto. Wichtig: Bitte geben Sie unbedingt als Verwendungszweck {$payment_reference} an, sonst kann die Zahlung nicht zugeordnet werden.

"; echo "
    "; echo "
  • Empfänger: {$account_holder_name}
  • "; echo "
  • IBAN: {$iban}
  • "; @@ -126,6 +113,7 @@ class PayUponInvoice { echo "
  • Verwendungszweck: {$payment_reference}
  • "; echo "
"; + echo "

{$merchant_name} hat die Forderung gegen Sie an die PayPal (Europe) S.à r.l. et Cie, S.C.A. abgetreten, die wiederum die Forderung an Ratepay GmbH abgetreten hat. Zahlungen mit schuldbefreiender Wirkung können nur an die Ratepay GmbH geleistet werden.

"; echo "

Mit freundlichen Grüßen"; From 6cbcdf32ddfae187b9198c1f6eff14587161f704 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 8 Apr 2022 10:50:59 +0200 Subject: [PATCH 033/163] Do not display pui gateway if customer billing country is not germany --- .../Gateway/PayUponInvoice/PayUponInvoice.php | 82 +++++++++++-------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 12636687d..c42c43116 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -81,46 +81,50 @@ class PayUponInvoice { 2 ); - add_action( 'woocommerce_email_before_order_table', function(WC_Order $order, $sent_to_admin) { - if(! $sent_to_admin && PayUponInvoiceGateway::ID === $order->get_payment_method() && $order->has_status( 'processing' )) { - $this->logger->info( "Adding Ratepay payment instructions to email for order #{$order->get_id()}." ); + add_action( + 'woocommerce_email_before_order_table', + function( WC_Order $order, $sent_to_admin ) { + if ( ! $sent_to_admin && PayUponInvoiceGateway::ID === $order->get_payment_method() && $order->has_status( 'processing' ) ) { + $this->logger->info( "Adding Ratepay payment instructions to email for order #{$order->get_id()}." ); - $instructions = $order->get_meta('ppcp_ratepay_payment_instructions_payment_reference'); + $instructions = $order->get_meta( 'ppcp_ratepay_payment_instructions_payment_reference' ); - $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' ); - $merchant_name = $gateway_settings['brand_name'] ?? ''; + $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' ); + $merchant_name = $gateway_settings['brand_name'] ?? ''; - $order_date = $order->get_date_created(); - $order_purchase_date = $order_date->date('d-m-Y'); - $order_time = $order_date->date('H:i:s'); - $order_date = $order_date->date('d-m-Y H:i:s'); - $order_date_30d = date( 'd-m-Y', strtotime( $order_date . ' +30 days' )); + $order_date = $order->get_date_created(); + $order_purchase_date = $order_date->date( 'd-m-Y' ); + $order_time = $order_date->date( 'H:i:s' ); + $order_date = $order_date->date( 'd-m-Y H:i:s' ); + $order_date_30d = date( 'd-m-Y', strtotime( $order_date . ' +30 days' ) ); - $payment_reference = $instructions[0] ?? ''; - $bic = $instructions[1]->bic ?? ''; - $bank_name = $instructions[1]->bank_name ?? ''; - $iban = $instructions[1]->iban ?? ''; - $account_holder_name = $instructions[1]->account_holder_name ?? ''; + $payment_reference = $instructions[0] ?? ''; + $bic = $instructions[1]->bic ?? ''; + $bank_name = $instructions[1]->bank_name ?? ''; + $iban = $instructions[1]->iban ?? ''; + $account_holder_name = $instructions[1]->account_holder_name ?? ''; - echo "

Für Ihre Bestellung #{$order->get_id()} ({$order_purchase_date} $order_time) bei {$merchant_name} haben Sie die Zahlung mittels “Rechnungskauf mit Ratepay“ gewählt."; - echo "
Bitte benutzen Sie die folgenden Informationen für Ihre Überweisung:
"; - echo "

Bitte überweisen Sie den Betrag in Höhe von {$order->get_currency()}{$order->get_total()} bis zum {$order_date_30d} auf das unten angegebene Konto. Wichtig: Bitte geben Sie unbedingt als Verwendungszweck {$payment_reference} an, sonst kann die Zahlung nicht zugeordnet werden.

"; - echo "
    "; - echo "
  • Empfänger: {$account_holder_name}
  • "; - echo "
  • IBAN: {$iban}
  • "; - echo "
  • BIC: {$bic}
  • "; - echo "
  • Name der Bank: {$bank_name}
  • "; - echo "
  • Verwendungszweck: {$payment_reference}
  • "; - echo "
"; + echo "

Für Ihre Bestellung #{$order->get_id()} ({$order_purchase_date} $order_time) bei {$merchant_name} haben Sie die Zahlung mittels “Rechnungskauf mit Ratepay“ gewählt."; + echo '
Bitte benutzen Sie die folgenden Informationen für Ihre Überweisung:
'; + echo "

Bitte überweisen Sie den Betrag in Höhe von {$order->get_currency()}{$order->get_total()} bis zum {$order_date_30d} auf das unten angegebene Konto. Wichtig: Bitte geben Sie unbedingt als Verwendungszweck {$payment_reference} an, sonst kann die Zahlung nicht zugeordnet werden.

"; + echo '
    '; + echo "
  • Empfänger: {$account_holder_name}
  • "; + echo "
  • IBAN: {$iban}
  • "; + echo "
  • BIC: {$bic}
  • "; + echo "
  • Name der Bank: {$bank_name}
  • "; + echo "
  • Verwendungszweck: {$payment_reference}
  • "; + echo '
'; + echo "

{$merchant_name} hat die Forderung gegen Sie an die PayPal (Europe) S.à r.l. et Cie, S.C.A. abgetreten, die wiederum die Forderung an Ratepay GmbH abgetreten hat. Zahlungen mit schuldbefreiender Wirkung können nur an die Ratepay GmbH geleistet werden.

"; - echo "

{$merchant_name} hat die Forderung gegen Sie an die PayPal (Europe) S.à r.l. et Cie, S.C.A. abgetreten, die wiederum die Forderung an Ratepay GmbH abgetreten hat. Zahlungen mit schuldbefreiender Wirkung können nur an die Ratepay GmbH geleistet werden.

"; - - echo "

Mit freundlichen Grüßen"; - echo "
"; - echo "{$merchant_name}

"; - } - }, 10, 3 ); + echo '

Mit freundlichen Grüßen'; + echo '
'; + echo "{$merchant_name}

"; + } + }, + 10, + 3 + ); add_filter( 'woocommerce_gateway_description', @@ -163,6 +167,18 @@ class PayUponInvoice { 10, 2 ); + + add_filter( + 'woocommerce_available_payment_gateways', + function( $methods ) { + $billing_country = filter_input( INPUT_POST, 'country', FILTER_SANITIZE_STRING ) ?? null; + if ( ! is_admin() && $billing_country !== 'DE' ) { + unset( $methods[ PayUponInvoiceGateway::ID ] ); + } + + return $methods; + } + ); } public function add_parameter_block() { ?> From a1741d5575402976def1af28ca0ac78abfa0132b Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 8 Apr 2022 11:13:46 +0200 Subject: [PATCH 034/163] Do not display pui gateway if customer billing country is not germany --- .../src/Gateway/PayUponInvoice/PayUponInvoice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index c42c43116..d27d72d0c 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -172,7 +172,7 @@ class PayUponInvoice { 'woocommerce_available_payment_gateways', function( $methods ) { $billing_country = filter_input( INPUT_POST, 'country', FILTER_SANITIZE_STRING ) ?? null; - if ( ! is_admin() && $billing_country !== 'DE' ) { + if ( $billing_country && $billing_country !== 'DE' ) { unset( $methods[ PayUponInvoiceGateway::ID ] ); } From a56c756773125972c983b3254350e740f92a0369 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 8 Apr 2022 11:23:02 +0200 Subject: [PATCH 035/163] Fix typo in item factory --- modules/ppcp-api-client/src/Factory/ItemFactory.php | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/ppcp-api-client/src/Factory/ItemFactory.php b/modules/ppcp-api-client/src/Factory/ItemFactory.php index fb57f066a..91d27d3ab 100644 --- a/modules/ppcp-api-client/src/Factory/ItemFactory.php +++ b/modules/ppcp-api-client/src/Factory/ItemFactory.php @@ -142,7 +142,6 @@ class ItemFactory { $tax = round( $price - $price_without_tax_rounded, 2 ); $tax = new Money( $tax, $currency ); $tax_rates = WC_Tax::get_rates($product->get_tax_class()); - $tax = new Money( $tax + $shipping_tax, $currency ); return new Item( mb_substr( $product->get_name(), 0, 127 ), From 6fa6d3cdc9bd1e1d7e92cfd523ed041b58bc028e Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 8 Apr 2022 12:03:24 +0200 Subject: [PATCH 036/163] Add custom translations --- .../src/Gateway/PayUponInvoice/OrderEndpoint.php | 15 +++++++++++++-- .../src/Gateway/PayUponInvoice/PayUponInvoice.php | 7 ++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php index d57a85a36..cdfb553ce 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/OrderEndpoint.php @@ -100,11 +100,22 @@ class OrderEndpoint { $status_code = (int) wp_remote_retrieve_response_code( $response ); if ( ! in_array($status_code, [200,201] ) ) { $issue = $json->details[0]->issue ?? null; + + $site_country_code = explode('-', get_bloginfo("language"))[0] ?? ''; if($issue === 'PAYMENT_SOURCE_INFO_CANNOT_BE_VERIFIED') { - throw new RuntimeException('The combination of your name and address could not be validated. Please correct your data and try again. You can find further information in the Ratepay Data Privacy Statement or you can contact Ratepay using this contact form.'); + if($site_country_code === 'de') { + throw new RuntimeException('Die Kombination aus Ihrem Namen und Ihrer Anschrift konnte nicht validiert werden. Bitte korrigieren Sie Ihre Daten und versuchen Sie es erneut. Weitere Informationen finden Sie in den Ratepay Datenschutzbestimmungen oder nutzen Sie das Ratepay Kontaktformular.'); + + } else { + throw new RuntimeException('The combination of your name and address could not be validated. Please correct your data and try again. You can find further information in the Ratepay Data Privacy Statement or you can contact Ratepay using this contact form.'); + } } if($issue === 'PAYMENT_SOURCE_DECLINED_BY_PROCESSOR') { - throw new RuntimeException('It is not possible to use the selected payment method. This decision is based on automated data processing. You can find further information in the Ratepay Data Privacy Statement or you can contact Ratepay using this contact form.'); + if($site_country_code === 'de') { + throw new RuntimeException('Die gewählte Zahlungsart kann nicht genutzt werden. Diese Entscheidung basiert auf einem automatisierten Datenverarbeitungsverfahren. Weitere Informationen finden Sie in den Ratepay Datenschutzbestimmungen oder nutzen Sie das Ratepay Kontaktformular.'); + } else { + throw new RuntimeException('It is not possible to use the selected payment method. This decision is based on automated data processing. You can find further information in the Ratepay Data Privacy Statement or you can contact Ratepay using this contact form.'); + } } throw new PayPalApiException( $json, $status_code ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index d27d72d0c..b0bc39858 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -145,7 +145,12 @@ class PayUponInvoice { ); echo '
'; - _e( 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); + $site_country_code = explode('-', get_bloginfo("language"))[0] ?? ''; + if($site_country_code === 'de') { + _e( 'Mit Klicken auf den Button akzeptieren Sie die Ratepay Zahlungsbedingungen und erklären sich mit der Durchführung einer Risikoprüfung durch Ratepay, unseren Partner, einverstanden. Sie akzeptieren auch PayPals Datenschutzerklärung. Falls Ihre Transaktion per Kauf auf Rechnung erfolgreich abgewickelt werden kann, wird der Kaufpreis an Ratepay abgetreten und Sie dürfen nur an Ratepay überweisen, nicht an den Händler.', 'woocommerce-paypal-payments' ); + } else { + _e( 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); + } echo '
'; $description .= ob_get_clean(); From 2d60d93617baaa8b43c738cea15a64357c18b10c Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 8 Apr 2022 12:35:01 +0200 Subject: [PATCH 037/163] Grab button label from place order button and display it on button legal text --- modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js | 6 +++++- .../src/Gateway/PayUponInvoice/PayUponInvoice.php | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js index 7d1ee70b9..31420d7b3 100644 --- a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js +++ b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js @@ -12,6 +12,10 @@ window.addEventListener('load', function() { form.appendChild(fraudnetSessionId); console.log(fncls_params.f) - }, 3000) + }, 3000); + + const buttonLabel = document.querySelector('#place_order').textContent; + const buttonLegalTextLabel = document.querySelector('#ppcp-legal-text-button-label'); + buttonLegalTextLabel.textContent = '"' + buttonLabel + '"'; }) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index b0bc39858..28ebef6d2 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -147,9 +147,9 @@ class PayUponInvoice { echo '
'; $site_country_code = explode('-', get_bloginfo("language"))[0] ?? ''; if($site_country_code === 'de') { - _e( 'Mit Klicken auf den Button akzeptieren Sie die Ratepay Zahlungsbedingungen und erklären sich mit der Durchführung einer Risikoprüfung durch Ratepay, unseren Partner, einverstanden. Sie akzeptieren auch PayPals Datenschutzerklärung. Falls Ihre Transaktion per Kauf auf Rechnung erfolgreich abgewickelt werden kann, wird der Kaufpreis an Ratepay abgetreten und Sie dürfen nur an Ratepay überweisen, nicht an den Händler.', 'woocommerce-paypal-payments' ); + _e( 'Mit Klicken auf den Button akzeptieren Sie die Ratepay Zahlungsbedingungen und erklären sich mit der Durchführung einer Risikoprüfung durch Ratepay, unseren Partner, einverstanden. Sie akzeptieren auch PayPals Datenschutzerklärung. Falls Ihre Transaktion per Kauf auf Rechnung erfolgreich abgewickelt werden kann, wird der Kaufpreis an Ratepay abgetreten und Sie dürfen nur an Ratepay überweisen, nicht an den Händler.', 'woocommerce-paypal-payments' ); } else { - _e( 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); + _e( 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); } echo '
'; From 1046b9d77a2738b4d537feb2795abce35886125f Mon Sep 17 00:00:00 2001 From: dinamiko Date: Fri, 8 Apr 2022 12:44:50 +0200 Subject: [PATCH 038/163] Grab button label from place order button and display it on button legal text --- .../resources/js/pay-upon-invoice.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js index 31420d7b3..3ca9b5a78 100644 --- a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js +++ b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js @@ -14,8 +14,18 @@ window.addEventListener('load', function() { console.log(fncls_params.f) }, 3000); - const buttonLabel = document.querySelector('#place_order').textContent; - const buttonLegalTextLabel = document.querySelector('#ppcp-legal-text-button-label'); - buttonLegalTextLabel.textContent = '"' + buttonLabel + '"'; + const replaceButtonLabel = () => { + const buttonLabel = document.querySelector('#place_order').textContent; + const buttonLegalTextLabel = document.querySelector('#ppcp-legal-text-button-label'); + if(buttonLabel && buttonLegalTextLabel) { + buttonLegalTextLabel.textContent = '"' + buttonLabel + '"'; + } + } + + jQuery(document.body).on('payment_method_selected', () => { + replaceButtonLabel(); + }); + + replaceButtonLabel(); }) From 317ac3f7e8c18ed671f47aae105f891489903d74 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Mon, 11 Apr 2022 12:50:05 +0200 Subject: [PATCH 039/163] Onboard pui optionally for merchants (wip) --- .../ppcp-onboarding/assets/js/onboarding.js | 19 +++++++ modules/ppcp-onboarding/services.php | 10 +++- .../src/Assets/OnboardingAssets.php | 2 + .../src/Endpoint/PayUponInvoiceEndpoint.php | 56 +++++++++++++++++++ .../ppcp-onboarding/src/OnboardingModule.php | 8 +++ .../src/Render/OnboardingOptionsRenderer.php | 29 +++++++++- modules/ppcp-wc-gateway/services.php | 3 +- .../Gateway/PayUponInvoice/PayUponInvoice.php | 17 +++++- 8 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php diff --git a/modules/ppcp-onboarding/assets/js/onboarding.js b/modules/ppcp-onboarding/assets/js/onboarding.js index 0753ad943..e7c70c5ee 100644 --- a/modules/ppcp-onboarding/assets/js/onboarding.js +++ b/modules/ppcp-onboarding/assets/js/onboarding.js @@ -70,6 +70,25 @@ const ppcp_onboarding = { }, 1000 ); + + const onboard_pui = document.querySelector('#ppcp-onboarding-pui'); + onboard_pui.addEventListener('click', (event) => { + event.preventDefault(); + + fetch(PayPalCommerceGatewayOnboarding.pui_endpoint, { + method: 'POST', + body: JSON.stringify({ + nonce: PayPalCommerceGatewayOnboarding.pui_nonce, + checked: onboard_pui.checked + }) + }).then((res)=>{ + return res.json(); + }).then((data)=>{ + console.log(data) + }); + + location.reload(); + }) }, loginSeller: function(env, authCode, sharedId) { diff --git a/modules/ppcp-onboarding/services.php b/modules/ppcp-onboarding/services.php index 5bbbbd6a9..29301c85e 100644 --- a/modules/ppcp-onboarding/services.php +++ b/modules/ppcp-onboarding/services.php @@ -18,6 +18,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnerReferrals; use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache; use WooCommerce\PayPalCommerce\Onboarding\Assets\OnboardingAssets; use WooCommerce\PayPalCommerce\Onboarding\Endpoint\LoginSellerEndpoint; +use WooCommerce\PayPalCommerce\Onboarding\Endpoint\PayUponInvoiceEndpoint; use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer; use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingRenderer; use WooCommerce\PayPalCommerce\Onboarding\OnboardingRESTController; @@ -186,6 +187,12 @@ return array( $logger ); }, + 'onboarding.endpoint.pui' => static function(ContainerInterface $container) : PayUponInvoiceEndpoint { + return new PayUponInvoiceEndpoint( + $container->get( 'wcgateway.settings' ), + $container->get( 'button.request-data' ) + ); + }, 'api.endpoint.partner-referrals-sandbox' => static function ( ContainerInterface $container ) : PartnerReferrals { return new PartnerReferrals( @@ -218,7 +225,8 @@ return array( 'onboarding.render-options' => static function ( ContainerInterface $container ) : OnboardingOptionsRenderer { return new OnboardingOptionsRenderer( $container->get( 'onboarding.url' ), - $container->get( 'api.shop.country' ) + $container->get( 'api.shop.country' ), + $container->get( 'wcgateway.settings' ) ); }, 'onboarding.rest' => static function( $container ) : OnboardingRESTController { diff --git a/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php b/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php index 6e73c3bac..8f669e9b4 100644 --- a/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php +++ b/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php @@ -145,6 +145,8 @@ class OnboardingAssets { 'error_messages' => array( 'no_credentials' => __( 'API credentials must be entered to save the settings.', 'woocommerce-paypal-payments' ), ), + 'pui_endpoint' => \WC_AJAX::get_endpoint( 'ppc-pui' ), + 'pui_nonce' => wp_create_nonce( 'ppc-pui' ), ); } diff --git a/modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php b/modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php new file mode 100644 index 000000000..474840122 --- /dev/null +++ b/modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php @@ -0,0 +1,56 @@ +settings = $settings; + $this->request_data = $request_data; + } + + public static function nonce(): string + { + return 'ppc-pui'; + } + + public function handle_request(): bool + { + try { + $data = $this->request_data->read_request( $this->nonce() ); + $this->settings->set('ppcp-onboarding-pui', $data['checked']); + $this->settings->persist(); + + } catch (\Exception $exception) { + + } + + wp_send_json_success([ + $this->settings->get('ppcp-onboarding-pui'), + ]); + return true; + } +} + diff --git a/modules/ppcp-onboarding/src/OnboardingModule.php b/modules/ppcp-onboarding/src/OnboardingModule.php index 0960c7b6c..3f35cfd9e 100644 --- a/modules/ppcp-onboarding/src/OnboardingModule.php +++ b/modules/ppcp-onboarding/src/OnboardingModule.php @@ -96,6 +96,14 @@ class OnboardingModule implements ModuleInterface { } ); + add_action( + 'wc_ajax_' . 'ppc-pui', + static function () use ( $c ) { + $endpoint = $c->get( 'onboarding.endpoint.pui' ); + $endpoint->handle_request(); + } + ); + // Initialize REST routes at the appropriate time. $rest_controller = $c->get( 'onboarding.rest' ); add_action( 'rest_api_init', array( $rest_controller, 'register_routes' ) ); diff --git a/modules/ppcp-onboarding/src/Render/OnboardingOptionsRenderer.php b/modules/ppcp-onboarding/src/Render/OnboardingOptionsRenderer.php index ce0d20b3f..24c1c2340 100644 --- a/modules/ppcp-onboarding/src/Render/OnboardingOptionsRenderer.php +++ b/modules/ppcp-onboarding/src/Render/OnboardingOptionsRenderer.php @@ -9,6 +9,8 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Onboarding\Render; +use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; + /** * Class OnboardingRenderer */ @@ -27,15 +29,21 @@ class OnboardingOptionsRenderer { */ private $country; + /** + * @var Settings + */ + protected $settings; + /** * OnboardingOptionsRenderer constructor. * * @param string $module_url The module url (for assets). * @param string $country 2-letter country code of the shop. */ - public function __construct( string $module_url, string $country ) { + public function __construct( string $module_url, string $country, Settings $settings) { $this->module_url = $module_url; $this->country = $country; + $this->settings = $settings; } /** @@ -56,8 +64,23 @@ class OnboardingOptionsRenderer { __( 'Securely accept all major credit & debit cards on the strength of the PayPal network', 'woocommerce-paypal-payments' ) . ' -
  • ' . $this->render_dcc( $is_shop_supports_dcc ) . '
  • -'; +
  • ' . $this->render_dcc( $is_shop_supports_dcc ) . '
  • ' . + $this->render_pui_option() +. ''; + } + + private function render_pui_option(): string { + if($this->country === 'DE') { + $checked = 'checked'; + if($this->settings->has('ppcp-onboarding-pui') && $this->settings->get('ppcp-onboarding-pui') !== '1') { + $checked = ''; + } + return ''; + } + + return ''; } /** diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index db8c84888..8eda96b2d 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -2176,7 +2176,8 @@ return array( $container->get( 'wcgateway.url' ), $container->get( 'wcgateway.pay-upon-invoice-fraudnet' ), $container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ), - $container->get( 'woocommerce.logger.woocommerce' ) + $container->get( 'woocommerce.logger.woocommerce' ), + $container->get( 'wcgateway.settings' ) ); }, ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 28ebef6d2..c925ad444 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -9,6 +9,7 @@ use WC_Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException; +use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; class PayUponInvoice { @@ -32,26 +33,38 @@ class PayUponInvoice { */ protected $logger; + /** + * @var Settings + */ + protected $settings; + public function __construct( string $module_url, FraudNet $fraud_net, OrderEndpoint $order_endpoint, - LoggerInterface $logger + LoggerInterface $logger, + Settings $settings ) { $this->module_url = $module_url; $this->fraud_net = $fraud_net; $this->order_endpoint = $order_endpoint; $this->logger = $logger; + $this->settings = $settings; } public function init() { add_filter( 'ppcp_partner_referrals_data', function ( $data ) { - if ( in_array( 'PPCP', $data['products'] ) ) { + if($this->settings->has('ppcp-onboarding-pui') && $this->settings->get('ppcp-onboarding-pui') !== '1') { + return $data; + } + + if(in_array( 'PPCP', $data['products'] )) { $data['products'][] = 'PAYMENT_METHODS'; $data['capabilities'][] = 'PAY_UPON_INVOICE'; } + return $data; } ); From dcf1fd863c12c5bc61d1ef85e655c137d1f9d81b Mon Sep 17 00:00:00 2001 From: dinamiko Date: Tue, 12 Apr 2022 15:09:28 +0200 Subject: [PATCH 040/163] Remove fraudnet session id if exist before creating it --- .../resources/js/pay-upon-invoice.js | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js index 3ca9b5a78..2509fd762 100644 --- a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js +++ b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js @@ -1,23 +1,42 @@ window.addEventListener('load', function() { - setTimeout(() => { + + const getSessionIdFromJson = () => { + const form = document.querySelector('form.checkout'); + if(!form) { + return; + } + const fncls = document.querySelector("[fncls='fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99']"); const fncls_params = JSON.parse(fncls.textContent); + if(document.querySelector("[name='fraudnet-session-id']") !== null) { + document.querySelector("[name='fraudnet-session-id']").remove(); + } + const fraudnetSessionId = document.createElement('input'); fraudnetSessionId.setAttribute('type', 'hidden'); fraudnetSessionId.setAttribute('name', 'fraudnet-session-id'); fraudnetSessionId.setAttribute('value', fncls_params.f); - const form = document.querySelector('form.checkout'); form.appendChild(fraudnetSessionId); + console.log(fncls_params) + } - console.log(fncls_params.f) - }, 3000); + document.addEventListener('hosted_fields_loaded', (event) => { + getSessionIdFromJson(); + }); + + getSessionIdFromJson(); const replaceButtonLabel = () => { - const buttonLabel = document.querySelector('#place_order').textContent; + const form = document.querySelector('form.checkout'); + if(!form) { + return; + } + + const buttonLabel = document.querySelector('#place_order')?.textContent; const buttonLegalTextLabel = document.querySelector('#ppcp-legal-text-button-label'); - if(buttonLabel && buttonLegalTextLabel) { + if (buttonLabel && buttonLegalTextLabel) { buttonLegalTextLabel.textContent = '"' + buttonLabel + '"'; } } From ae30f4346dd9f0e7c715e45bdf2d0105ab743bf5 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Wed, 13 Apr 2022 11:53:44 +0200 Subject: [PATCH 041/163] Add experience context fields --- .../PayUponInvoice/PayUponInvoiceGateway.php | 86 +++++++++++-------- .../PayUponInvoice/PaymentSourceFactory.php | 11 ++- 2 files changed, 58 insertions(+), 39 deletions(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index dab06489c..4249042d0 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -60,8 +60,8 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { $this->method_title = __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' ); $this->method_description = __( 'Pay upon Invoice is an invoice payment method in Germany. It is a local buy now, pay later payment method that allows the buyer to place an order, receive the goods, try them, verify they are in good order, and then pay the invoice within 30 days.', 'woocommerce-paypal-payments' ); - $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' ); - $this->title = $gateway_settings['title'] ?? $this->method_title; + $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' ); + $this->title = $gateway_settings['title'] ?? $this->method_title; $this->description = $gateway_settings['description'] ?? __( 'Once you place an order, pay within 30 days. Our payment partner Ratepay will send you payment instructions.', 'woocommerce-paypal-payments' ); $this->init_form_fields(); @@ -79,7 +79,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { $this->purchase_unit_factory = $purchase_unit_factory; $this->payment_source_factory = $payment_source_factory; $this->logger = $logger; - $this->environment = $environment; + $this->environment = $environment; } /** @@ -87,39 +87,53 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { */ public function init_form_fields() { $this->form_fields = array( - 'enabled' => array( - 'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ), - 'type' => 'checkbox', - 'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ), - 'default' => 'no', - 'desc_tip' => true, - 'description' => __('Enable/Disable Pay Upon Invoice payment gateway.', 'woocommerce-paypal-payments'), + 'enabled' => array( + 'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ), + 'type' => 'checkbox', + 'label' => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ), + 'default' => 'no', + 'desc_tip' => true, + 'description' => __( 'Enable/Disable Pay Upon Invoice payment gateway.', 'woocommerce-paypal-payments' ), ), - 'title' => array( - 'title' => __( 'Title', 'woocommerce-paypal-payments' ), - 'type' => 'text', - 'default' => $this->title, - 'desc_tip' => true, - 'description' => __('This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments'), + 'title' => array( + 'title' => __( 'Title', 'woocommerce-paypal-payments' ), + 'type' => 'text', + 'default' => $this->title, + 'desc_tip' => true, + 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ), ), - 'description' => array( - 'title' => __( 'Description', 'woocommerce-paypal-payments' ), - 'type' => 'text', - 'default' => $this->description, - 'desc_tip' => true, - 'description' => __('This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments'), + 'description' => array( + 'title' => __( 'Description', 'woocommerce-paypal-payments' ), + 'type' => 'text', + 'default' => $this->description, + 'desc_tip' => true, + 'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ), ), - 'experience_context' => array( + 'experience_context' => array( 'title' => __( 'Experience Context', 'woocommerce' ), 'type' => 'title', - 'description' => __("Specify brand name, logo and customer service instructions to be presented on Ratepay's payment instruction email sent to the buyer.", 'woocommerce-paypal-payments'), + 'description' => __( "Specify brand name, logo and customer service instructions to be presented on Ratepay's payment instructions.", 'woocommerce-paypal-payments' ), ), - 'brand_name' => array( - 'title' => __( 'Brand name', 'woocommerce-paypal-payments' ), - 'type' => 'text', - 'default' => '', - 'desc_tip' => true, - 'description' => __('Merchant name displayed in the email.', 'woocommerce-paypal-payments'), + 'brand_name' => array( + 'title' => __( 'Brand name', 'woocommerce-paypal-payments' ), + 'type' => 'text', + 'default' => get_bloginfo( 'name' ) ?? '', + 'desc_tip' => true, + 'description' => __( 'Merchant name displayed in Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ), + ), + 'logo_url' => array( + 'title' => __( 'Logo URL', 'woocommerce-paypal-payments' ), + 'type' => 'url', + 'default' => '', + 'desc_tip' => true, + 'description' => __( 'Logo to be presented on Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ), + ), + 'customer_service_instructions' => array( + 'title' => __( 'Customer service instructions', 'woocommerce-paypal-payments' ), + 'type' => 'text', + 'default' => '', + 'desc_tip' => true, + 'description' => __( 'Customer service instructions to be presented on Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ), ), ); } @@ -132,7 +146,7 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { $payment_source = $this->payment_source_factory->from_wc_order( $wc_order ); try { - $fraudnet_session_id = filter_input(INPUT_POST, 'fraudnet-session-id', FILTER_SANITIZE_STRING) ?? ''; + $fraudnet_session_id = filter_input( INPUT_POST, 'fraudnet-session-id', FILTER_SANITIZE_STRING ) ?? ''; $order = $this->order_endpoint->create( array( $purchase_unit ), $payment_source, $fraudnet_session_id ); $this->add_paypal_meta( $wc_order, $order, $this->environment ); @@ -146,13 +160,13 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway { } catch ( RuntimeException $exception ) { $error = $exception->getMessage(); - if(is_a($exception, PayPalApiException::class) && is_array($exception->details())) { + if ( is_a( $exception, PayPalApiException::class ) && is_array( $exception->details() ) ) { $details = ''; - foreach ($exception->details() as $detail) { - $issue = $detail->issue ?? ''; - $field = $detail->field ?? ''; + foreach ( $exception->details() as $detail ) { + $issue = $detail->issue ?? ''; + $field = $detail->field ?? ''; $description = $detail->description ?? ''; - $details .= $issue . ' ' . $field . ' ' . $description . '
    '; + $details .= $issue . ' ' . $field . ' ' . $description . '
    '; } $error = $details; diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php index ccacd8a16..8577c3f9b 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php @@ -11,6 +11,11 @@ class PaymentSourceFactory { $birth_date = filter_input( INPUT_POST, 'billing_birth_date', FILTER_SANITIZE_STRING ); $phone_country_code = WC()->countries->get_country_calling_code( $address['country'] ?? '' ); + $gateway_settings = get_option( 'woocommerce_ppcp-pay-upon-invoice-gateway_settings' ); + $merchant_name = $gateway_settings['brand_name'] ?? ''; + $logo_url = $gateway_settings['logo_url'] ?? ''; + $customer_service_instructions = $gateway_settings['customer_service_instructions'] ?? ''; + return new PaymentSource( $address['first_name'] ?? '', $address['last_name'] ?? '', @@ -23,9 +28,9 @@ class PaymentSourceFactory { $address['postcode'] ?? '', $address['country'] ?? '', 'en-DE', - 'EXAMPLE INC', - 'https://example.com/logoUrl.svg', - array('Customer service phone is +49 6912345678.') + $merchant_name, + $logo_url, + array($customer_service_instructions) ); } } From 9835421a321c3f57be23a0ddc92bffaa4bfc1681 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Wed, 13 Apr 2022 16:46:13 +0200 Subject: [PATCH 042/163] Add pui gateway settings as PayPal tab (WIP) --- modules/ppcp-wc-gateway/services.php | 2 +- modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php | 9 +++++++++ .../ppcp-wc-gateway/src/Settings/SectionsRenderer.php | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index c0cf84c25..91871baef 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -143,7 +143,7 @@ return array( } $section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : ''; - return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID ), true ); + return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID, PayUponInvoiceGateway::ID ), true ); }, 'wcgateway.current-ppcp-settings-page-id' => static function ( ContainerInterface $container ): string { diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php index c0604e598..75446008d 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php @@ -19,6 +19,7 @@ use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway; use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor; use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor; use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor; @@ -340,6 +341,10 @@ class PayPalGateway extends \WC_Payment_Gateway { if ( $this->is_paypal_tab() ) { return __( 'PayPal Checkout', 'woocommerce-paypal-payments' ); } + if($this->is_pui_tab()) { + return __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' ); + } + return __( 'PayPal', 'woocommerce-paypal-payments' ); } @@ -388,6 +393,10 @@ class PayPalGateway extends \WC_Payment_Gateway { } + private function is_pui_tab():bool { + return is_admin() && PayUponInvoiceGateway::ID === $this->page_id; + } + /** * Whether we are on the Webhooks Status tab. * diff --git a/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php b/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php index 2bddabe1b..316ff65fa 100644 --- a/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php +++ b/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php @@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Settings; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway; use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage; /** @@ -56,6 +57,7 @@ class SectionsRenderer { $sections = array( PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ), CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ), + PayUponInvoiceGateway::ID => __( 'Pay Upon Invoice', 'woocommerce-paypal-payments' ), WebhooksStatusPage::ID => __( 'Webhooks Status', 'woocommerce-paypal-payments' ), ); From 0a261a0de9dec1cf1dd925cd5394085a28e5c971 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Thu, 14 Apr 2022 10:13:41 +0200 Subject: [PATCH 043/163] Add sandbox parameter to config json when in sandbox environment --- modules/ppcp-wc-gateway/services.php | 3 ++- .../Gateway/PayUponInvoice/PayUponInvoice.php | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 91871baef..3086c6da0 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -2192,7 +2192,8 @@ return array( $container->get( 'wcgateway.pay-upon-invoice-fraudnet' ), $container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ), $container->get( 'woocommerce.logger.woocommerce' ), - $container->get( 'wcgateway.settings' ) + $container->get( 'wcgateway.settings' ), + $container->get( 'onboarding.environment' ) ); }, 'wcgateway.logging.is-enabled' => function ( ContainerInterface $container ) : bool { diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index c925ad444..9d2e386bd 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -9,6 +9,7 @@ use WC_Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException; +use WooCommerce\PayPalCommerce\Onboarding\Environment; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; class PayUponInvoice { @@ -38,18 +39,25 @@ class PayUponInvoice { */ protected $settings; + /** + * @var Environment + */ + protected $environment; + public function __construct( string $module_url, FraudNet $fraud_net, OrderEndpoint $order_endpoint, LoggerInterface $logger, - Settings $settings + Settings $settings, + Environment $environment ) { $this->module_url = $module_url; $this->fraud_net = $fraud_net; $this->order_endpoint = $order_endpoint; $this->logger = $logger; $this->settings = $settings; + $this->environment = $environment; } public function init() { @@ -199,8 +207,10 @@ class PayUponInvoice { ); } - public function add_parameter_block() { ?> - + public function add_parameter_block() { + $sandbox = $this->environment->current_environment_is(Environment::SANDBOX) ? '"sandbox":true,': ''; + ?> + Date: Thu, 14 Apr 2022 10:54:14 +0200 Subject: [PATCH 044/163] Get place order button label from filter --- .../resources/js/pay-upon-invoice.js | 19 ------------------- .../Gateway/PayUponInvoice/PayUponInvoice.php | 4 ++-- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js index 2509fd762..50ed4d56f 100644 --- a/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js +++ b/modules/ppcp-wc-gateway/resources/js/pay-upon-invoice.js @@ -27,24 +27,5 @@ window.addEventListener('load', function() { }); getSessionIdFromJson(); - - const replaceButtonLabel = () => { - const form = document.querySelector('form.checkout'); - if(!form) { - return; - } - - const buttonLabel = document.querySelector('#place_order')?.textContent; - const buttonLegalTextLabel = document.querySelector('#ppcp-legal-text-button-label'); - if (buttonLabel && buttonLegalTextLabel) { - buttonLegalTextLabel.textContent = '"' + buttonLabel + '"'; - } - } - - jQuery(document.body).on('payment_method_selected', () => { - replaceButtonLabel(); - }); - - replaceButtonLabel(); }) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 9d2e386bd..5c335dea0 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -168,9 +168,9 @@ class PayUponInvoice { echo '
    '; $site_country_code = explode('-', get_bloginfo("language"))[0] ?? ''; if($site_country_code === 'de') { - _e( 'Mit Klicken auf den Button akzeptieren Sie die Ratepay Zahlungsbedingungen und erklären sich mit der Durchführung einer Risikoprüfung durch Ratepay, unseren Partner, einverstanden. Sie akzeptieren auch PayPals Datenschutzerklärung. Falls Ihre Transaktion per Kauf auf Rechnung erfolgreich abgewickelt werden kann, wird der Kaufpreis an Ratepay abgetreten und Sie dürfen nur an Ratepay überweisen, nicht an den Händler.', 'woocommerce-paypal-payments' ); + _e( 'Mit Klicken auf '.apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ).' akzeptieren Sie die Ratepay Zahlungsbedingungen und erklären sich mit der Durchführung einer Risikoprüfung durch Ratepay, unseren Partner, einverstanden. Sie akzeptieren auch PayPals Datenschutzerklärung. Falls Ihre Transaktion per Kauf auf Rechnung erfolgreich abgewickelt werden kann, wird der Kaufpreis an Ratepay abgetreten und Sie dürfen nur an Ratepay überweisen, nicht an den Händler.', 'woocommerce-paypal-payments' ); } else { - _e( 'By clicking on the button, you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); + _e( 'By clicking on '.apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ).', you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); } echo '
    '; From 473c4026333d3ac7971bc791cb785978e294ea7b Mon Sep 17 00:00:00 2001 From: dinamiko Date: Thu, 14 Apr 2022 11:45:27 +0200 Subject: [PATCH 045/163] Add pui gateway settings as PayPal tab (WIP) --- modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php b/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php index 316ff65fa..54b6eec31 100644 --- a/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php +++ b/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php @@ -67,6 +67,9 @@ class SectionsRenderer { foreach ( $sections as $id => $label ) { $url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&' . self::KEY . '=' . $id ); + if($id === PayUponInvoiceGateway::ID) { + $url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-pay-upon-invoice-gateway'); + } echo '
  • ' . esc_html( $label ) . ' ' . ( end( $array_keys ) === $id ? '' : '|' ) . '
  • '; } From b303804f813bc4421ee389b5849f3860350d5fbd Mon Sep 17 00:00:00 2001 From: dinamiko Date: Thu, 14 Apr 2022 12:08:13 +0200 Subject: [PATCH 046/163] Remove all phone non-numeric characters --- .../src/Gateway/PayUponInvoice/PaymentSourceFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php index 8577c3f9b..531fd7a06 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PaymentSourceFactory.php @@ -21,7 +21,7 @@ class PaymentSourceFactory { $address['last_name'] ?? '', $address['email'] ?? '', $birth_date ?? '', - $address['phone'] ?? '', + preg_replace('/[^0-9]/', '', $address['phone']), substr($phone_country_code, strlen('+')) ?? '', $address['address_1'] ?? '', $address['city'] ?? '', From 42ce61de5bce99183bd5d6bade6aaa85f0e396c3 Mon Sep 17 00:00:00 2001 From: dinamiko Date: Thu, 14 Apr 2022 15:52:22 +0200 Subject: [PATCH 047/163] Reload page inside then --- modules/ppcp-onboarding/assets/js/onboarding.js | 9 +++++---- .../src/Gateway/PayUponInvoice/PayUponInvoice.php | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/ppcp-onboarding/assets/js/onboarding.js b/modules/ppcp-onboarding/assets/js/onboarding.js index e7c70c5ee..913c86d34 100644 --- a/modules/ppcp-onboarding/assets/js/onboarding.js +++ b/modules/ppcp-onboarding/assets/js/onboarding.js @@ -73,7 +73,10 @@ const ppcp_onboarding = { const onboard_pui = document.querySelector('#ppcp-onboarding-pui'); onboard_pui.addEventListener('click', (event) => { - event.preventDefault(); + event.preventDefault(); + buttons.forEach((element) => { + element.removeAttribute('href'); + }); fetch(PayPalCommerceGatewayOnboarding.pui_endpoint, { method: 'POST', @@ -84,10 +87,8 @@ const ppcp_onboarding = { }).then((res)=>{ return res.json(); }).then((data)=>{ - console.log(data) + location.reload(); }); - - location.reload(); }) }, diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 5c335dea0..e51b57a13 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -168,9 +168,9 @@ class PayUponInvoice { echo '
    '; $site_country_code = explode('-', get_bloginfo("language"))[0] ?? ''; if($site_country_code === 'de') { - _e( 'Mit Klicken auf '.apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ).' akzeptieren Sie die Ratepay Zahlungsbedingungen und erklären sich mit der Durchführung einer Risikoprüfung durch Ratepay, unseren Partner, einverstanden. Sie akzeptieren auch PayPals Datenschutzerklärung. Falls Ihre Transaktion per Kauf auf Rechnung erfolgreich abgewickelt werden kann, wird der Kaufpreis an Ratepay abgetreten und Sie dürfen nur an Ratepay überweisen, nicht an den Händler.', 'woocommerce-paypal-payments' ); + _e( 'Mit Klicken auf '.apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ).' akzeptieren Sie die Ratepay Zahlungsbedingungen und erklären sich mit der Durchführung einer Risikoprüfung durch Ratepay, unseren Partner, einverstanden. Sie akzeptieren auch PayPals Datenschutzerklärung. Falls Ihre Transaktion per Kauf auf Rechnung erfolgreich abgewickelt werden kann, wird der Kaufpreis an Ratepay abgetreten und Sie dürfen nur an Ratepay überweisen, nicht an den Händler.', 'woocommerce-paypal-payments' ); } else { - _e( 'By clicking on '.apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ).', you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); + _e( 'By clicking on '.apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ).', you agree to the terms of payment and performance of a risk check from the payment partner, Ratepay. You also agree to PayPal’s privacy statement. If your request to purchase upon invoice is accepted, the purchase price claim will be assigned to Ratepay, and you may only pay Ratepay, not the merchant.', 'woocommerce-paypal-payments' ); } echo '
    '; From e9cf8187995fb72cb31b3e11ff39e4cae8bbb2dc Mon Sep 17 00:00:00 2001 From: dinamiko Date: Thu, 14 Apr 2022 17:17:56 +0200 Subject: [PATCH 048/163] Fix phpcd (WIP) --- modules/ppcp-api-client/src/Entity/Item.php | 12 +- .../src/Entity/OrderStatus.php | 16 +-- .../src/Factory/ItemFactory.php | 8 +- .../src/Repository/PartnerReferralsData.php | 3 + modules/ppcp-onboarding/services.php | 5 +- .../src/Assets/OnboardingAssets.php | 4 +- .../src/Endpoint/PayUponInvoiceEndpoint.php | 62 +++++++-- .../ppcp-onboarding/src/OnboardingModule.php | 2 +- .../src/Render/OnboardingOptionsRenderer.php | 26 ++-- modules/ppcp-wc-gateway/services.php | 74 +++++----- .../src/Gateway/PayPalGateway.php | 7 +- .../src/Gateway/PayUponInvoice/FraudNet.php | 28 +++- .../PayUponInvoice/FraudNetSessionId.php | 20 ++- .../FraudNetSourceWebsiteId.php | 32 ++++- .../Gateway/PayUponInvoice/OrderEndpoint.php | 78 ++++++++--- .../Gateway/PayUponInvoice/PayUponInvoice.php | 66 +++++++-- .../PayUponInvoice/PayUponInvoiceGateway.php | 32 ++++- .../Gateway/PayUponInvoice/PaymentSource.php | 131 ++++++++++++++---- .../PayUponInvoice/PaymentSourceFactory.php | 34 +++-- .../src/Settings/SectionsRenderer.php | 10 +- .../ppcp-wc-gateway/src/WCGatewayModule.php | 2 +- .../src/Handler/CheckoutOrderApproved.php | 2 +- .../src/Handler/CheckoutOrderCompleted.php | 2 +- .../src/Handler/PaymentCaptureCompleted.php | 6 +- 24 files changed, 487 insertions(+), 175 deletions(-) diff --git a/modules/ppcp-api-client/src/Entity/Item.php b/modules/ppcp-api-client/src/Entity/Item.php index dd661301e..93576e86a 100644 --- a/modules/ppcp-api-client/src/Entity/Item.php +++ b/modules/ppcp-api-client/src/Entity/Item.php @@ -83,6 +83,7 @@ class Item { * @param Money|null $tax The tax. * @param string $sku The SKU. * @param string $category The category. + * @param float $tax_rate The tax rate. */ public function __construct( string $name, @@ -102,8 +103,8 @@ class Item { $this->tax = $tax; $this->sku = $sku; $this->category = ( self::DIGITAL_GOODS === $category ) ? self::DIGITAL_GOODS : self::PHYSICAL_GOODS; - $this->category = $category; - $this->tax_rate = $tax_rate; + $this->category = $category; + $this->tax_rate = $tax_rate; } /** @@ -174,9 +175,8 @@ class Item { * * @return float */ - public function tax_rate():float - { - return round((float) $this->tax_rate, 2); + public function tax_rate():float { + return round( (float) $this->tax_rate, 2 ); } /** @@ -198,7 +198,7 @@ class Item { $item['tax'] = $this->tax()->to_array(); } - if ($this->tax_rate()) { + if ( $this->tax_rate() ) { $item['tax_rate'] = (string) $this->tax_rate(); } diff --git a/modules/ppcp-api-client/src/Entity/OrderStatus.php b/modules/ppcp-api-client/src/Entity/OrderStatus.php index 397ae8b64..e2dec053b 100644 --- a/modules/ppcp-api-client/src/Entity/OrderStatus.php +++ b/modules/ppcp-api-client/src/Entity/OrderStatus.php @@ -15,14 +15,14 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; * Class OrderStatus */ class OrderStatus { - const INTERNAL = 'INTERNAL'; - const CREATED = 'CREATED'; - const SAVED = 'SAVED'; - const APPROVED = 'APPROVED'; - const VOIDED = 'VOIDED'; - const COMPLETED = 'COMPLETED'; - const PENDING_APPROVAL = 'PENDING_APPROVAL'; - const VALID_STATUS = array( + const INTERNAL = 'INTERNAL'; + const CREATED = 'CREATED'; + const SAVED = 'SAVED'; + const APPROVED = 'APPROVED'; + const VOIDED = 'VOIDED'; + const COMPLETED = 'COMPLETED'; + const PENDING_APPROVAL = 'PENDING_APPROVAL'; + const VALID_STATUS = array( self::INTERNAL, self::CREATED, self::SAVED, diff --git a/modules/ppcp-api-client/src/Factory/ItemFactory.php b/modules/ppcp-api-client/src/Factory/ItemFactory.php index aa8be50c4..3bd277807 100644 --- a/modules/ppcp-api-client/src/Factory/ItemFactory.php +++ b/modules/ppcp-api-client/src/Factory/ItemFactory.php @@ -58,7 +58,7 @@ class ItemFactory { $price_without_tax = (float) wc_get_price_excluding_tax( $product ); $price_without_tax_rounded = round( $price_without_tax, 2 ); $tax = round( $price - $price_without_tax_rounded, 2 ); - $tax_rates = WC_Tax::get_rates($product->get_tax_class()); + $tax_rates = WC_Tax::get_rates( $product->get_tax_class() ); $tax = new Money( $tax + $shipping_tax, $this->currency ); $tax = new Money( $tax, $this->currency ); return new Item( @@ -69,7 +69,7 @@ class ItemFactory { $tax, $product->get_sku(), ( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS, - reset($tax_rates)['rate'] ?? 0 + reset( $tax_rates )['rate'] ?? 0 ); }, $cart->get_cart_contents() @@ -141,7 +141,7 @@ class ItemFactory { $price_without_tax_rounded = round( $price_without_tax, 2 ); $tax = round( $price - $price_without_tax_rounded, 2 ); $tax = new Money( $tax, $currency ); - $tax_rates = WC_Tax::get_rates($product->get_tax_class()); + $tax_rates = WC_Tax::get_rates( $product->get_tax_class() ); return new Item( mb_substr( $product->get_name(), 0, 127 ), @@ -151,7 +151,7 @@ class ItemFactory { $tax, $product->get_sku(), ( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS, - reset($tax_rates)['rate'] ?? 0 + reset( $tax_rates )['rate'] ?? 0 ); } diff --git a/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php b/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php index d8ada8567..7bf902dcb 100644 --- a/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php +++ b/modules/ppcp-api-client/src/Repository/PartnerReferralsData.php @@ -72,6 +72,9 @@ class PartnerReferralsData { * @return array */ public function data(): array { + /** + * Returns the partners referrals data. + */ return apply_filters( 'ppcp_partner_referrals_data', array( diff --git a/modules/ppcp-onboarding/services.php b/modules/ppcp-onboarding/services.php index 29301c85e..d92446054 100644 --- a/modules/ppcp-onboarding/services.php +++ b/modules/ppcp-onboarding/services.php @@ -187,10 +187,11 @@ return array( $logger ); }, - 'onboarding.endpoint.pui' => static function(ContainerInterface $container) : PayUponInvoiceEndpoint { + 'onboarding.endpoint.pui' => static function( ContainerInterface $container ) : PayUponInvoiceEndpoint { return new PayUponInvoiceEndpoint( $container->get( 'wcgateway.settings' ), - $container->get( 'button.request-data' ) + $container->get( 'button.request-data' ), + $container->get( 'woocommerce.logger.woocommerce' ) ); }, 'api.endpoint.partner-referrals-sandbox' => static function ( ContainerInterface $container ) : PartnerReferrals { diff --git a/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php b/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php index 8f669e9b4..8c65cc803 100644 --- a/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php +++ b/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php @@ -145,8 +145,8 @@ class OnboardingAssets { 'error_messages' => array( 'no_credentials' => __( 'API credentials must be entered to save the settings.', 'woocommerce-paypal-payments' ), ), - 'pui_endpoint' => \WC_AJAX::get_endpoint( 'ppc-pui' ), - 'pui_nonce' => wp_create_nonce( 'ppc-pui' ), + 'pui_endpoint' => \WC_AJAX::get_endpoint( 'ppc-pui' ), + 'pui_nonce' => wp_create_nonce( 'ppc-pui' ), ); } diff --git a/modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php b/modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php index 474840122..6700236df 100644 --- a/modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php +++ b/modules/ppcp-onboarding/src/Endpoint/PayUponInvoiceEndpoint.php @@ -9,47 +9,83 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Onboarding\Endpoint; +use Exception; +use Psr\Log\LoggerInterface; use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface; use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; +use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; +/** + * Class PayUponInvoiceEndpoint + */ class PayUponInvoiceEndpoint implements EndpointInterface { /** + * The settings. + * * @var Settings */ protected $settings; /** + * The request data. + * * @var RequestData */ protected $request_data; - public function __construct(Settings $settings, RequestData $request_data) - { - $this->settings = $settings; + /** + * The logger. + * + * @var LoggerInterface + */ + protected $logger; + + /** + * PayUponInvoiceEndpoint constructor. + * + * @param Settings $settings The settings. + * @param RequestData $request_data The request data. + * @param LoggerInterface $logger The logger. + */ + public function __construct( Settings $settings, RequestData $request_data, LoggerInterface $logger ) { + $this->settings = $settings; $this->request_data = $request_data; + $this->logger = $logger; } - public static function nonce(): string - { + /** + * The nonce. + * + * @return string + */ + public static function nonce(): string { return 'ppc-pui'; } - public function handle_request(): bool - { + /** + * * Handles the request. + * + * @return bool + * @throws NotFoundException When order not found or handling failed. + */ + public function handle_request(): bool { try { $data = $this->request_data->read_request( $this->nonce() ); - $this->settings->set('ppcp-onboarding-pui', $data['checked']); + $this->settings->set( 'ppcp-onboarding-pui', $data['checked'] ); $this->settings->persist(); - } catch (\Exception $exception) { - + } catch ( Exception $exception ) { + $this->logger->error( $exception->getMessage() ); } - wp_send_json_success([ - $this->settings->get('ppcp-onboarding-pui'), - ]); + wp_send_json_success( + array( + $this->settings->get( 'ppcp-onboarding-pui' ), + ) + ); + return true; } } diff --git a/modules/ppcp-onboarding/src/OnboardingModule.php b/modules/ppcp-onboarding/src/OnboardingModule.php index 3f35cfd9e..767d47839 100644 --- a/modules/ppcp-onboarding/src/OnboardingModule.php +++ b/modules/ppcp-onboarding/src/OnboardingModule.php @@ -97,7 +97,7 @@ class OnboardingModule implements ModuleInterface { ); add_action( - 'wc_ajax_' . 'ppc-pui', + 'wc_ajax_ppc-pui', static function () use ( $c ) { $endpoint = $c->get( 'onboarding.endpoint.pui' ); $endpoint->handle_request(); diff --git a/modules/ppcp-onboarding/src/Render/OnboardingOptionsRenderer.php b/modules/ppcp-onboarding/src/Render/OnboardingOptionsRenderer.php index 24c1c2340..dc02c0d9d 100644 --- a/modules/ppcp-onboarding/src/Render/OnboardingOptionsRenderer.php +++ b/modules/ppcp-onboarding/src/Render/OnboardingOptionsRenderer.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Onboarding\Render; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; +use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; /** * Class OnboardingRenderer @@ -30,6 +31,8 @@ class OnboardingOptionsRenderer { private $country; /** + * The settings. + * * @var Settings */ protected $settings; @@ -37,13 +40,14 @@ class OnboardingOptionsRenderer { /** * OnboardingOptionsRenderer constructor. * - * @param string $module_url The module url (for assets). - * @param string $country 2-letter country code of the shop. + * @param string $module_url The module url (for assets). + * @param string $country 2-letter country code of the shop. + * @param Settings $settings The settings. */ - public function __construct( string $module_url, string $country, Settings $settings) { + public function __construct( string $module_url, string $country, Settings $settings ) { $this->module_url = $module_url; $this->country = $country; - $this->settings = $settings; + $this->settings = $settings; } /** @@ -66,16 +70,22 @@ class OnboardingOptionsRenderer {
  • ' . $this->render_dcc( $is_shop_supports_dcc ) . '
  • ' . $this->render_pui_option() -. ''; + . ''; } + /** + * Renders pui option. + * + * @return string + * @throws NotFoundException When setting is not found. + */ private function render_pui_option(): string { - if($this->country === 'DE') { + if ( 'DE' === $this->country ) { $checked = 'checked'; - if($this->settings->has('ppcp-onboarding-pui') && $this->settings->get('ppcp-onboarding-pui') !== '1') { + if ( $this->settings->has( 'ppcp-onboarding-pui' ) && $this->settings->get( 'ppcp-onboarding-pui' ) !== '1' ) { $checked = ''; } - return '