mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-31 06:52:50 +08:00
Merge branch 'trunk' into PCP-2347-new-feature-accelerated-checkout
# Conflicts: # modules.php
This commit is contained in:
commit
9cb63040d8
129 changed files with 7018 additions and 1124 deletions
2
.github/workflows/e2e.yml
vendored
2
.github/workflows/e2e.yml
vendored
|
@ -1,6 +1,6 @@
|
|||
name: e2e tests
|
||||
|
||||
on: [push]
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
|
@ -87,6 +87,32 @@ function ppcp_capture_order( WC_Order $wc_order ): void {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reauthorizes the PayPal order.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @throws InvalidArgumentException When the order cannot be captured.
|
||||
* @throws Exception When the operation fails.
|
||||
*/
|
||||
function ppcp_reauthorize_order( WC_Order $wc_order ): void {
|
||||
$intent = strtoupper( (string) $wc_order->get_meta( PayPalGateway::INTENT_META_KEY ) );
|
||||
|
||||
if ( $intent !== 'AUTHORIZE' ) {
|
||||
throw new InvalidArgumentException( 'Only orders with "authorize" intent can be reauthorized.' );
|
||||
}
|
||||
$captured = wc_string_to_bool( $wc_order->get_meta( AuthorizedPaymentsProcessor::CAPTURED_META_KEY ) );
|
||||
if ( $captured ) {
|
||||
throw new InvalidArgumentException( 'The order is already captured.' );
|
||||
}
|
||||
|
||||
$authorized_payment_processor = PPCP::container()->get( 'wcgateway.processor.authorized-payments' );
|
||||
assert( $authorized_payment_processor instanceof AuthorizedPaymentsProcessor );
|
||||
|
||||
if ( $authorized_payment_processor->reauthorize_payment( $wc_order ) !== AuthorizedPaymentsProcessor::SUCCESSFUL ) {
|
||||
throw new RuntimeException( $authorized_payment_processor->reauthorization_failure_reason() ?: 'Reauthorization failed.' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refunds the PayPal order.
|
||||
* Note that you can use wc_refund_payment() to trigger the refund in WC and PayPal.
|
||||
|
|
|
@ -1,5 +1,54 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 2.6.1 - 2024-04-09 =
|
||||
* Fix - Payment tokens fixes and adjustments #2106
|
||||
* Fix - Pay upon Invoice: Add input validation to Experience Context fields #2092
|
||||
* Fix - Disable markup in get_plugin_data() returns to fix an issue with wptexturize() #2094
|
||||
* Fix - Problem changing the shipping option in block pages #2142
|
||||
* Fix - Saved payment token deleted after payment with another saved payment token #2146
|
||||
* Enhancement - Pay later messaging configurator improvements #2107
|
||||
* Enhancement - Replace the middleware URL from connect.woocommerce.com to api.woocommerce.com/integrations #2130
|
||||
* Enhancement - Remove all Sofort references as it has been deprecated #2124
|
||||
* Enhancement - Improve funding source names #2118
|
||||
* Enhancement - More fraud prevention capabilities by storing additional data in the order #2125
|
||||
* Enhancement - Update ACDC currency eligibility for AMEX #2129
|
||||
* Enhancement - Sync shipping options with Venmo when skipping final confirmation on Checkout #2108
|
||||
* Enhancement - Card Fields: Add a filter for the CVC field and update the placeholder to match the label #2089
|
||||
* Enhancement - Product Title: Sanitize before sending to PayPal #2090
|
||||
* Enhancement - Add filter for disabling permit_multiple_payment_tokens vault attribute #2136
|
||||
* Enhancement - Filter to hide PayPal email address not working on order detail #2137
|
||||
|
||||
= 2.6.0 - 2024-03-20 =
|
||||
* Fix - invoice_id not included in API call when creating payment with saved card #2086
|
||||
* Fix - Typo in SCA indicators for ACDC Vault transactions #2083
|
||||
* Fix - Payments with saved card tokens use Capture intent when Authorize is configured #2069
|
||||
* Fix - WooPayments multi-currency causing currency mismatch error on Block Cart & Checkout pages #2054
|
||||
* Fix - "Must pass createSubscription with intent=subscription" error with PayPal Subscriptions mode #2058
|
||||
* Fix - "Proceed to PayPal" button displayed for Free trial PayPal Subscription products when payment token is saved #2041
|
||||
* Fix - ACDC payments with new credit card may fail when debugging is enabled (JSON malformed by warning) #2051
|
||||
* Enhancement - Add Pay Later Messaging block #1897
|
||||
* Enhancement - Submit the form instead of refreshing the page to show the save notice #2081
|
||||
* Enhancement - Integrate pay later messaging block with the messaging configurator #2080
|
||||
* Enhancement - Reauthorize authorized payments #2062
|
||||
* Enhancement - Do not handle VAULT.PAYMENT-TOKEN.CREATED webhook for Vault v3 #2079
|
||||
* Enhancement - Improve the messaging configurator styles #2053
|
||||
* Enhancement - Ensure PayPal Vaulting is not selected as Subscriptions Mode when Reference Transactions are disabled #2057
|
||||
* Enhancement - Pay later messaging configurator & messaging block adjustments #2096
|
||||
|
||||
= 2.5.4 - 2024-02-27 =
|
||||
* Fix - Cannot enable Apple Pay when API credentials were manually created #2015
|
||||
* Fix - Cart simulation type error #1943
|
||||
* Enhancement - Apple Pay recurring payments #1986
|
||||
* Enhancement - Real Time Account Updater (RTAU) integration #2027
|
||||
* Enhancement - Prepare the SKU for sending to PayPal #2033
|
||||
* Enhancement - Store the Card Brand in Address Verification Result instead of 3DS authentication result #2026
|
||||
* Enhancement - Update country eligibility for AdvancedCard Processing, Apple Pay, Google Pay #2019
|
||||
* Enhancement - Disable PayPal Vaulting setting instead of hiding it when Reference Transactions not available #2029
|
||||
* Enhancement - Store three d secure enrollment status and authentication status responses in wc order #1980
|
||||
* Enhancement - Add more checks to prevent "PayPal order ID not found" errors #2038
|
||||
* Enhancement - Disable messaging configurator when vault is enabled #2042
|
||||
* Feature preview - Pay Later Messaging configurator #1924
|
||||
|
||||
= 2.5.3 - 2024-02-06 =
|
||||
* Fix - Free trial subscription products using PayPal Vaulting when PayPal Subscriptions configured as Subscriptions Mode #1979
|
||||
* Fix - Pay by link - Germany - PayPal buttons are not visible on Pay for order page #2014
|
||||
|
|
350
composer.lock
generated
350
composer.lock
generated
|
@ -8,20 +8,20 @@
|
|||
"packages": [
|
||||
{
|
||||
"name": "container-interop/service-provider",
|
||||
"version": "v0.4.0",
|
||||
"version": "v0.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/container-interop/service-provider.git",
|
||||
"reference": "4969b9e49460690b7430b3f1a87cab07be61418a"
|
||||
"reference": "e04441ca21ef03e10dce70b0af29269281eec6dc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/container-interop/service-provider/zipball/4969b9e49460690b7430b3f1a87cab07be61418a",
|
||||
"reference": "4969b9e49460690b7430b3f1a87cab07be61418a",
|
||||
"url": "https://api.github.com/repos/container-interop/service-provider/zipball/e04441ca21ef03e10dce70b0af29269281eec6dc",
|
||||
"reference": "e04441ca21ef03e10dce70b0af29269281eec6dc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"psr/container": "^1.0"
|
||||
"psr/container": "^1.0 || ^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -37,9 +37,9 @@
|
|||
"homepage": "https://github.com/container-interop/service-provider",
|
||||
"support": {
|
||||
"issues": "https://github.com/container-interop/service-provider/issues",
|
||||
"source": "https://github.com/container-interop/service-provider/tree/master"
|
||||
"source": "https://github.com/container-interop/service-provider/tree/v0.4.1"
|
||||
},
|
||||
"time": "2017-09-20T14:13:36+00:00"
|
||||
"time": "2023-12-14T14:50:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dhii/human-readable-interface",
|
||||
|
@ -438,16 +438,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
|
||||
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
|
||||
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
|
||||
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -455,9 +455,6 @@
|
|||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
|
@ -501,7 +498,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -517,7 +514,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "wikimedia/composer-merge-plugin",
|
||||
|
@ -797,16 +794,16 @@
|
|||
},
|
||||
{
|
||||
"name": "antecedent/patchwork",
|
||||
"version": "2.1.25",
|
||||
"version": "2.1.28",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/antecedent/patchwork.git",
|
||||
"reference": "17314e042d45e0dacb0a494c2d1ef50e7621136a"
|
||||
"reference": "6b30aff81ebadf0f2feb9268d3e08385cebcc08d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/antecedent/patchwork/zipball/17314e042d45e0dacb0a494c2d1ef50e7621136a",
|
||||
"reference": "17314e042d45e0dacb0a494c2d1ef50e7621136a",
|
||||
"url": "https://api.github.com/repos/antecedent/patchwork/zipball/6b30aff81ebadf0f2feb9268d3e08385cebcc08d",
|
||||
"reference": "6b30aff81ebadf0f2feb9268d3e08385cebcc08d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -827,7 +824,7 @@
|
|||
}
|
||||
],
|
||||
"description": "Method redefinition (monkey-patching) functionality for PHP.",
|
||||
"homepage": "http://patchwork2.org/",
|
||||
"homepage": "https://antecedent.github.io/patchwork/",
|
||||
"keywords": [
|
||||
"aop",
|
||||
"aspect",
|
||||
|
@ -839,9 +836,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/antecedent/patchwork/issues",
|
||||
"source": "https://github.com/antecedent/patchwork/tree/2.1.25"
|
||||
"source": "https://github.com/antecedent/patchwork/tree/2.1.28"
|
||||
},
|
||||
"time": "2023-02-19T12:51:24+00:00"
|
||||
"time": "2024-02-06T09:26:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brain/monkey",
|
||||
|
@ -988,16 +985,16 @@
|
|||
},
|
||||
{
|
||||
"name": "composer/pcre",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/pcre.git",
|
||||
"reference": "3fdb2807b31a78a40ad89570e30ec77466c98717"
|
||||
"reference": "b439557066cd445732fa57cbc8d905394b4db8a0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/3fdb2807b31a78a40ad89570e30ec77466c98717",
|
||||
"reference": "3fdb2807b31a78a40ad89570e30ec77466c98717",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/b439557066cd445732fa57cbc8d905394b4db8a0",
|
||||
"reference": "b439557066cd445732fa57cbc8d905394b4db8a0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1039,7 +1036,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/pcre/issues",
|
||||
"source": "https://github.com/composer/pcre/tree/2.1.0"
|
||||
"source": "https://github.com/composer/pcre/tree/2.1.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1055,20 +1052,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-16T18:32:04+00:00"
|
||||
"time": "2023-10-11T07:10:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
"version": "3.3.2",
|
||||
"version": "3.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/semver.git",
|
||||
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
|
||||
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
|
||||
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
|
||||
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1118,9 +1115,9 @@
|
|||
"versioning"
|
||||
],
|
||||
"support": {
|
||||
"irc": "irc://irc.freenode.org/composer",
|
||||
"irc": "ircs://irc.libera.chat:6697/composer",
|
||||
"issues": "https://github.com/composer/semver/issues",
|
||||
"source": "https://github.com/composer/semver/tree/3.3.2"
|
||||
"source": "https://github.com/composer/semver/tree/3.4.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1136,7 +1133,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-04-01T19:23:25+00:00"
|
||||
"time": "2023-08-31T09:50:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/xdebug-handler",
|
||||
|
@ -1604,24 +1601,24 @@
|
|||
},
|
||||
{
|
||||
"name": "graham-campbell/result-type",
|
||||
"version": "v1.1.1",
|
||||
"version": "v1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/GrahamCampbell/Result-Type.git",
|
||||
"reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831"
|
||||
"reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831",
|
||||
"reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831",
|
||||
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/fbd48bce38f73f8a4ec8583362e732e4095e5862",
|
||||
"reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"phpoption/phpoption": "^1.9.1"
|
||||
"phpoption/phpoption": "^1.9.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12"
|
||||
"phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -1650,7 +1647,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/GrahamCampbell/Result-Type/issues",
|
||||
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.1"
|
||||
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1662,7 +1659,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-25T20:23:15+00:00"
|
||||
"time": "2023-11-12T22:16:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hamcrest/hamcrest-php",
|
||||
|
@ -1845,16 +1842,16 @@
|
|||
},
|
||||
{
|
||||
"name": "netresearch/jsonmapper",
|
||||
"version": "v4.2.0",
|
||||
"version": "v4.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cweiske/jsonmapper.git",
|
||||
"reference": "f60565f8c0566a31acf06884cdaa591867ecc956"
|
||||
"reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956",
|
||||
"reference": "f60565f8c0566a31acf06884cdaa591867ecc956",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/132c75c7dd83e45353ebb9c6c9f591952995bbf0",
|
||||
"reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1865,7 +1862,7 @@
|
|||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~7.5 || ~8.0 || ~9.0",
|
||||
"phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0",
|
||||
"squizlabs/php_codesniffer": "~3.5"
|
||||
},
|
||||
"type": "library",
|
||||
|
@ -1890,22 +1887,22 @@
|
|||
"support": {
|
||||
"email": "cweiske@cweiske.de",
|
||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0"
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v4.4.1"
|
||||
},
|
||||
"time": "2023-04-09T17:37:40+00:00"
|
||||
"time": "2024-01-31T06:18:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.16.0",
|
||||
"version": "v4.18.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "19526a33fb561ef417e822e85f08a00db4059c17"
|
||||
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17",
|
||||
"reference": "19526a33fb561ef417e822e85f08a00db4059c17",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999",
|
||||
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1946,9 +1943,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0"
|
||||
},
|
||||
"time": "2023-06-25T14:52:30+00:00"
|
||||
"time": "2023-12-10T21:03:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "openlss/lib-array2xml",
|
||||
|
@ -2539,16 +2536,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpoption/phpoption",
|
||||
"version": "1.9.1",
|
||||
"version": "1.9.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/schmittjoh/php-option.git",
|
||||
"reference": "dd3a383e599f49777d8b628dadbb90cae435b87e"
|
||||
"reference": "80735db690fe4fc5c76dfa7f9b770634285fa820"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e",
|
||||
"reference": "dd3a383e599f49777d8b628dadbb90cae435b87e",
|
||||
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/80735db690fe4fc5c76dfa7f9b770634285fa820",
|
||||
"reference": "80735db690fe4fc5c76dfa7f9b770634285fa820",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2556,7 +2553,7 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12"
|
||||
"phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -2598,7 +2595,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/schmittjoh/php-option/issues",
|
||||
"source": "https://github.com/schmittjoh/php-option/tree/1.9.1"
|
||||
"source": "https://github.com/schmittjoh/php-option/tree/1.9.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2610,7 +2607,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-25T19:38:58+00:00"
|
||||
"time": "2023-11-12T21:59:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
@ -2911,16 +2908,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "8.5.33",
|
||||
"version": "8.5.36",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "7d1ff0e8c6b35db78ff13e3e05517d7cbf7aa32e"
|
||||
"reference": "9652df58e06a681429d8cfdaec3c43d6de581d5a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7d1ff0e8c6b35db78ff13e3e05517d7cbf7aa32e",
|
||||
"reference": "7d1ff0e8c6b35db78ff13e3e05517d7cbf7aa32e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9652df58e06a681429d8cfdaec3c43d6de581d5a",
|
||||
"reference": "9652df58e06a681429d8cfdaec3c43d6de581d5a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2950,9 +2947,9 @@
|
|||
"sebastian/version": "^2.0.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-soap": "*",
|
||||
"ext-xdebug": "*",
|
||||
"phpunit/php-invoker": "^2.0.0"
|
||||
"ext-soap": "To be able to generate mocks based on WSDL files",
|
||||
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage",
|
||||
"phpunit/php-invoker": "To allow enforcing time limits"
|
||||
},
|
||||
"bin": [
|
||||
"phpunit"
|
||||
|
@ -2988,7 +2985,8 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.33"
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.36"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3004,7 +3002,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-27T13:04:50+00:00"
|
||||
"time": "2023-12-01T16:52:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
|
@ -3343,16 +3341,16 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
"version": "3.0.2",
|
||||
"version": "3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/global-state.git",
|
||||
"reference": "de036ec91d55d2a9e0db2ba975b512cdb1c23921"
|
||||
"reference": "66783ce213de415b451b904bfef9dda0cf9aeae0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/de036ec91d55d2a9e0db2ba975b512cdb1c23921",
|
||||
"reference": "de036ec91d55d2a9e0db2ba975b512cdb1c23921",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/66783ce213de415b451b904bfef9dda0cf9aeae0",
|
||||
"reference": "66783ce213de415b451b904bfef9dda0cf9aeae0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3395,7 +3393,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/3.0.2"
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/3.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3403,7 +3401,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-02-10T06:55:38+00:00"
|
||||
"time": "2023-08-02T09:23:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/object-enumerator",
|
||||
|
@ -3737,16 +3735,16 @@
|
|||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.7.2",
|
||||
"version": "3.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
||||
"reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879"
|
||||
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
|
||||
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879",
|
||||
"reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7",
|
||||
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3756,11 +3754,11 @@
|
|||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4"
|
||||
},
|
||||
"bin": [
|
||||
"bin/phpcs",
|
||||
"bin/phpcbf"
|
||||
"bin/phpcbf",
|
||||
"bin/phpcs"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -3775,35 +3773,58 @@
|
|||
"authors": [
|
||||
{
|
||||
"name": "Greg Sherwood",
|
||||
"role": "lead"
|
||||
"role": "Former lead"
|
||||
},
|
||||
{
|
||||
"name": "Juliette Reinders Folmer",
|
||||
"role": "Current lead"
|
||||
},
|
||||
{
|
||||
"name": "Contributors",
|
||||
"homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
||||
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
|
||||
"homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
|
||||
"keywords": [
|
||||
"phpcs",
|
||||
"standards",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
|
||||
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
|
||||
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
|
||||
"issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
|
||||
"security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
|
||||
"source": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
|
||||
"wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki"
|
||||
},
|
||||
"time": "2023-02-22T23:07:41+00:00"
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/PHPCSStandards",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/jrfnl",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://opencollective.com/php_codesniffer",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-11T20:47:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.4.26",
|
||||
"version": "v5.4.35",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "b504a3d266ad2bb632f196c0936ef2af5ff6e273"
|
||||
"reference": "dbdf6adcb88d5f83790e1efb57ef4074309d3931"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/b504a3d266ad2bb632f196c0936ef2af5ff6e273",
|
||||
"reference": "b504a3d266ad2bb632f196c0936ef2af5ff6e273",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/dbdf6adcb88d5f83790e1efb57ef4074309d3931",
|
||||
"reference": "dbdf6adcb88d5f83790e1efb57ef4074309d3931",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3873,7 +3894,7 @@
|
|||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v5.4.26"
|
||||
"source": "https://github.com/symfony/console/tree/v5.4.35"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3889,7 +3910,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-07-19T20:11:33+00:00"
|
||||
"time": "2024-01-23T14:28:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
|
@ -3960,16 +3981,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
|
||||
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
|
||||
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
|
||||
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3983,9 +4004,6 @@
|
|||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
|
@ -4022,7 +4040,7 @@
|
|||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4038,20 +4056,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||
"reference": "511a08c03c1960e08a883f4cffcacd219b758354"
|
||||
"reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
|
||||
"reference": "511a08c03c1960e08a883f4cffcacd219b758354",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f",
|
||||
"reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4062,9 +4080,6 @@
|
|||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
|
@ -4103,7 +4118,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4119,20 +4134,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
|
||||
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
|
||||
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
|
||||
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4143,9 +4158,6 @@
|
|||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
|
@ -4187,7 +4199,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4203,20 +4215,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
|
||||
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
|
||||
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4230,9 +4242,6 @@
|
|||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
|
@ -4270,7 +4279,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4286,20 +4295,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php73",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php73.git",
|
||||
"reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9"
|
||||
"reference": "21bd091060673a1177ae842c0ef8fe30893114d2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
|
||||
"reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2",
|
||||
"reference": "21bd091060673a1177ae842c0ef8fe30893114d2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4307,9 +4316,6 @@
|
|||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
|
@ -4349,7 +4355,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-php73/tree/v1.29.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4365,7 +4371,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
|
@ -4452,16 +4458,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v5.4.26",
|
||||
"version": "v5.4.35",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "1181fe9270e373537475e826873b5867b863883c"
|
||||
"reference": "c209c4d0559acce1c9a2067612cfb5d35756edc2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/1181fe9270e373537475e826873b5867b863883c",
|
||||
"reference": "1181fe9270e373537475e826873b5867b863883c",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/c209c4d0559acce1c9a2067612cfb5d35756edc2",
|
||||
"reference": "c209c4d0559acce1c9a2067612cfb5d35756edc2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4518,7 +4524,7 @@
|
|||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v5.4.26"
|
||||
"source": "https://github.com/symfony/string/tree/v5.4.35"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4534,20 +4540,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-06-28T12:46:07+00:00"
|
||||
"time": "2024-01-23T13:51:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theseer/tokenizer.git",
|
||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
|
||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4576,7 +4582,7 @@
|
|||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||
"support": {
|
||||
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.1"
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4584,7 +4590,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-07-28T10:34:58+00:00"
|
||||
"time": "2023-11-20T00:12:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "vimeo/psalm",
|
||||
|
@ -4696,31 +4702,31 @@
|
|||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v5.5.0",
|
||||
"version": "v5.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vlucas/phpdotenv.git",
|
||||
"reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7"
|
||||
"reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7",
|
||||
"reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7",
|
||||
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4",
|
||||
"reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-pcre": "*",
|
||||
"graham-campbell/result-type": "^1.0.2",
|
||||
"php": "^7.1.3 || ^8.0",
|
||||
"phpoption/phpoption": "^1.8",
|
||||
"symfony/polyfill-ctype": "^1.23",
|
||||
"symfony/polyfill-mbstring": "^1.23.1",
|
||||
"symfony/polyfill-php80": "^1.23.1"
|
||||
"graham-campbell/result-type": "^1.1.2",
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"phpoption/phpoption": "^1.9.2",
|
||||
"symfony/polyfill-ctype": "^1.24",
|
||||
"symfony/polyfill-mbstring": "^1.24",
|
||||
"symfony/polyfill-php80": "^1.24"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.4.1",
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"ext-filter": "*",
|
||||
"phpunit/phpunit": "^7.5.20 || ^8.5.30 || ^9.5.25"
|
||||
"phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-filter": "Required to use the boolean validator."
|
||||
|
@ -4732,7 +4738,7 @@
|
|||
"forward-command": true
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "5.5-dev"
|
||||
"dev-master": "5.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -4764,7 +4770,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/vlucas/phpdotenv/issues",
|
||||
"source": "https://github.com/vlucas/phpdotenv/tree/v5.5.0"
|
||||
"source": "https://github.com/vlucas/phpdotenv/tree/v5.6.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4776,7 +4782,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-10-16T01:01:54+00:00"
|
||||
"time": "2023-11-12T22:43:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
|
@ -4996,5 +5002,5 @@
|
|||
"ext-json": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
use WooCommerce\PayPalCommerce\PayLaterBlock\PayLaterBlockModule;
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\PayLaterConfiguratorModule;
|
||||
use WooCommerce\PayPalCommerce\PluginModule;
|
||||
|
||||
return function ( string $root_dir ): iterable {
|
||||
|
@ -67,10 +68,14 @@ return function ( string $root_dir ): iterable {
|
|||
$modules[] = ( require "$modules_dir/ppcp-save-payment-methods/module.php" )();
|
||||
}
|
||||
|
||||
if ( PayLaterBlockModule::is_enabled() ) {
|
||||
if ( PayLaterBlockModule::is_module_loading_required() ) {
|
||||
$modules[] = ( require "$modules_dir/ppcp-paylater-block/module.php" )();
|
||||
}
|
||||
|
||||
if ( PayLaterConfiguratorModule::is_enabled() ) {
|
||||
$modules[] = ( require "$modules_dir/ppcp-paylater-configurator/module.php" )();
|
||||
}
|
||||
|
||||
if ( apply_filters(
|
||||
'woocommerce.feature-flags.woocommerce_paypal_payments.axo_enabled',
|
||||
getenv( 'PCP_AXO_ENABLED' ) === '1'
|
||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\AdminNotices;
|
||||
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Repository\Repository;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||
|
@ -40,6 +42,34 @@ class AdminNotices implements ModuleInterface {
|
|||
$renderer->render();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
Repository::NOTICES_FILTER,
|
||||
/**
|
||||
* Adds persisted notices to the notices array.
|
||||
*
|
||||
* @param array $notices The notices.
|
||||
* @return array
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function ( $notices ) use ( $c ) {
|
||||
if ( ! is_array( $notices ) ) {
|
||||
return $notices;
|
||||
}
|
||||
|
||||
$admin_notices = $c->get( 'admin-notices.repository' );
|
||||
assert( $admin_notices instanceof Repository );
|
||||
|
||||
$persisted_notices = $admin_notices->get_persisted_and_clear();
|
||||
|
||||
if ( $persisted_notices ) {
|
||||
$notices = array_merge( $notices, $persisted_notices );
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -92,4 +92,18 @@ class Message {
|
|||
public function wrapper(): string {
|
||||
return $this->wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'type' => $this->type,
|
||||
'message' => $this->message,
|
||||
'dismissable' => $this->dismissable,
|
||||
'wrapper' => $this->wrapper,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
|||
class Repository implements RepositoryInterface {
|
||||
|
||||
const NOTICES_FILTER = 'ppcp.admin-notices.current-notices';
|
||||
const PERSISTED_NOTICES_OPTION = 'woocommerce_ppcp-admin-notices';
|
||||
|
||||
/**
|
||||
* Returns the current messages.
|
||||
|
@ -37,4 +38,40 @@ class Repository implements RepositoryInterface {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a message to persist between page reloads.
|
||||
*
|
||||
* @param Message $message The message.
|
||||
* @return void
|
||||
*/
|
||||
public function persist( Message $message ): void {
|
||||
$persisted_notices = get_option( self::PERSISTED_NOTICES_OPTION ) ?: array();
|
||||
|
||||
$persisted_notices[] = $message->to_array();
|
||||
|
||||
update_option( self::PERSISTED_NOTICES_OPTION, $persisted_notices );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a message to persist between page reloads.
|
||||
*
|
||||
* @return array|Message[]
|
||||
*/
|
||||
public function get_persisted_and_clear(): array {
|
||||
$notices = array();
|
||||
|
||||
$persisted_data = get_option( self::PERSISTED_NOTICES_OPTION ) ?: array();
|
||||
foreach ( $persisted_data as $notice_data ) {
|
||||
$notices[] = new Message(
|
||||
(string) ( $notice_data['message'] ?? '' ),
|
||||
(string) ( $notice_data['type'] ?? '' ),
|
||||
(bool) ( $notice_data['dismissable'] ?? true ),
|
||||
(string) ( $notice_data['wrapper'] ?? '' )
|
||||
);
|
||||
}
|
||||
|
||||
update_option( self::PERSISTED_NOTICES_OPTION, array(), true );
|
||||
return $notices;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -417,7 +417,7 @@ return array(
|
|||
return new PaymentsFactory( $authorizations_factory, $capture_factory, $refund_factory );
|
||||
},
|
||||
'api.factory.authorization' => static function ( ContainerInterface $container ): AuthorizationFactory {
|
||||
return new AuthorizationFactory();
|
||||
return new AuthorizationFactory( $container->get( 'api.factory.fraud-processor-response' ) );
|
||||
},
|
||||
'api.factory.exchange-rate' => static function ( ContainerInterface $container ): ExchangeRateFactory {
|
||||
return new ExchangeRateFactory();
|
||||
|
@ -626,6 +626,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'AT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'BE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -914,6 +938,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -1310,11 +1358,28 @@ return array(
|
|||
'USD',
|
||||
),
|
||||
'NO' => array(
|
||||
'EUR',
|
||||
'USD',
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
@ -1335,35 +1400,40 @@ return array(
|
|||
'visa' => array(),
|
||||
'amex' => array( 'AUD' ),
|
||||
),
|
||||
'AT' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array(),
|
||||
),
|
||||
'BE' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD', 'CAD' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'BG' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'CY' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'CZ' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'CZK' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'DE' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'DK' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'DKK' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'EE' => array(
|
||||
'mastercard' => array(),
|
||||
|
@ -1373,37 +1443,42 @@ return array(
|
|||
'ES' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'FI' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'FR' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'GB' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'GBP', 'USD' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'GR' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'HU' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'HUF' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'IE' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array(),
|
||||
),
|
||||
'IT' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'US' => array(
|
||||
'mastercard' => array(),
|
||||
|
@ -1414,28 +1489,33 @@ return array(
|
|||
'CA' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'CAD' ),
|
||||
'amex' => array( 'CAD', 'USD' ),
|
||||
'jcb' => array( 'CAD' ),
|
||||
),
|
||||
'LI' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array(),
|
||||
),
|
||||
'LT' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'LU' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'LV' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'MT' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'MX' => array(
|
||||
'mastercard' => array(),
|
||||
|
@ -1445,42 +1525,42 @@ return array(
|
|||
'NL' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'NO' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'NOK' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'PL' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD', 'GBP', 'PLN' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'PT' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD', 'CAD', 'GBP' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'RO' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'USD' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'SE' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'SEK' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'SI' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'SK' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'EUR', 'GBP' ),
|
||||
'amex' => array(),
|
||||
),
|
||||
'JP' => array(
|
||||
'mastercard' => array(),
|
||||
|
|
|
@ -115,7 +115,7 @@ class PaymentMethodTokensEndpoint {
|
|||
* @throws RuntimeException When something when wrong with the request.
|
||||
* @throws PayPalApiException When something when wrong setting up the token.
|
||||
*/
|
||||
public function payment_tokens( PaymentSource $payment_source ): stdClass {
|
||||
public function create_payment_token( PaymentSource $payment_source ): stdClass {
|
||||
$data = array(
|
||||
'payment_source' => array(
|
||||
$payment_source->name() => $payment_source->properties(),
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WP_Error;
|
||||
|
@ -92,4 +93,53 @@ class PaymentTokensEndpoint {
|
|||
throw new PayPalApiException( $json, $status_code );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all payment tokens for the given customer.
|
||||
*
|
||||
* @param string $customer_id PayPal customer id.
|
||||
* @return array
|
||||
*
|
||||
* @throws RuntimeException When something went wrong with the request.
|
||||
* @throws PayPalApiException When something went wrong getting the payment tokens.
|
||||
*/
|
||||
public function payment_tokens_for_customer( string $customer_id ): array {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v3/vault/payment-tokens?customer_id=' . $customer_id;
|
||||
$args = array(
|
||||
'method' => 'GET',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( $response instanceof WP_Error ) {
|
||||
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 );
|
||||
}
|
||||
|
||||
$tokens = array();
|
||||
$payment_tokens = $json->payment_tokens ?? array();
|
||||
foreach ( $payment_tokens as $payment_token ) {
|
||||
$name = array_key_first( (array) $payment_token->payment_source ) ?? '';
|
||||
if ( $name ) {
|
||||
$tokens[] = array(
|
||||
'id' => $payment_token->id,
|
||||
'payment_source' => new PaymentSource(
|
||||
$name,
|
||||
$payment_token->payment_source->$name
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,6 +193,53 @@ class PaymentsEndpoint {
|
|||
return $this->capture_factory->from_paypal_response( $json );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reauthorizes an order.
|
||||
*
|
||||
* @param string $authorization_id The id.
|
||||
* @param Money|null $amount The amount to capture. If not specified, the whole authorized amount is captured.
|
||||
*
|
||||
* @return string
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function reauthorize( string $authorization_id, ?Money $amount = null ) : string {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/payments/authorizations/' . $authorization_id . '/reauthorize';
|
||||
|
||||
$data = array();
|
||||
if ( $amount ) {
|
||||
$data['amount'] = $amount->to_array();
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
),
|
||||
'body' => wp_json_encode( $data, JSON_FORCE_OBJECT ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
$json = json_decode( $response['body'] );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
throw new RuntimeException( 'Could not reauthorize authorized payment.' );
|
||||
}
|
||||
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 201 !== $status_code || ! is_object( $json ) ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
|
||||
return $json->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refunds a payment.
|
||||
*
|
||||
|
|
|
@ -28,19 +28,29 @@ class Authorization {
|
|||
*/
|
||||
private $authorization_status;
|
||||
|
||||
/**
|
||||
* The fraud processor response (AVS, CVV ...).
|
||||
*
|
||||
* @var FraudProcessorResponse|null
|
||||
*/
|
||||
protected $fraud_processor_response;
|
||||
|
||||
/**
|
||||
* Authorization constructor.
|
||||
*
|
||||
* @param string $id The id.
|
||||
* @param AuthorizationStatus $authorization_status The status.
|
||||
* @param FraudProcessorResponse|null $fraud_processor_response The fraud processor response (AVS, CVV ...).
|
||||
*/
|
||||
public function __construct(
|
||||
string $id,
|
||||
AuthorizationStatus $authorization_status
|
||||
AuthorizationStatus $authorization_status,
|
||||
?FraudProcessorResponse $fraud_processor_response
|
||||
) {
|
||||
|
||||
$this->id = $id;
|
||||
$this->authorization_status = $authorization_status;
|
||||
$this->fraud_processor_response = $fraud_processor_response;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,15 +81,30 @@ class Authorization {
|
|||
$this->authorization_status->is( AuthorizationStatus::PENDING );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fraud processor response (AVS, CVV ...).
|
||||
*
|
||||
* @return FraudProcessorResponse|null
|
||||
*/
|
||||
public function fraud_processor_response() : ?FraudProcessorResponse {
|
||||
return $this->fraud_processor_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
$data = array(
|
||||
'id' => $this->id,
|
||||
'status' => $this->authorization_status->name(),
|
||||
);
|
||||
|
||||
if ( $this->fraud_processor_response ) {
|
||||
$data['fraud_processor_response'] = $this->fraud_processor_response->to_array();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,19 +21,37 @@ class SellerStatus {
|
|||
*/
|
||||
private $products;
|
||||
|
||||
/**
|
||||
* The capabilities.
|
||||
*
|
||||
* @var SellerStatusCapability[]
|
||||
*/
|
||||
private $capabilities;
|
||||
|
||||
/**
|
||||
* SellerStatus constructor.
|
||||
*
|
||||
* @param SellerStatusProduct[] $products The products.
|
||||
* @param SellerStatusCapability[] $capabilities The capabilities.
|
||||
*
|
||||
* @psalm-suppress RedundantConditionGivenDocblockType
|
||||
*/
|
||||
public function __construct( array $products ) {
|
||||
public function __construct( array $products, array $capabilities ) {
|
||||
foreach ( $products as $key => $product ) {
|
||||
if ( is_a( $product, SellerStatusProduct::class ) ) {
|
||||
continue;
|
||||
}
|
||||
unset( $products[ $key ] );
|
||||
}
|
||||
foreach ( $capabilities as $key => $capability ) {
|
||||
if ( is_a( $capability, SellerStatusCapability::class ) ) {
|
||||
continue;
|
||||
}
|
||||
unset( $capabilities[ $key ] );
|
||||
}
|
||||
|
||||
$this->products = $products;
|
||||
$this->capabilities = $capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,6 +63,15 @@ class SellerStatus {
|
|||
return $this->products;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the capabilities.
|
||||
*
|
||||
* @return SellerStatusCapability[]
|
||||
*/
|
||||
public function capabilities() : array {
|
||||
return $this->capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enitity as array.
|
||||
*
|
||||
|
@ -58,8 +85,16 @@ class SellerStatus {
|
|||
$this->products()
|
||||
);
|
||||
|
||||
$capabilities = array_map(
|
||||
function( SellerStatusCapability $capability ) : array {
|
||||
return $capability->to_array();
|
||||
},
|
||||
$this->capabilities()
|
||||
);
|
||||
|
||||
return array(
|
||||
'products' => $products,
|
||||
'capabilities' => $capabilities,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
/**
|
||||
* The capabilities of a seller status.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class SellerStatusCapability
|
||||
*/
|
||||
class SellerStatusCapability {
|
||||
|
||||
const STATUS_ACTIVE = 'ACTIVE';
|
||||
|
||||
/**
|
||||
* The name of the product.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* The status of the capability.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $status;
|
||||
|
||||
/**
|
||||
* SellerStatusCapability constructor.
|
||||
*
|
||||
* @param string $name The name of the product.
|
||||
* @param string $status The status of the capability.
|
||||
*/
|
||||
public function __construct(
|
||||
string $name,
|
||||
string $status
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the product.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name() : string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status for this capability.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function status() : string {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() : array {
|
||||
return array(
|
||||
'name' => $this->name(),
|
||||
'status' => $this->status(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -19,6 +19,22 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
|||
*/
|
||||
class AuthorizationFactory {
|
||||
|
||||
/**
|
||||
* The FraudProcessorResponseFactory factory.
|
||||
*
|
||||
* @var FraudProcessorResponseFactory
|
||||
*/
|
||||
protected $fraud_processor_response_factory;
|
||||
|
||||
/**
|
||||
* AuthorizationFactory constructor.
|
||||
*
|
||||
* @param FraudProcessorResponseFactory $fraud_processor_response_factory The FraudProcessorResponseFactory factory.
|
||||
*/
|
||||
public function __construct( FraudProcessorResponseFactory $fraud_processor_response_factory ) {
|
||||
$this->fraud_processor_response_factory = $fraud_processor_response_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Authorization based off a PayPal response.
|
||||
*
|
||||
|
@ -42,12 +58,17 @@ class AuthorizationFactory {
|
|||
|
||||
$reason = $data->status_details->reason ?? null;
|
||||
|
||||
$fraud_processor_response = isset( $data->processor_response ) ?
|
||||
$this->fraud_processor_response_factory->from_paypal_response( $data->processor_response )
|
||||
: null;
|
||||
|
||||
return new Authorization(
|
||||
$data->id,
|
||||
new AuthorizationStatus(
|
||||
$data->status,
|
||||
$reason ? new AuthorizationStatusDetails( $reason ) : null
|
||||
)
|
||||
),
|
||||
$fraud_processor_response
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ class FraudProcessorResponseFactory {
|
|||
* @return FraudProcessorResponse
|
||||
*/
|
||||
public function from_paypal_response( stdClass $data ): FraudProcessorResponse {
|
||||
$avs_code = $data->avs_code ?: null;
|
||||
$cvv_code = $data->cvv_code ?: null;
|
||||
$avs_code = ( $data->avs_code ?? null ) ?: null;
|
||||
$cvv_code = ( $data->cvv_code ?? null ) ?: null;
|
||||
|
||||
return new FraudProcessorResponse( $avs_code, $cvv_code );
|
||||
}
|
||||
|
|
|
@ -61,12 +61,12 @@ class ItemFactory {
|
|||
|
||||
$price = (float) $item['line_subtotal'] / (float) $item['quantity'];
|
||||
return new Item(
|
||||
mb_substr( $product->get_name(), 0, 127 ),
|
||||
$this->prepare_item_string( $product->get_name() ),
|
||||
new Money( $price, $this->currency ),
|
||||
$quantity,
|
||||
$this->prepare_description( $product->get_description() ),
|
||||
$this->prepare_item_string( $product->get_description() ),
|
||||
null,
|
||||
$product->get_sku(),
|
||||
$this->prepare_sku( $product->get_sku() ),
|
||||
( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS,
|
||||
$product->get_permalink(),
|
||||
$image[0] ?? '',
|
||||
|
@ -138,12 +138,12 @@ class ItemFactory {
|
|||
$image = $product instanceof WC_Product ? wp_get_attachment_image_src( (int) $product->get_image_id(), 'full' ) : '';
|
||||
|
||||
return new Item(
|
||||
mb_substr( $item->get_name(), 0, 127 ),
|
||||
$this->prepare_item_string( $item->get_name() ),
|
||||
new Money( $price_without_tax_rounded, $currency ),
|
||||
$quantity,
|
||||
$product instanceof WC_Product ? $this->prepare_description( $product->get_description() ) : '',
|
||||
$product instanceof WC_Product ? $this->prepare_item_string( $product->get_description() ) : '',
|
||||
null,
|
||||
$product instanceof WC_Product ? $product->get_sku() : '',
|
||||
$product instanceof WC_Product ? $this->prepare_sku( $product->get_sku() ) : '',
|
||||
( $product instanceof WC_Product && $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS,
|
||||
$product instanceof WC_Product ? $product->get_permalink() : '',
|
||||
$image[0] ?? ''
|
||||
|
@ -160,7 +160,7 @@ class ItemFactory {
|
|||
*/
|
||||
private function from_wc_order_fee( \WC_Order_Item_Fee $item, \WC_Order $order ): Item {
|
||||
return new Item(
|
||||
$item->get_name(),
|
||||
$this->prepare_item_string( $item->get_name() ),
|
||||
new Money( (float) $item->get_amount(), $order->get_currency() ),
|
||||
$item->get_quantity(),
|
||||
'',
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
|||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusProduct;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusCapability;
|
||||
|
||||
/**
|
||||
* Class SellerStatusFactory
|
||||
|
@ -37,6 +38,17 @@ class SellerStatusFactory {
|
|||
isset( $json->products ) ? (array) $json->products : array()
|
||||
);
|
||||
|
||||
return new SellerStatus( $products );
|
||||
$capabilities = array_map(
|
||||
function( $json ) : SellerStatusCapability {
|
||||
$capability = new SellerStatusCapability(
|
||||
isset( $json->name ) ? (string) $json->name : '',
|
||||
isset( $json->status ) ? (string) $json->status : ''
|
||||
);
|
||||
return $capability;
|
||||
},
|
||||
isset( $json->capabilities ) ? (array) $json->capabilities : array()
|
||||
);
|
||||
|
||||
return new SellerStatus( $products, $capabilities );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,13 +12,23 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Helper;
|
|||
trait ItemTrait {
|
||||
|
||||
/**
|
||||
* Cleanups the description and prepares it for sending to PayPal.
|
||||
* Cleans up item strings (title and description for example) and prepares them for sending to PayPal.
|
||||
*
|
||||
* @param string $description Item description.
|
||||
* @param string $string Item string.
|
||||
* @return string
|
||||
*/
|
||||
protected function prepare_description( string $description ): string {
|
||||
$description = strip_shortcodes( wp_strip_all_tags( $description ) );
|
||||
return substr( $description, 0, 127 ) ?: '';
|
||||
protected function prepare_item_string( string $string ): string {
|
||||
$string = strip_shortcodes( wp_strip_all_tags( $string ) );
|
||||
return substr( $string, 0, 127 ) ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the sku for sending to PayPal.
|
||||
*
|
||||
* @param string $sku Item sku.
|
||||
* @return string
|
||||
*/
|
||||
protected function prepare_sku( string $sku ): string {
|
||||
return substr( wp_strip_all_tags( $sku ), 0, 127 ) ?: '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,10 +70,6 @@ class ApplepayButton {
|
|||
|
||||
if (this.isEligible) {
|
||||
this.fetchTransactionInfo().then(() => {
|
||||
const isSubscriptionProduct = this.ppcpConfig?.data_client_id?.has_subscriptions === true;
|
||||
if (isSubscriptionProduct) {
|
||||
return;
|
||||
}
|
||||
this.addButton();
|
||||
const id_minicart = "#apple-" + this.buttonConfig.button.mini_cart_wrapper;
|
||||
const id = "#apple-" + this.buttonConfig.button.wrapper;
|
||||
|
@ -214,6 +210,8 @@ class ApplepayButton {
|
|||
|
||||
const paymentRequest = this.paymentRequest();
|
||||
|
||||
window.ppcpFundingSource = 'apple_pay'; // Do this on another place like on create order endpoint handler.
|
||||
|
||||
// Trigger woocommerce validation if we are in the checkout page.
|
||||
if (this.context === 'checkout') {
|
||||
const checkoutFormSelector = 'form.woocommerce-checkout';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import ErrorHandler from "../../../../ppcp-button/resources/js/modules/ErrorHandler";
|
||||
import CartActionHandler
|
||||
from "../../../../ppcp-button/resources/js/modules/ActionHandler/CartActionHandler";
|
||||
import {isPayPalSubscription} from "../../../../ppcp-blocks/resources/js/Helper/Subscription";
|
||||
|
||||
class BaseHandler {
|
||||
|
||||
|
@ -9,9 +10,15 @@ class BaseHandler {
|
|||
this.ppcpConfig = ppcpConfig;
|
||||
}
|
||||
|
||||
isVaultV3Mode() {
|
||||
return this.ppcpConfig?.save_payment_methods?.id_token // vault v3
|
||||
&& ! this.ppcpConfig?.data_client_id?.paypal_subscriptions_enabled // not PayPal Subscriptions mode
|
||||
&& this.ppcpConfig?.can_save_vault_token; // vault is enabled
|
||||
}
|
||||
|
||||
validateContext() {
|
||||
if ( this.ppcpConfig?.locations_with_subscription_product?.cart ) {
|
||||
return false;
|
||||
return this.isVaultV3Mode();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ class PayNowHandler extends BaseHandler {
|
|||
|
||||
validateContext() {
|
||||
if ( this.ppcpConfig?.locations_with_subscription_product?.payorder ) {
|
||||
return false;
|
||||
return this.isVaultV3Mode();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ class SingleProductHandler extends BaseHandler {
|
|||
|
||||
validateContext() {
|
||||
if ( this.ppcpConfig?.locations_with_subscription_product?.product ) {
|
||||
return false;
|
||||
return this.isVaultV3Mode();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import {useEffect, useState} from '@wordpress/element';
|
||||
import {registerExpressPaymentMethod, registerPaymentMethod} from '@woocommerce/blocks-registry';
|
||||
import {registerExpressPaymentMethod} from '@woocommerce/blocks-registry';
|
||||
import {loadPaypalScript} from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading'
|
||||
import {cartHasSubscriptionProducts} from '../../../ppcp-blocks/resources/js/Helper/Subscription'
|
||||
import ApplepayManager from "./ApplepayManager";
|
||||
import {loadCustomScript} from "@paypal/paypal-js";
|
||||
import CheckoutHandler from "./Context/CheckoutHandler";
|
||||
|
||||
const ppcpData = wc.wcSettings.getSetting('ppcp-gateway_data');
|
||||
const ppcpConfig = ppcpData.scriptData;
|
||||
|
@ -50,6 +52,13 @@ const ApplePayComponent = () => {
|
|||
|
||||
const features = ['products'];
|
||||
|
||||
if (
|
||||
cartHasSubscriptionProducts(ppcpConfig)
|
||||
&& (new CheckoutHandler(buttonConfig, ppcpConfig)).isVaultV3Mode()
|
||||
) {
|
||||
features.push('subscriptions');
|
||||
}
|
||||
|
||||
registerExpressPaymentMethod({
|
||||
name: buttonData.id,
|
||||
label: <div dangerouslySetInnerHTML={{__html: buttonData.title}}/>,
|
||||
|
|
|
@ -18,6 +18,7 @@ use WooCommerce\PayPalCommerce\Applepay\Assets\BlocksPaymentMethod;
|
|||
use WooCommerce\PayPalCommerce\Applepay\Assets\PropertiesDictionary;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Helper\ApmApplies;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Helper\AvailabilityNotice;
|
||||
use WooCommerce\PayPalCommerce\Common\Pattern\SingletonDecorator;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
@ -72,14 +73,16 @@ return array(
|
|||
return $settings->has( 'applepay_validated' ) ? $settings->get( 'applepay_validated' ) === true : false;
|
||||
},
|
||||
|
||||
'applepay.apple-product-status' => static function( ContainerInterface $container ): AppleProductStatus {
|
||||
'applepay.apple-product-status' => SingletonDecorator::make(
|
||||
static function( ContainerInterface $container ): AppleProductStatus {
|
||||
return new AppleProductStatus(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'api.endpoint.partners' ),
|
||||
$container->get( 'onboarding.state' ),
|
||||
$container->get( 'api.helper.failure-registry' )
|
||||
);
|
||||
},
|
||||
}
|
||||
),
|
||||
'applepay.available' => static function ( ContainerInterface $container ): bool {
|
||||
if ( apply_filters( 'woocommerce_paypal_payments_applepay_validate_product_status', true ) ) {
|
||||
$status = $container->get( 'applepay.apple-product-status' );
|
||||
|
@ -195,6 +198,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'AT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'BE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -483,6 +510,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -531,6 +582,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LI' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -603,6 +678,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'NO' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'NL' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\Applepay\Assets;
|
|||
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusCapability;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
@ -100,6 +101,11 @@ class AppleProductStatus {
|
|||
return false;
|
||||
}
|
||||
|
||||
$status_override = apply_filters( 'woocommerce_paypal_payments_apple_pay_product_status', null );
|
||||
if ( null !== $status_override ) {
|
||||
return $status_override;
|
||||
}
|
||||
|
||||
// If status was already checked on this request return the same result.
|
||||
if ( null !== $this->current_status ) {
|
||||
return $this->current_status;
|
||||
|
@ -128,12 +134,24 @@ class AppleProductStatus {
|
|||
}
|
||||
|
||||
// Check the seller status for the intended capability.
|
||||
$has_capability = false;
|
||||
foreach ( $seller_status->products() as $product ) {
|
||||
if ( $product->name() !== 'PAYMENT_METHODS' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( in_array( self::CAPABILITY_NAME, $product->capabilities(), true ) ) {
|
||||
$has_capability = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $seller_status->capabilities() as $capability ) {
|
||||
if ( $capability->name() === self::CAPABILITY_NAME && $capability->status() === SellerStatusCapability::STATUS_ACTIVE ) {
|
||||
$has_capability = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $has_capability ) {
|
||||
// Capability found, persist status and return true.
|
||||
$this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_ENABLED );
|
||||
$this->settings->persist();
|
||||
|
@ -141,7 +159,6 @@ class AppleProductStatus {
|
|||
$this->current_status = true;
|
||||
return $this->current_status;
|
||||
}
|
||||
}
|
||||
|
||||
// Capability not found, persist status and return false.
|
||||
$this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_DISABLED );
|
||||
|
|
22
modules/ppcp-blocks/resources/js/Helper/Helper.js
Normal file
22
modules/ppcp-blocks/resources/js/Helper/Helper.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* @param str
|
||||
* @returns {string}
|
||||
*/
|
||||
export const toSnakeCase = (str) => {
|
||||
return str.replace(/[\w]([A-Z])/g, function(m) {
|
||||
return m[0] + "_" + m[1];
|
||||
}).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj
|
||||
* @returns {{}}
|
||||
*/
|
||||
export const convertKeysToSnakeCase = (obj) => {
|
||||
const newObj = {};
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const newKey = toSnakeCase(key);
|
||||
newObj[newKey] = obj[key];
|
||||
});
|
||||
return newObj;
|
||||
}
|
|
@ -6,6 +6,9 @@ import {
|
|||
paypalOrderToWcAddresses,
|
||||
paypalSubscriptionToWcAddresses
|
||||
} from "./Helper/Address";
|
||||
import {
|
||||
convertKeysToSnakeCase
|
||||
} from "./Helper/Helper";
|
||||
import {
|
||||
cartHasSubscriptionProducts,
|
||||
isPayPalSubscription
|
||||
|
@ -18,6 +21,7 @@ import {
|
|||
} from '../../../ppcp-button/resources/js/modules/Helper/Style'
|
||||
import buttonModuleWatcher from "../../../ppcp-button/resources/js/modules/ButtonModuleWatcher";
|
||||
import BlockCheckoutMessagesBootstrap from "./Bootstrap/BlockCheckoutMessagesBootstrap";
|
||||
import {keysToCamelCase} from "../../../ppcp-button/resources/js/modules/Helper/Utils";
|
||||
const config = wc.wcSettings.getSetting('ppcp-gateway_data');
|
||||
|
||||
window.ppcpFundingSource = config.fundingSource;
|
||||
|
@ -87,6 +91,7 @@ const PayPalComponent = ({
|
|||
bn_code: '',
|
||||
context: config.scriptData.context,
|
||||
payment_method: 'ppcp-gateway',
|
||||
funding_source: window.ppcpFundingSource ?? 'paypal',
|
||||
createaccount: false
|
||||
}),
|
||||
});
|
||||
|
@ -285,17 +290,43 @@ const PayPalComponent = ({
|
|||
onClick();
|
||||
};
|
||||
|
||||
let handleShippingChange = null;
|
||||
let handleSubscriptionShippingChange = null;
|
||||
let handleShippingOptionsChange = null;
|
||||
let handleShippingAddressChange = null;
|
||||
let handleSubscriptionShippingOptionsChange = null;
|
||||
let handleSubscriptionShippingAddressChange = null;
|
||||
if (shippingData.needsShipping && !config.finalReviewEnabled) {
|
||||
handleShippingChange = async (data, actions) => {
|
||||
handleShippingOptionsChange = async (data, actions) => {
|
||||
try {
|
||||
const shippingOptionId = data.selected_shipping_option?.id;
|
||||
const shippingOptionId = data.selectedShippingOption?.id;
|
||||
if (shippingOptionId) {
|
||||
await wp.data.dispatch('wc/store/cart').selectShippingRate(shippingOptionId);
|
||||
await shippingData.setSelectedRates(shippingOptionId);
|
||||
}
|
||||
|
||||
const address = paypalAddressToWc(data.shipping_address);
|
||||
const res = await fetch(config.ajax.update_shipping.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: config.ajax.update_shipping.nonce,
|
||||
order_id: data.orderID,
|
||||
})
|
||||
});
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if (!json.success) {
|
||||
throw new Error(json.data.message);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
actions.reject();
|
||||
}
|
||||
};
|
||||
|
||||
handleShippingAddressChange = async (data, actions) => {
|
||||
try {
|
||||
const address = paypalAddressToWc(convertKeysToSnakeCase(data.shippingAddress));
|
||||
|
||||
await wp.data.dispatch('wc/store/cart').updateCustomerData({
|
||||
shipping_address: address,
|
||||
|
@ -324,16 +355,23 @@ const PayPalComponent = ({
|
|||
}
|
||||
};
|
||||
|
||||
handleSubscriptionShippingChange = async (data, actions) => {
|
||||
console.log('--- handleSubscriptionShippingChange', data, actions);
|
||||
|
||||
handleSubscriptionShippingOptionsChange = async (data, actions) => {
|
||||
try {
|
||||
const shippingOptionId = data.selected_shipping_option?.id;
|
||||
const shippingOptionId = data.selectedShippingOption?.id;
|
||||
if (shippingOptionId) {
|
||||
await wp.data.dispatch('wc/store/cart').selectShippingRate(shippingOptionId);
|
||||
await shippingData.setSelectedRates(shippingOptionId);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
const address = paypalAddressToWc(data.shipping_address);
|
||||
actions.reject();
|
||||
}
|
||||
};
|
||||
|
||||
handleSubscriptionShippingAddressChange = async (data, actions) => {
|
||||
try {
|
||||
const address = paypalAddressToWc(convertKeysToSnakeCase(data.shippingAddress));
|
||||
|
||||
await wp.data.dispatch('wc/store/cart').updateCustomerData({
|
||||
shipping_address: address,
|
||||
|
@ -443,7 +481,8 @@ const PayPalComponent = ({
|
|||
onError={onClose}
|
||||
createSubscription={createSubscription}
|
||||
onApprove={handleApproveSubscription}
|
||||
onShippingChange={handleSubscriptionShippingChange}
|
||||
onShippingOptionsChange={handleSubscriptionShippingOptionsChange}
|
||||
onShippingAddressChange={handleSubscriptionShippingAddressChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -457,7 +496,8 @@ const PayPalComponent = ({
|
|||
onError={onClose}
|
||||
createOrder={createOrder}
|
||||
onApprove={handleApprove}
|
||||
onShippingChange={handleShippingChange}
|
||||
onShippingOptionsChange={handleShippingOptionsChange}
|
||||
onShippingAddressChange={handleShippingAddressChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -476,6 +516,14 @@ if(cartHasSubscriptionProducts(config.scriptData)) {
|
|||
block_enabled = false;
|
||||
}
|
||||
|
||||
// Don't render if vaulting disabled and is in vault subscription mode
|
||||
if(
|
||||
! isPayPalSubscription(config.scriptData)
|
||||
&& ! config.scriptData.can_save_vault_token
|
||||
) {
|
||||
block_enabled = false;
|
||||
}
|
||||
|
||||
// Don't render buttons if in subscription mode and product not associated with a PayPal subscription
|
||||
if(
|
||||
isPayPalSubscription(config.scriptData)
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\Blocks;
|
|||
|
||||
use WooCommerce\PayPalCommerce\Blocks\Endpoint\UpdateShippingEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
|
||||
|
||||
return array(
|
||||
'blocks.url' => static function ( ContainerInterface $container ): string {
|
||||
|
@ -28,7 +29,9 @@ return array(
|
|||
return new PayPalPaymentMethod(
|
||||
$container->get( 'blocks.url' ),
|
||||
$container->get( 'ppcp.asset-version' ),
|
||||
$container->get( 'button.smart-button' ),
|
||||
function () use ( $container ): SmartButtonInterface {
|
||||
return $container->get( 'button.smart-button' );
|
||||
},
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'wcgateway.settings.status' ),
|
||||
$container->get( 'wcgateway.paypal-gateway' ),
|
||||
|
|
|
@ -41,7 +41,7 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
/**
|
||||
* The smart button script loading handler.
|
||||
*
|
||||
* @var SmartButtonInterface
|
||||
* @var SmartButtonInterface|callable
|
||||
*/
|
||||
private $smart_button;
|
||||
|
||||
|
@ -127,7 +127,7 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
*
|
||||
* @param string $module_url The url of this module.
|
||||
* @param string $version The assets version.
|
||||
* @param SmartButtonInterface $smart_button The smart button script loading handler.
|
||||
* @param SmartButtonInterface|callable $smart_button The smart button script loading handler.
|
||||
* @param Settings $plugin_settings The settings.
|
||||
* @param SettingsStatus $settings_status The Settings status helper.
|
||||
* @param PayPalGateway $gateway The WC gateway.
|
||||
|
@ -143,7 +143,7 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
public function __construct(
|
||||
string $module_url,
|
||||
string $version,
|
||||
SmartButtonInterface $smart_button,
|
||||
$smart_button,
|
||||
Settings $plugin_settings,
|
||||
SettingsStatus $settings_status,
|
||||
PayPalGateway $gateway,
|
||||
|
@ -209,7 +209,7 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_payment_method_data() {
|
||||
$script_data = $this->smart_button->script_data();
|
||||
$script_data = $this->smart_button()->script_data();
|
||||
|
||||
if ( isset( $script_data['continuation'] ) ) {
|
||||
$url = add_query_arg( array( CancelController::NONCE => wp_create_nonce( CancelController::NONCE ) ), wc_get_checkout_url() );
|
||||
|
@ -267,4 +267,21 @@ class PayPalPaymentMethod extends AbstractPaymentMethodType {
|
|||
$screen = get_current_screen();
|
||||
return $screen && $screen->is_block_editor();
|
||||
}
|
||||
|
||||
/**
|
||||
* The smart button.
|
||||
*
|
||||
* @return SmartButtonInterface
|
||||
*/
|
||||
private function smart_button(): SmartButtonInterface {
|
||||
if ( $this->smart_button instanceof SmartButtonInterface ) {
|
||||
return $this->smart_button;
|
||||
}
|
||||
|
||||
if ( is_callable( $this->smart_button ) ) {
|
||||
$this->smart_button = ( $this->smart_button )();
|
||||
}
|
||||
|
||||
return $this->smart_button;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,7 +137,12 @@ const bootstrap = () => {
|
|||
}
|
||||
|
||||
const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;
|
||||
if (isFreeTrial && data.fundingSource !== 'card' && ! PayPalCommerceGateway.subscription_plan_id) {
|
||||
if (
|
||||
isFreeTrial
|
||||
&& data.fundingSource !== 'card'
|
||||
&& ! PayPalCommerceGateway.subscription_plan_id
|
||||
&& ! PayPalCommerceGateway.vault_v3_enabled
|
||||
) {
|
||||
freeTrialHandler.handle();
|
||||
return actions.reject();
|
||||
}
|
||||
|
@ -241,7 +246,6 @@ document.addEventListener(
|
|||
if (!typeof (PayPalCommerceGateway)) {
|
||||
console.error('PayPal button could not be configured.');
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
|
|
|
@ -144,6 +144,54 @@ class CheckoutActionHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
addPaymentMethodConfiguration() {
|
||||
return {
|
||||
createVaultSetupToken: async () => {
|
||||
const response = await fetch(this.config.ajax.create_setup_token.endpoint, {
|
||||
method: "POST",
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nonce: this.config.ajax.create_setup_token.nonce,
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json()
|
||||
if (result.data.id) {
|
||||
return result.data.id
|
||||
}
|
||||
|
||||
console.error(result)
|
||||
},
|
||||
onApprove: async ({vaultSetupToken}) => {
|
||||
const response = await fetch(this.config.ajax.create_payment_token_for_guest.endpoint, {
|
||||
method: "POST",
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nonce: this.config.ajax.create_payment_token_for_guest.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
})
|
||||
})
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success === true) {
|
||||
document.querySelector('#place_order').click()
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(result)
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default CheckoutActionHandler;
|
||||
|
|
|
@ -7,7 +7,6 @@ class ButtonModuleWatcher {
|
|||
}
|
||||
|
||||
watchContextBootstrap(callable) {
|
||||
console.log('ButtonModuleWatcher.js: watchContextBootstrap', this.contextBootstrapRegistry)
|
||||
this.contextBootstrapWatchers.push(callable);
|
||||
Object.values(this.contextBootstrapRegistry).forEach(callable);
|
||||
}
|
||||
|
|
|
@ -116,6 +116,14 @@ class CheckoutBootstap {
|
|||
return;
|
||||
}
|
||||
|
||||
if(
|
||||
PayPalCommerceGateway.is_free_trial_cart
|
||||
&& PayPalCommerceGateway.vault_v3_enabled
|
||||
) {
|
||||
this.renderer.render(actionHandler.addPaymentMethodConfiguration(), {}, actionHandler.configuration());
|
||||
return;
|
||||
}
|
||||
|
||||
this.renderer.render(actionHandler.configuration(), {}, actionHandler.configuration());
|
||||
}
|
||||
|
||||
|
|
|
@ -127,19 +127,7 @@ class CardFieldsRenderer {
|
|||
|
||||
const paymentToken = document.querySelector('input[name="wc-ppcp-credit-card-gateway-payment-token"]:checked')?.value
|
||||
if(paymentToken && paymentToken !== 'new') {
|
||||
fetch(this.defaultConfig.ajax.capture_card_payment.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: this.defaultConfig.ajax.capture_card_payment.nonce,
|
||||
payment_token: paymentToken
|
||||
})
|
||||
}).then((res) => {
|
||||
return res.json();
|
||||
}).then((data) => {
|
||||
document.querySelector('#place_order').click();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,8 @@ return array(
|
|||
$container->get( 'button.early-wc-checkout-validation-enabled' ),
|
||||
$container->get( 'button.pay-now-contexts' ),
|
||||
$container->get( 'wcgateway.funding-sources-without-redirect' ),
|
||||
$container->get( 'vaulting.vault-v3-enabled' ),
|
||||
$container->get( 'api.endpoint.payment-tokens' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
|
|
|
@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface;
|
|||
use WC_Order;
|
||||
use WC_Product;
|
||||
use WC_Product_Variation;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
|
@ -33,6 +34,9 @@ use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
|||
use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\PayLaterBlock\PayLaterBlockModule;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentTokenForGuest;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
|
@ -184,13 +188,6 @@ class SmartButton implements SmartButtonInterface {
|
|||
*/
|
||||
private $funding_sources_without_redirect;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* Session handler.
|
||||
*
|
||||
|
@ -198,6 +195,27 @@ class SmartButton implements SmartButtonInterface {
|
|||
*/
|
||||
private $session_handler;
|
||||
|
||||
/**
|
||||
* Whether Vault v3 module is enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $vault_v3_enabled;
|
||||
|
||||
/**
|
||||
* Payment tokens endpoint.
|
||||
*
|
||||
* @var PaymentTokensEndpoint
|
||||
*/
|
||||
private $payment_tokens_endpoint;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* SmartButton constructor.
|
||||
*
|
||||
|
@ -220,6 +238,8 @@ class SmartButton implements SmartButtonInterface {
|
|||
* @param bool $early_validation_enabled Whether to execute WC validation of the checkout form.
|
||||
* @param array $pay_now_contexts The contexts that should have the Pay Now button.
|
||||
* @param string[] $funding_sources_without_redirect The sources that do not cause issues about redirecting (on mobile, ...) and sometimes not returning back.
|
||||
* @param bool $vault_v3_enabled Whether Vault v3 module is enabled.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
|
@ -242,6 +262,8 @@ class SmartButton implements SmartButtonInterface {
|
|||
bool $early_validation_enabled,
|
||||
array $pay_now_contexts,
|
||||
array $funding_sources_without_redirect,
|
||||
bool $vault_v3_enabled,
|
||||
PaymentTokensEndpoint $payment_tokens_endpoint,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
|
@ -264,7 +286,9 @@ class SmartButton implements SmartButtonInterface {
|
|||
$this->early_validation_enabled = $early_validation_enabled;
|
||||
$this->pay_now_contexts = $pay_now_contexts;
|
||||
$this->funding_sources_without_redirect = $funding_sources_without_redirect;
|
||||
$this->vault_v3_enabled = $vault_v3_enabled;
|
||||
$this->logger = $logger;
|
||||
$this->payment_tokens_endpoint = $payment_tokens_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -631,7 +655,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
|
||||
$messaging_enabled_for_current_location = $this->settings_status->is_pay_later_messaging_enabled_for_location( $location );
|
||||
|
||||
$has_paylater_block = has_block( 'woocommerce-paypal-payments/paylater-messages' ) && PayLaterBlockModule::is_enabled();
|
||||
$has_paylater_block = has_block( 'woocommerce-paypal-payments/paylater-messages' ) && PayLaterBlockModule::is_block_enabled( $this->settings_status );
|
||||
|
||||
switch ( $location ) {
|
||||
case 'checkout':
|
||||
|
@ -872,12 +896,13 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
$text_color = $this->settings->has( "{$setting_name_prefix}_color" ) ? $this->settings->get( "{$setting_name_prefix}_color" ) : 'black';
|
||||
$style_color = $this->settings->has( "{$setting_name_prefix}_flex_color" ) ? $this->settings->get( "{$setting_name_prefix}_flex_color" ) : 'blue';
|
||||
$ratio = $this->settings->has( "{$setting_name_prefix}_flex_ratio" ) ? $this->settings->get( "{$setting_name_prefix}_flex_ratio" ) : '1x1';
|
||||
$text_size = $this->settings->has( "{$setting_name_prefix}_text_size" ) ? $this->settings->get( "{$setting_name_prefix}_text_size" ) : '12';
|
||||
|
||||
return array(
|
||||
'wrapper' => '#ppcp-messages',
|
||||
'is_hidden' => ! $this->is_pay_later_filter_enabled_for_location( $this->context() ),
|
||||
'block' => array(
|
||||
'enabled' => PayLaterBlockModule::is_enabled(),
|
||||
'enabled' => PayLaterBlockModule::is_block_enabled( $this->settings_status ),
|
||||
),
|
||||
'amount' => $amount,
|
||||
'placement' => $placement,
|
||||
|
@ -889,6 +914,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
),
|
||||
'text' => array(
|
||||
'color' => $text_color,
|
||||
'size' => $text_size,
|
||||
),
|
||||
'color' => $style_color,
|
||||
'ratio' => $ratio,
|
||||
|
@ -948,7 +974,10 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
* @return bool
|
||||
*/
|
||||
private function has_subscriptions(): bool {
|
||||
if ( ! $this->subscription_helper->accept_only_automatic_payment_gateways() ) {
|
||||
if (
|
||||
! $this->subscription_helper->accept_only_automatic_payment_gateways()
|
||||
&& $this->paypal_subscriptions_enabled() !== true
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if ( is_product() ) {
|
||||
|
@ -985,11 +1014,21 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
if ( $this->settings->has( '3d_secure_contingency' ) ) {
|
||||
$value = $this->settings->get( '3d_secure_contingency' );
|
||||
if ( $value ) {
|
||||
return $value;
|
||||
return $this->return_3ds_contingency( $value );
|
||||
}
|
||||
}
|
||||
|
||||
return 'SCA_WHEN_REQUIRED';
|
||||
return $this->return_3ds_contingency( 'SCA_WHEN_REQUIRED' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes and returns the 3D Secure contingency.
|
||||
*
|
||||
* @param string $contingency The ThreeD secure contingency.
|
||||
* @return string
|
||||
*/
|
||||
private function return_3ds_contingency( string $contingency ): string {
|
||||
return apply_filters( 'woocommerce_paypal_payments_three_d_secure_contingency', $contingency );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1055,9 +1094,22 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
'cart_script_params' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CartScriptParamsEndpoint::ENDPOINT ),
|
||||
),
|
||||
'create_setup_token' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CreateSetupToken::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( CreateSetupToken::nonce() ),
|
||||
),
|
||||
'create_payment_token' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentToken::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( CreatePaymentToken::nonce() ),
|
||||
),
|
||||
'create_payment_token_for_guest' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentTokenForGuest::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( CreatePaymentTokenForGuest::nonce() ),
|
||||
),
|
||||
),
|
||||
'cart_contains_subscription' => $this->subscription_helper->cart_contains_subscription(),
|
||||
'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(),
|
||||
'vault_v3_enabled' => $this->vault_v3_enabled,
|
||||
'variable_paypal_subscription_variations' => $this->subscription_helper->variable_paypal_subscription_variations(),
|
||||
'subscription_product_allowed' => $this->subscription_helper->checkout_subscription_product_allowed(),
|
||||
'locations_with_subscription_product' => $this->subscription_helper->locations_with_subscription_product(),
|
||||
|
@ -1313,7 +1365,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
$disable_funding,
|
||||
array_diff(
|
||||
array_keys( $this->all_funding_sources ),
|
||||
array( 'venmo', 'paylater' )
|
||||
array( 'venmo', 'paylater', 'paypal' )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1334,6 +1386,20 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
$disable_funding[] = 'paylater';
|
||||
}
|
||||
|
||||
$disable_funding = array_filter(
|
||||
$disable_funding,
|
||||
/**
|
||||
* Make sure paypal is not sent in disable funding.
|
||||
*
|
||||
* @param string $funding_source The funding_source.
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function( $funding_source ) {
|
||||
return $funding_source !== 'paypal';
|
||||
}
|
||||
);
|
||||
|
||||
if ( count( $disable_funding ) > 0 ) {
|
||||
$params['disable-funding'] = implode( ',', array_unique( $disable_funding ) );
|
||||
}
|
||||
|
@ -1875,8 +1941,18 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
*/
|
||||
private function get_vaulted_paypal_email(): string {
|
||||
try {
|
||||
$tokens = $this->get_payment_tokens();
|
||||
$customer_id = get_user_meta( get_current_user_id(), '_ppcp_target_customer_id', true );
|
||||
if ( $customer_id ) {
|
||||
$customer_tokens = $this->payment_tokens_endpoint->payment_tokens_for_customer( $customer_id );
|
||||
foreach ( $customer_tokens as $token ) {
|
||||
$email_address = $token['payment_source']->properties()->email_address ?? '';
|
||||
if ( $email_address ) {
|
||||
return $email_address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tokens = $this->get_payment_tokens();
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( isset( $token->source()->paypal ) ) {
|
||||
return $token->source()->paypal->payer->email_address;
|
||||
|
@ -1885,6 +1961,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
|
|||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( 'Failed to get PayPal vaulted email. ' . $exception->getMessage() );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButton;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
|
||||
|
||||
/**
|
||||
|
@ -66,6 +67,11 @@ class CartScriptParamsEndpoint implements EndpointInterface {
|
|||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
if ( ! $this->smart_button instanceof SmartButton ) {
|
||||
wp_send_json_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_callable( 'wc_maybe_define_constant' ) ) {
|
||||
wc_maybe_define_constant( 'WOOCOMMERCE_CART', true );
|
||||
}
|
||||
|
|
|
@ -329,6 +329,21 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
if ( 'pay-now' === $data['context'] && is_a( $wc_order, \WC_Order::class ) ) {
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() );
|
||||
$wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() );
|
||||
|
||||
$payment_source = $order->payment_source();
|
||||
$payment_source_name = $payment_source ? $payment_source->name() : null;
|
||||
$payer = $order->payer();
|
||||
if (
|
||||
$payer
|
||||
&& $payment_source_name
|
||||
&& in_array( $payment_source_name, PayPalGateway::PAYMENT_SOURCES_WITH_PAYER_EMAIL, true )
|
||||
) {
|
||||
$payer_email = $payer->email_address();
|
||||
if ( $payer_email ) {
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email );
|
||||
}
|
||||
}
|
||||
|
||||
$wc_order->save_meta_data();
|
||||
|
||||
do_action( 'woocommerce_paypal_payments_woocommerce_order_created', $wc_order, $order );
|
||||
|
@ -422,6 +437,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
*
|
||||
* @throws RuntimeException If create order request fails.
|
||||
* @throws PayPalApiException If create order request fails.
|
||||
*
|
||||
* phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
||||
*/
|
||||
private function create_paypal_order( \WC_Order $wc_order = null, string $payment_method = '', array $data = array() ): Order {
|
||||
|
|
|
@ -13,6 +13,7 @@ use Exception;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButton;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\CartProductsHelper;
|
||||
|
||||
/**
|
||||
|
@ -25,7 +26,7 @@ class SimulateCartEndpoint extends AbstractCartEndpoint {
|
|||
/**
|
||||
* The SmartButton.
|
||||
*
|
||||
* @var SmartButton
|
||||
* @var SmartButtonInterface
|
||||
*/
|
||||
private $smart_button;
|
||||
|
||||
|
@ -39,14 +40,14 @@ class SimulateCartEndpoint extends AbstractCartEndpoint {
|
|||
/**
|
||||
* ChangeCartEndpoint constructor.
|
||||
*
|
||||
* @param SmartButton $smart_button The SmartButton.
|
||||
* @param SmartButtonInterface $smart_button The SmartButton.
|
||||
* @param \WC_Cart $cart The current WC cart object.
|
||||
* @param RequestData $request_data The request data helper.
|
||||
* @param CartProductsHelper $cart_products The cart products helper.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
SmartButton $smart_button,
|
||||
SmartButtonInterface $smart_button,
|
||||
\WC_Cart $cart,
|
||||
RequestData $request_data,
|
||||
CartProductsHelper $cart_products,
|
||||
|
@ -68,6 +69,11 @@ class SimulateCartEndpoint extends AbstractCartEndpoint {
|
|||
* @throws Exception On error.
|
||||
*/
|
||||
protected function handle_data(): bool {
|
||||
if ( ! $this->smart_button instanceof SmartButton ) {
|
||||
wp_send_json_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
$products = $this->products_from_request();
|
||||
|
||||
if ( ! $products ) {
|
||||
|
|
|
@ -159,6 +159,22 @@ class EarlyOrderHandler {
|
|||
$wc_order = wc_get_order( $order_id );
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $order->id() );
|
||||
$wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() );
|
||||
|
||||
$payment_source = $order->payment_source();
|
||||
$payment_source_name = $payment_source ? $payment_source->name() : null;
|
||||
$payer = $order->payer();
|
||||
if (
|
||||
$payer
|
||||
&& $payment_source_name
|
||||
&& in_array( $payment_source_name, PayPalGateway::PAYMENT_SOURCES_WITH_PAYER_EMAIL, true )
|
||||
&& $wc_order instanceof \WC_Order
|
||||
) {
|
||||
$payer_email = $payer->email_address();
|
||||
if ( $payer_email ) {
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email );
|
||||
}
|
||||
}
|
||||
|
||||
$wc_order->save_meta_data();
|
||||
|
||||
/**
|
||||
|
|
|
@ -57,42 +57,58 @@ class ThreeDSecure {
|
|||
*
|
||||
* @link https://developer.paypal.com/docs/business/checkout/add-capabilities/3d-secure/#authenticationresult
|
||||
*
|
||||
* @param Order $order The order for which the decission is needed.
|
||||
* @param Order $order The order for which the decision is needed.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function proceed_with_order( Order $order ): int {
|
||||
|
||||
do_action( 'woocommerce_paypal_payments_three_d_secure_before_check', $order );
|
||||
|
||||
$payment_source = $order->payment_source();
|
||||
if ( ! $payment_source ) {
|
||||
return self::NO_DECISION;
|
||||
return $this->return_decision( self::NO_DECISION, $order );
|
||||
}
|
||||
|
||||
if ( ! $payment_source->properties()->brand ?? '' ) {
|
||||
return self::NO_DECISION;
|
||||
if ( ! ( $payment_source->properties()->brand ?? '' ) ) {
|
||||
return $this->return_decision( self::NO_DECISION, $order );
|
||||
}
|
||||
if ( ! $payment_source->properties()->authentication_result ?? '' ) {
|
||||
return self::NO_DECISION;
|
||||
if ( ! ( $payment_source->properties()->authentication_result ?? '' ) ) {
|
||||
return $this->return_decision( self::NO_DECISION, $order );
|
||||
}
|
||||
|
||||
$authentication_result = $payment_source->properties()->authentication_result ?? null;
|
||||
if ( $authentication_result ) {
|
||||
$result = $this->card_authentication_result_factory->from_paypal_response( $authentication_result );
|
||||
|
||||
$this->logger->info( '3DS authentication result: ' . wc_print_r( $result->to_array(), true ) );
|
||||
$this->logger->info( '3DS Authentication Result: ' . wc_print_r( $result->to_array(), true ) );
|
||||
|
||||
if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_POSSIBLE ) {
|
||||
return self::PROCCEED;
|
||||
return $this->return_decision( self::PROCCEED, $order );
|
||||
}
|
||||
|
||||
if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_UNKNOWN ) {
|
||||
return self::RETRY;
|
||||
return $this->return_decision( self::RETRY, $order );
|
||||
}
|
||||
if ( $result->liability_shift() === AuthResult::LIABILITY_SHIFT_NO ) {
|
||||
return $this->no_liability_shift( $result );
|
||||
return $this->return_decision( $this->no_liability_shift( $result ), $order );
|
||||
}
|
||||
}
|
||||
|
||||
return self::NO_DECISION;
|
||||
return $this->return_decision( self::NO_DECISION, $order );
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes and returns a ThreeD secure decision.
|
||||
*
|
||||
* @param int $decision The ThreeD secure decision.
|
||||
* @param Order $order The PayPal Order object.
|
||||
* @return int
|
||||
*/
|
||||
public function return_decision( int $decision, Order $order ) {
|
||||
$decision = apply_filters( 'woocommerce_paypal_payments_three_d_secure_decision', $decision, $order );
|
||||
do_action( 'woocommerce_paypal_payments_three_d_secure_after_check', $order, $decision );
|
||||
return $decision;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -54,6 +54,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'AT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'BE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -342,6 +366,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -390,6 +438,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LI' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -686,6 +758,30 @@ return array(
|
|||
'JPY',
|
||||
'USD',
|
||||
),
|
||||
'NO' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
)
|
||||
);
|
||||
},
|
||||
|
|
|
@ -115,17 +115,19 @@ class CardFieldsModule implements ModuleInterface {
|
|||
$settings = $c->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
|
||||
if (
|
||||
$three_d_secure_contingency =
|
||||
$settings->has( '3d_secure_contingency' )
|
||||
&& (
|
||||
$settings->get( '3d_secure_contingency' ) === 'SCA_ALWAYS'
|
||||
|| $settings->get( '3d_secure_contingency' ) === 'SCA_WHEN_REQUIRED'
|
||||
)
|
||||
? apply_filters( 'woocommerce_paypal_payments_three_d_secure_contingency', $settings->get( '3d_secure_contingency' ) )
|
||||
: '';
|
||||
|
||||
if (
|
||||
$three_d_secure_contingency === 'SCA_ALWAYS'
|
||||
|| $three_d_secure_contingency === 'SCA_WHEN_REQUIRED'
|
||||
) {
|
||||
$data['payment_source']['card'] = array(
|
||||
'attributes' => array(
|
||||
'verification' => array(
|
||||
'method' => $settings->get( '3d_secure_contingency' ),
|
||||
'method' => $three_d_secure_contingency,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -114,6 +114,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'AT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'BE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -402,6 +426,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -450,6 +498,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LI' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -522,6 +594,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'NO' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'NL' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\Googlepay\Helper;
|
|||
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusCapability;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
@ -100,6 +101,11 @@ class ApmProductStatus {
|
|||
return false;
|
||||
}
|
||||
|
||||
$status_override = apply_filters( 'woocommerce_paypal_payments_google_pay_product_status', null );
|
||||
if ( null !== $status_override ) {
|
||||
return $status_override;
|
||||
}
|
||||
|
||||
// If status was already checked on this request return the same result.
|
||||
if ( null !== $this->current_status ) {
|
||||
return $this->current_status;
|
||||
|
@ -128,12 +134,24 @@ class ApmProductStatus {
|
|||
}
|
||||
|
||||
// Check the seller status for the intended capability.
|
||||
$has_capability = false;
|
||||
foreach ( $seller_status->products() as $product ) {
|
||||
if ( $product->name() !== 'PAYMENT_METHODS' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( in_array( self::CAPABILITY_NAME, $product->capabilities(), true ) ) {
|
||||
$has_capability = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $seller_status->capabilities() as $capability ) {
|
||||
if ( $capability->name() === self::CAPABILITY_NAME && $capability->status() === SellerStatusCapability::STATUS_ACTIVE ) {
|
||||
$has_capability = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $has_capability ) {
|
||||
// Capability found, persist status and return true.
|
||||
$this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_ENABLED );
|
||||
$this->settings->persist();
|
||||
|
@ -141,7 +159,6 @@ class ApmProductStatus {
|
|||
$this->current_status = true;
|
||||
return $this->current_status;
|
||||
}
|
||||
}
|
||||
|
||||
// Capability not found, persist status and return false.
|
||||
$this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_DISABLED );
|
||||
|
|
|
@ -359,6 +359,20 @@ document.addEventListener(
|
|||
);
|
||||
}
|
||||
|
||||
const referenceTransactionsCheck = () => {
|
||||
if (
|
||||
typeof PayPalCommerceGatewaySettings !== 'undefined'
|
||||
&& PayPalCommerceGatewaySettings.reference_transaction_enabled !== '1'
|
||||
) {
|
||||
document.getElementById('ppcp-vault_enabled')?.setAttribute('disabled', 'disabled');
|
||||
|
||||
const description = document.getElementById('field-vault_enabled')?.getElementsByClassName('description')[0];
|
||||
if (description) {
|
||||
description.innerHTML = PayPalCommerceGatewaySettings.vaulting_must_enable_advanced_wallet_message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(() => {
|
||||
removeDisabledCardIcons('select[name="ppcp[disable_cards][]"]', 'select[name="ppcp[card_icons][]"]');
|
||||
|
||||
|
@ -408,6 +422,8 @@ document.addEventListener(
|
|||
);
|
||||
|
||||
togglePayLaterMessageFields();
|
||||
|
||||
referenceTransactionsCheck()
|
||||
})();
|
||||
}
|
||||
)
|
||||
|
|
|
@ -14,6 +14,7 @@ use WC_Order_Item_Product;
|
|||
use WC_Product;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\ItemTrait;
|
||||
use WooCommerce\PayPalCommerce\OrderTracking\OrderTrackingModule;
|
||||
|
||||
/**
|
||||
|
@ -21,6 +22,8 @@ use WooCommerce\PayPalCommerce\OrderTracking\OrderTrackingModule;
|
|||
*/
|
||||
class Shipment implements ShipmentInterface {
|
||||
|
||||
use ItemTrait;
|
||||
|
||||
/**
|
||||
* The WC order ID.
|
||||
*
|
||||
|
@ -166,12 +169,12 @@ class Shipment implements ShipmentInterface {
|
|||
$image = wp_get_attachment_image_src( (int) $product->get_image_id(), 'full' );
|
||||
|
||||
$ppcp_order_item = new Item(
|
||||
mb_substr( $item->get_name(), 0, 127 ),
|
||||
$this->prepare_item_string( $item->get_name() ),
|
||||
new Money( $price_without_tax_rounded, $currency ),
|
||||
$quantity,
|
||||
$this->prepare_description( $product->get_description() ),
|
||||
$this->prepare_item_string( $product->get_description() ),
|
||||
null,
|
||||
$product->get_sku(),
|
||||
$this->prepare_sku( $product->get_sku() ),
|
||||
$product->is_virtual() ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS,
|
||||
$product->get_permalink(),
|
||||
$image[0] ?? ''
|
||||
|
@ -239,17 +242,6 @@ class Shipment implements ShipmentInterface {
|
|||
return $shipment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanups the description and prepares it for sending to PayPal.
|
||||
*
|
||||
* @param string $description Item description.
|
||||
* @return string
|
||||
*/
|
||||
protected function prepare_description( string $description ): string {
|
||||
$description = strip_shortcodes( wp_strip_all_tags( $description ) );
|
||||
return substr( $description, 0, 127 ) ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the shipment line items info.
|
||||
*
|
||||
|
|
|
@ -7,7 +7,7 @@ import { loadPaypalScript } from '../../../ppcp-button/resources/js/modules/Help
|
|||
import PayPalMessages from "./components/PayPalMessages";
|
||||
|
||||
export default function Edit( { attributes, clientId, setAttributes } ) {
|
||||
const { layout, logo, position, color, flexColor, flexRatio, placement, id } = attributes;
|
||||
const { layout, logo, position, color, size, flexColor, flexRatio, placement, id } = attributes;
|
||||
const isFlex = layout === 'flex';
|
||||
|
||||
const [paypalScriptState, setPaypalScriptState] = useState(null);
|
||||
|
@ -30,11 +30,12 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
ratio: flexRatio,
|
||||
text: {
|
||||
color,
|
||||
size
|
||||
},
|
||||
};
|
||||
|
||||
let classes = ['ppcp-paylater-block-preview', 'ppcp-overlay-parent'];
|
||||
if (PcpPayLaterBlock.vaultingEnabled) {
|
||||
if (PcpPayLaterBlock.vaultingEnabled || !PcpPayLaterBlock.placementEnabled) {
|
||||
classes = ['ppcp-paylater-block-preview', 'ppcp-paylater-unavailable', 'block-editor-warning'];
|
||||
}
|
||||
const props = useBlockProps({className: classes});
|
||||
|
@ -68,6 +69,27 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
</div>
|
||||
}
|
||||
|
||||
if (!PcpPayLaterBlock.placementEnabled) {
|
||||
return <div {...props}>
|
||||
<div className={'block-editor-warning__contents'}>
|
||||
<h3>{__('PayPal Pay Later Messaging', 'woocommerce-paypal-payments')}</h3>
|
||||
<p className={'block-editor-warning__message'}>{__('Pay Later Messaging cannot be used while the “WooCommerce Block” messaging placement is disabled. Enable the placement in the PayPal Payments Pay Later settings to reactivate this block.', 'woocommerce-paypal-payments')}</p>
|
||||
<div className={'class="block-editor-warning__actions"'}>
|
||||
<span className={'block-editor-warning__action'}>
|
||||
<a href={PcpPayLaterBlock.payLaterSettingsUrl} className={'components-button is-primary'}>
|
||||
{__('PayPal Payments Settings', 'woocommerce-paypal-payments')}
|
||||
</a>
|
||||
</span>
|
||||
<span className={'block-editor-warning__action'}>
|
||||
<button onClick={() => wp.data.dispatch( 'core/block-editor' ).removeBlock(clientId)} type={'button'} className={'components-button is-secondary'}>
|
||||
{__('Remove Block', 'woocommerce-paypal-payments')}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
let scriptParams = useScriptParams(PcpPayLaterBlock.ajax.cart_script_params);
|
||||
if (scriptParams === null) {
|
||||
return loadingElement;
|
||||
|
@ -108,10 +130,10 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
{ !isFlex && (<SelectControl
|
||||
label={__('Logo', 'woocommerce-paypal-payments')}
|
||||
options={[
|
||||
{ label: __('Primary', 'woocommerce-paypal-payments'), value: 'primary' },
|
||||
{ label: __('Alternative', 'woocommerce-paypal-payments'), value: 'alternative' },
|
||||
{ label: __('Full logo', 'woocommerce-paypal-payments'), value: 'primary' },
|
||||
{ label: __('Monogram', 'woocommerce-paypal-payments'), value: 'alternative' },
|
||||
{ label: __('Inline', 'woocommerce-paypal-payments'), value: 'inline' },
|
||||
{ label: __('None', 'woocommerce-paypal-payments'), value: 'none' },
|
||||
{ label: __('Message only', 'woocommerce-paypal-payments'), value: 'none' },
|
||||
]}
|
||||
value={logo}
|
||||
onChange={(value) => setAttributes({logo: value})}
|
||||
|
@ -129,24 +151,31 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
{ !isFlex && (<SelectControl
|
||||
label={__('Text Color', 'woocommerce-paypal-payments')}
|
||||
options={[
|
||||
{ label: __( 'Black', 'woocommerce-paypal-payments' ), value: 'black' },
|
||||
{ label: __( 'White', 'woocommerce-paypal-payments' ), value: 'white' },
|
||||
{ label: __( 'Black / Blue logo', 'woocommerce-paypal-payments' ), value: 'black' },
|
||||
{ label: __( 'White / White logo', 'woocommerce-paypal-payments' ), value: 'white' },
|
||||
{ label: __( 'Monochrome', 'woocommerce-paypal-payments' ), value: 'monochrome' },
|
||||
{ label: __( 'Grayscale', 'woocommerce-paypal-payments' ), value: 'grayscale' },
|
||||
{ label: __( 'Black / Gray logo', 'woocommerce-paypal-payments' ), value: 'grayscale' },
|
||||
]}
|
||||
value={color}
|
||||
onChange={(value) => setAttributes({color: value})}
|
||||
/>)}
|
||||
{ !isFlex && (<SelectControl
|
||||
label={__('Text Size', 'woocommerce-paypal-payments')}
|
||||
options={[
|
||||
{ label: __( 'Small', 'woocommerce-paypal-payments' ), value: '12' },
|
||||
{ label: __( 'Medium', 'woocommerce-paypal-payments' ), value: '14' },
|
||||
{ label: __( 'Large', 'woocommerce-paypal-payments' ), value: '16' },
|
||||
]}
|
||||
value={size}
|
||||
onChange={(value) => setAttributes({size: value})}
|
||||
/>)}
|
||||
{ isFlex && (<SelectControl
|
||||
label={__('Color', 'woocommerce-paypal-payments')}
|
||||
options={[
|
||||
{ label: __( 'Blue', 'woocommerce-paypal-payments' ), value: 'blue' },
|
||||
{ label: __( 'Black', 'woocommerce-paypal-payments' ), value: 'black' },
|
||||
{ label: __( 'White', 'woocommerce-paypal-payments' ), value: 'white' },
|
||||
{ label: __( 'White no border', 'woocommerce-paypal-payments' ), value: 'white-no-border' },
|
||||
{ label: __( 'Gray', 'woocommerce-paypal-payments' ), value: 'gray' },
|
||||
{ label: __( 'Monochrome', 'woocommerce-paypal-payments' ), value: 'monochrome' },
|
||||
{ label: __( 'Grayscale', 'woocommerce-paypal-payments' ), value: 'grayscale' },
|
||||
{ label: __( 'White (no border)', 'woocommerce-paypal-payments' ), value: 'white-no-border' },
|
||||
]}
|
||||
value={flexColor}
|
||||
onChange={(value) => setAttributes({flexColor: value})}
|
||||
|
@ -154,8 +183,6 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
{ isFlex && (<SelectControl
|
||||
label={__('Ratio', 'woocommerce-paypal-payments')}
|
||||
options={[
|
||||
{ label: __( '1x1', 'woocommerce-paypal-payments' ), value: '1x1' },
|
||||
{ label: __( '1x4', 'woocommerce-paypal-payments' ), value: '1x4' },
|
||||
{ label: __( '8x1', 'woocommerce-paypal-payments' ), value: '8x1' },
|
||||
{ label: __( '20x1', 'woocommerce-paypal-payments' ), value: '20x1' },
|
||||
]}
|
||||
|
@ -167,12 +194,11 @@ export default function Edit( { attributes, clientId, setAttributes } ) {
|
|||
help={ __( 'Used for the analytics dashboard in the merchant account.', 'woocommerce-paypal-payments' ) }
|
||||
options={ [
|
||||
{ label: __( 'Detect automatically', 'woocommerce-paypal-payments' ), value: 'auto' },
|
||||
{ label: __( 'Product Page', 'woocommerce-paypal-payments' ), value: 'product' },
|
||||
{ label: __( 'Cart', 'woocommerce-paypal-payments' ), value: 'cart' },
|
||||
{ label: __( 'Payment', 'woocommerce-paypal-payments' ), value: 'payment' },
|
||||
{ label: __( 'Product', 'woocommerce-paypal-payments' ), value: 'product' },
|
||||
{ label: __( 'Product list', 'woocommerce-paypal-payments' ), value: 'product-list' },
|
||||
{ label: __( 'Checkout', 'woocommerce-paypal-payments' ), value: 'checkout' },
|
||||
{ label: __( 'Home', 'woocommerce-paypal-payments' ), value: 'home' },
|
||||
{ label: __( 'Category', 'woocommerce-paypal-payments' ), value: 'category' },
|
||||
{ label: __( 'Shop', 'woocommerce-paypal-payments' ), value: 'shop' },
|
||||
] }
|
||||
value={ placement }
|
||||
onChange={ ( value ) => setAttributes( { placement: value } ) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
|
||||
export default function save( { attributes } ) {
|
||||
const { layout, logo, position, color, flexColor, flexRatio, placement, id } = attributes;
|
||||
const { layout, logo, position, color, size, flexColor, flexRatio, placement, id } = attributes;
|
||||
const paypalAttributes = layout === 'flex' ? {
|
||||
'data-pp-style-layout': 'flex',
|
||||
'data-pp-style-color': flexColor,
|
||||
|
@ -11,6 +11,7 @@ export default function save( { attributes } ) {
|
|||
'data-pp-style-logo-type': logo,
|
||||
'data-pp-style-logo-position': position,
|
||||
'data-pp-style-text-color': color,
|
||||
'data-pp-style-text-size': size,
|
||||
};
|
||||
if (placement && placement !== 'auto') {
|
||||
paypalAttributes['data-pp-placement'] = placement;
|
||||
|
|
|
@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
|||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
|
@ -22,16 +23,26 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
|||
*/
|
||||
class PayLaterBlockModule implements ModuleInterface {
|
||||
/**
|
||||
* Returns whether the block should be loaded.
|
||||
* Returns whether the block module should be loaded.
|
||||
*/
|
||||
public static function is_enabled(): bool {
|
||||
public static function is_module_loading_required(): bool {
|
||||
return apply_filters(
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
'woocommerce.feature-flags.woocommerce_paypal_payments.paylater_block_enabled',
|
||||
getenv( 'PCP_PAYLATER_BLOCK' ) === '1'
|
||||
getenv( 'PCP_PAYLATER_BLOCK' ) !== '0'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the block is enabled.
|
||||
*
|
||||
* @param SettingsStatus $settings_status The Settings status helper.
|
||||
* @return bool true if the block is enabled, otherwise false.
|
||||
*/
|
||||
public static function is_block_enabled( SettingsStatus $settings_status ): bool {
|
||||
return self::is_module_loading_required() && $settings_status->is_pay_later_messaging_enabled_for_location( 'custom_placement' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -78,6 +89,8 @@ class PayLaterBlockModule implements ModuleInterface {
|
|||
),
|
||||
'settingsUrl' => admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' ),
|
||||
'vaultingEnabled' => $settings->has( 'vault_enabled' ) && $settings->get( 'vault_enabled' ),
|
||||
'placementEnabled' => self::is_block_enabled( $c->get( 'wcgateway.settings.status' ) ),
|
||||
'payLaterSettingsUrl' => admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=ppcp-pay-later' ),
|
||||
)
|
||||
);
|
||||
|
||||
|
|
14
modules/ppcp-paylater-configurator/.babelrc
Normal file
14
modules/ppcp-paylater-configurator/.babelrc
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"useBuiltIns": "usage",
|
||||
"corejs": "3.25.0"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@babel/preset-react"
|
||||
]
|
||||
]
|
||||
}
|
3
modules/ppcp-paylater-configurator/.gitignore
vendored
Normal file
3
modules/ppcp-paylater-configurator/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
node_modules
|
||||
assets/js
|
||||
assets/css
|
17
modules/ppcp-paylater-configurator/composer.json
Normal file
17
modules/ppcp-paylater-configurator/composer.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "woocommerce/ppcp-paylater-configurator",
|
||||
"type": "dhii-mod",
|
||||
"description": "Pay Later Messaging configurator module for PPCP",
|
||||
"license": "GPL-2.0",
|
||||
"require": {
|
||||
"php": "^7.2 | ^8.0",
|
||||
"dhii/module-interface": "^0.3.0-alpha1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"WooCommerce\\PayPalCommerce\\PayLaterConfigurator\\": "src"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
83
modules/ppcp-paylater-configurator/extensions.php
Normal file
83
modules/ppcp-paylater-configurator/extensions.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
/**
|
||||
* The Pay Later configurator module extensions.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\PayLaterConfigurator
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\PayLaterConfigurator;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
return array(
|
||||
'wcgateway.settings.fields' => function ( ContainerInterface $container, array $fields ): array {
|
||||
$old_fields = array(
|
||||
'pay_later_messaging_locations',
|
||||
'pay_later_enable_styling_per_messaging_location',
|
||||
'pay_later_general_message_layout',
|
||||
'pay_later_general_message_logo',
|
||||
'pay_later_general_message_position',
|
||||
'pay_later_general_message_color',
|
||||
'pay_later_general_message_flex_color',
|
||||
'pay_later_general_message_flex_ratio',
|
||||
'pay_later_general_message_preview',
|
||||
'pay_later_product_messaging_heading',
|
||||
'pay_later_product_message_layout',
|
||||
'pay_later_product_message_logo',
|
||||
'pay_later_product_message_position',
|
||||
'pay_later_product_message_color',
|
||||
'pay_later_product_message_flex_color',
|
||||
'pay_later_product_message_flex_ratio',
|
||||
'pay_later_product_message_preview',
|
||||
'pay_later_cart_messaging_heading',
|
||||
'pay_later_cart_message_layout',
|
||||
'pay_later_cart_message_logo',
|
||||
'pay_later_cart_message_position',
|
||||
'pay_later_cart_message_color',
|
||||
'pay_later_cart_message_flex_color',
|
||||
'pay_later_cart_message_flex_ratio',
|
||||
'pay_later_cart_message_preview',
|
||||
'pay_later_checkout_messaging_heading',
|
||||
'pay_later_checkout_message_layout',
|
||||
'pay_later_checkout_message_logo',
|
||||
'pay_later_checkout_message_position',
|
||||
'pay_later_checkout_message_color',
|
||||
'pay_later_checkout_message_flex_color',
|
||||
'pay_later_checkout_message_flex_ratio',
|
||||
'pay_later_checkout_message_preview',
|
||||
'pay_later_shop_messaging_heading',
|
||||
'pay_later_shop_message_layout',
|
||||
'pay_later_shop_message_logo',
|
||||
'pay_later_shop_message_position',
|
||||
'pay_later_shop_message_color',
|
||||
'pay_later_shop_message_flex_color',
|
||||
'pay_later_shop_message_flex_ratio',
|
||||
'pay_later_shop_message_preview',
|
||||
'pay_later_home_messaging_heading',
|
||||
'pay_later_home_message_layout',
|
||||
'pay_later_home_message_logo',
|
||||
'pay_later_home_message_position',
|
||||
'pay_later_home_message_color',
|
||||
'pay_later_home_message_flex_color',
|
||||
'pay_later_home_message_flex_ratio',
|
||||
'pay_later_home_message_preview',
|
||||
);
|
||||
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
$vault_enabled = $settings->has( 'vault_enabled' ) && $settings->get( 'vault_enabled' );
|
||||
|
||||
if ( ! $vault_enabled ) {
|
||||
$old_fields[] = 'pay_later_messaging_enabled';
|
||||
}
|
||||
|
||||
foreach ( $old_fields as $old_field ) {
|
||||
unset( $fields[ $old_field ] );
|
||||
}
|
||||
|
||||
return $fields;
|
||||
},
|
||||
);
|
16
modules/ppcp-paylater-configurator/module.php
Normal file
16
modules/ppcp-paylater-configurator/module.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* The Pay Later configurator module.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\PayLaterConfigurator
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\PayLaterConfigurator;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
|
||||
return static function (): ModuleInterface {
|
||||
return new PayLaterConfiguratorModule();
|
||||
};
|
33
modules/ppcp-paylater-configurator/package.json
Normal file
33
modules/ppcp-paylater-configurator/package.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "ppcp-paylater-configurator",
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"browserslist": [
|
||||
"> 0.5%",
|
||||
"Safari >= 8",
|
||||
"Chrome >= 41",
|
||||
"Firefox >= 43",
|
||||
"Edge >= 14"
|
||||
],
|
||||
"dependencies": {
|
||||
"core-js": "^3.25.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.19",
|
||||
"@babel/preset-env": "^7.19",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@woocommerce/dependency-extraction-webpack-plugin": "^2.2.0",
|
||||
"babel-loader": "^8.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"file-loader": "^6.2.0",
|
||||
"sass": "^1.42.1",
|
||||
"sass-loader": "^12.1.0",
|
||||
"webpack": "^5.76",
|
||||
"webpack-cli": "^4.10"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
|
||||
"watch": "cross-env BABEL_ENV=default NODE_ENV=production webpack --watch",
|
||||
"dev": "cross-env BABEL_ENV=default webpack --watch"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
#messaging-configurator {
|
||||
& > div {
|
||||
justify-content: left;
|
||||
margin: 0;
|
||||
|
||||
& > div {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
.ppcp-paylater-configurator-publishButton {
|
||||
display:none;
|
||||
}
|
||||
.ppcp-paylater-configurator-header {
|
||||
font-size: 1.3em;
|
||||
color: #1d2327;
|
||||
margin: 1em 0;
|
||||
font-weight: 600;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
|
||||
line-height: 1.3;
|
||||
}
|
||||
#configurator-eligibleContainer div:has(.ppcp-paylater-configurator-header#configurator-headerText) {
|
||||
display: none;
|
||||
}
|
||||
.ppcp-paylater-configurator-subheader {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: #3c434a;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
|
||||
|
||||
a {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.css-dpyjrq-text_body, .css-dpyjrq-text_body a {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
button.css-104jwuk {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.css-1yo2lxy-text_body_strong, span.css-16jt5za-text_body, span.css-1yo2lxy-text_body_strong, span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-right: 16px;
|
||||
border-top-color: #B1B7BD;
|
||||
}
|
||||
}
|
||||
|
||||
#field-pay_later_messaging_heading h3{
|
||||
margin-bottom: 0px;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
const form = document.querySelector('#mainform');
|
||||
const table = form.querySelector('.form-table');
|
||||
const headingRow = table.querySelector('#field-pay_later_messaging_heading');
|
||||
const saveChangesButton = form.querySelector('.woocommerce-save-button');
|
||||
const publishButtonClassName = PcpPayLaterConfigurator.publishButtonClassName;
|
||||
|
||||
const tempContainer = document.createElement('div');
|
||||
tempContainer.innerHTML = `<div id='messaging-configurator'></div>`;
|
||||
|
||||
// Get the new row element from the container
|
||||
const newRow = tempContainer.firstChild;
|
||||
|
||||
// Insert the new row after the headingRow
|
||||
headingRow.parentNode.insertBefore(newRow, headingRow.nextSibling);
|
||||
|
||||
|
||||
let isSaving = false; // Flag variable to track whether saving is in progress
|
||||
|
||||
saveChangesButton.addEventListener('click', () => {
|
||||
// Check if saving is not already in progress
|
||||
if (!isSaving) {
|
||||
isSaving = true; // Set flag to indicate saving is in progress
|
||||
|
||||
// Trigger the click event on the publish button
|
||||
form.querySelector('.' + publishButtonClassName).click();
|
||||
|
||||
// Trigger click event on saveChangesButton after a short delay
|
||||
setTimeout(() => {
|
||||
saveChangesButton.click(); // Trigger click event on saveChangesButton
|
||||
isSaving = false; // Reset flag when saving is complete
|
||||
}, 1000); // Adjust the delay as needed
|
||||
}
|
||||
});
|
||||
|
||||
merchantConfigurators.Messaging({
|
||||
config: PcpPayLaterConfigurator.config,
|
||||
merchantClientId: PcpPayLaterConfigurator.merchantClientId,
|
||||
partnerClientId: PcpPayLaterConfigurator.partnerClientId,
|
||||
partnerName: 'WooCommerce',
|
||||
bnCode: 'Woo_PPCP',
|
||||
placements: ['cart', 'checkout', 'product', 'shop', 'home', 'custom_placement'],
|
||||
styleOverrides: {
|
||||
button: publishButtonClassName,
|
||||
header: PcpPayLaterConfigurator.headerClassName,
|
||||
subheader: PcpPayLaterConfigurator.subheaderClassName
|
||||
},
|
||||
onSave: data => {
|
||||
fetch(PcpPayLaterConfigurator.ajax.save_config.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: PcpPayLaterConfigurator.ajax.save_config.nonce,
|
||||
config: data,
|
||||
}),
|
||||
});
|
||||
}
|
||||
})
|
||||
} );
|
38
modules/ppcp-paylater-configurator/services.php
Normal file
38
modules/ppcp-paylater-configurator/services.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
* The Pay Later configurator module services.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\PayLaterConfigurator
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\PayLaterConfigurator;
|
||||
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint\SaveConfig;
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Factory\ConfigFactory;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
return array(
|
||||
'paylater-configurator.url' => static function ( ContainerInterface $container ): string {
|
||||
/**
|
||||
* Cannot return false for this path.
|
||||
*
|
||||
* @psalm-suppress PossiblyFalseArgument
|
||||
*/
|
||||
return plugins_url(
|
||||
'/modules/ppcp-paylater-configurator/',
|
||||
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
||||
);
|
||||
},
|
||||
'paylater-configurator.factory.config' => static function ( ContainerInterface $container ): ConfigFactory {
|
||||
return new ConfigFactory();
|
||||
},
|
||||
'paylater-configurator.endpoint.save-config' => static function ( ContainerInterface $container ): SaveConfig {
|
||||
return new SaveConfig(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'button.request-data' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
);
|
150
modules/ppcp-paylater-configurator/src/Endpoint/SaveConfig.php
Normal file
150
modules/ppcp-paylater-configurator/src/Endpoint/SaveConfig.php
Normal file
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
/**
|
||||
* The endpoint for saving the Pay Later messaging config from the configurator.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* Class SaveConfig.
|
||||
*/
|
||||
class SaveConfig {
|
||||
const ENDPOINT = 'ppc-save-message-config';
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* The request data.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
protected $request_data;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* SaveConfig 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce.
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
wp_send_json_error( 'Not admin.', 403 );
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
|
||||
$this->save_config( $data['config']['config'] );
|
||||
|
||||
wp_send_json_success();
|
||||
return true;
|
||||
} catch ( Throwable $error ) {
|
||||
$this->logger->error( "SaveConfig execution failed. {$error->getMessage()} {$error->getFile()}:{$error->getLine()}" );
|
||||
|
||||
wp_send_json_error();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the config into the old settings.
|
||||
*
|
||||
* @param array $config The configurator config.
|
||||
*/
|
||||
private function save_config( array $config ): void {
|
||||
$this->settings->set( 'pay_later_enable_styling_per_messaging_location', true );
|
||||
$this->settings->set( 'pay_later_messaging_enabled', true );
|
||||
|
||||
$enabled_locations = array();
|
||||
foreach ( $config as $placement => $data ) {
|
||||
$this->save_config_for_location( $data, $placement );
|
||||
|
||||
if ( $placement === 'custom_placement' ) {
|
||||
$data = $data[0] ?? array();
|
||||
}
|
||||
|
||||
if ( $data['status'] === 'enabled' ) {
|
||||
$enabled_locations[] = $placement;
|
||||
}
|
||||
}
|
||||
|
||||
$this->settings->set( 'pay_later_messaging_locations', $enabled_locations );
|
||||
|
||||
$this->settings->persist();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the config for a location into the old settings.
|
||||
*
|
||||
* @param array $config The configurator config for a location.
|
||||
* @param string $location The location name in the old settings.
|
||||
*/
|
||||
private function save_config_for_location( array $config, string $location ): void {
|
||||
$this->set_value_if_present( $config, 'layout', "pay_later_{$location}_message_layout" );
|
||||
|
||||
$this->set_value_if_present( $config, 'color', "pay_later_{$location}_message_flex_color" );
|
||||
$this->set_value_if_present( $config, 'ratio', "pay_later_{$location}_message_flex_ratio" );
|
||||
|
||||
$this->set_value_if_present( $config, 'logo-position', "pay_later_{$location}_message_position" );
|
||||
$this->set_value_if_present( $config, 'logo-type', "pay_later_{$location}_message_logo" );
|
||||
$this->set_value_if_present( $config, 'logo-color', "pay_later_{$location}_message_color" );
|
||||
$this->set_value_if_present( $config, 'text-size', "pay_later_{$location}_message_text_size" );
|
||||
$this->set_value_if_present( $config, 'text-color', "pay_later_{$location}_message_color" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value in the settings if it is available in the config.
|
||||
*
|
||||
* @param array $config The configurator config.
|
||||
* @param string $key The key in the config.
|
||||
* @param string $settings_key The key in the settings.
|
||||
*/
|
||||
private function set_value_if_present( array $config, string $key, string $settings_key ): void {
|
||||
if ( isset( $config[ $key ] ) ) {
|
||||
$this->settings->set( $settings_key, $config[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
145
modules/ppcp-paylater-configurator/src/Factory/ConfigFactory.php
Normal file
145
modules/ppcp-paylater-configurator/src/Factory/ConfigFactory.php
Normal file
|
@ -0,0 +1,145 @@
|
|||
<?php
|
||||
/**
|
||||
* The factory the Pay Later messaging configurator configs.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\PayLaterConfigurator\Factory;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* Class ConfigFactory.
|
||||
*/
|
||||
class ConfigFactory {
|
||||
/**
|
||||
* Returns the configurator config for the given old settings.
|
||||
*
|
||||
* @param Settings $settings The settings.
|
||||
*/
|
||||
public function from_settings( Settings $settings ): array {
|
||||
return array(
|
||||
'cart' => $this->for_location( $settings, 'cart' ),
|
||||
'checkout' => $this->for_location( $settings, 'checkout' ),
|
||||
'product' => $this->for_location( $settings, 'product' ),
|
||||
'shop' => $this->for_location( $settings, 'shop' ),
|
||||
'home' => $this->for_location( $settings, 'home' ),
|
||||
'custom_placement' => array( $this->for_location( $settings, 'woocommerceBlock' ) ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configurator config for a location.
|
||||
*
|
||||
* @param Settings $settings The settings.
|
||||
* @param string $location The location name in the old settings.
|
||||
*/
|
||||
private function for_location( Settings $settings, string $location ): array {
|
||||
$selected_locations = $settings->has( 'pay_later_messaging_locations' ) ? $settings->get( 'pay_later_messaging_locations' ) : array();
|
||||
|
||||
switch ( $location ) {
|
||||
case 'shop':
|
||||
case 'home':
|
||||
$config = $this->for_shop_or_home( $settings, $location, $selected_locations );
|
||||
break;
|
||||
case 'woocommerceBlock':
|
||||
$config = $this->for_woocommerce_block( $selected_locations );
|
||||
break;
|
||||
default:
|
||||
$config = $this->for_default_location( $settings, $location, $selected_locations );
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configurator config for shop, home locations.
|
||||
*
|
||||
* @param Settings $settings The settings.
|
||||
* @param string $location The location.
|
||||
* @param string[] $selected_locations The list of selected locations.
|
||||
* @return array{
|
||||
* layout: string,
|
||||
* color: string,
|
||||
* ratio: string,
|
||||
* status: "disabled"|"enabled",
|
||||
* placement: string
|
||||
* } The configurator config map.
|
||||
*/
|
||||
private function for_shop_or_home( Settings $settings, string $location, array $selected_locations ): array {
|
||||
return array(
|
||||
'layout' => $this->get_or_default( $settings, "pay_later_{$location}_message_layout", 'flex' ),
|
||||
'color' => $this->get_or_default( $settings, "pay_later_{$location}_message_flex_color", 'black' ),
|
||||
'ratio' => $this->get_or_default( $settings, "pay_later_{$location}_message_flex_ratio", '8x1' ),
|
||||
'status' => in_array( $location, $selected_locations, true ) ? 'enabled' : 'disabled',
|
||||
'placement' => $location,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configurator config for woocommerceBlock location.
|
||||
*
|
||||
* @param array $selected_locations The list of selected locations.
|
||||
* @return array{
|
||||
* status: "disabled"|"enabled",
|
||||
* message_reference: string
|
||||
* } The configurator config map.
|
||||
*/
|
||||
private function for_woocommerce_block( array $selected_locations ): array {
|
||||
return array(
|
||||
'status' => in_array( 'custom_placement', $selected_locations, true ) ? 'enabled' : 'disabled',
|
||||
'message_reference' => 'woocommerceBlock',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configurator config for default locations.
|
||||
*
|
||||
* @param Settings $settings The settings.
|
||||
* @param string $location The location.
|
||||
* @param string[] $selected_locations The list of selected locations.
|
||||
* @return array{
|
||||
* layout: string,
|
||||
* logo-position: string,
|
||||
* logo-type: string,
|
||||
* text-color: string,
|
||||
* text-size: string,
|
||||
* status: "disabled"|"enabled",
|
||||
* placement: string
|
||||
* } The configurator config map.
|
||||
*/
|
||||
private function for_default_location( Settings $settings, string $location, array $selected_locations ): array {
|
||||
return array(
|
||||
'layout' => $this->get_or_default( $settings, "pay_later_{$location}_message_layout", 'text' ),
|
||||
'logo-position' => $this->get_or_default( $settings, "pay_later_{$location}_message_position", 'left' ),
|
||||
'logo-type' => $this->get_or_default( $settings, "pay_later_{$location}_message_logo", 'inline' ),
|
||||
'text-color' => $this->get_or_default( $settings, "pay_later_{$location}_message_color", 'black' ),
|
||||
'text-size' => $this->get_or_default( $settings, "pay_later_{$location}_message_text_size", '12' ),
|
||||
'status' => in_array( $location, $selected_locations, true ) ? 'enabled' : 'disabled',
|
||||
'placement' => $location,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the settings value or default, if does not exist or not allowed value.
|
||||
*
|
||||
* @param Settings $settings The settings.
|
||||
* @param string $key The key.
|
||||
* @param mixed $default The default value.
|
||||
* @param array|null $allowed_values The list of allowed values, or null if all values are allowed.
|
||||
* @return string
|
||||
*/
|
||||
private function get_or_default( Settings $settings, string $key, $default, ?array $allowed_values = null ): string {
|
||||
if ( $settings->has( $key ) ) {
|
||||
$value = $settings->get( $key );
|
||||
if ( ! $allowed_values || in_array( $value, $allowed_values, true ) ) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
/**
|
||||
* The Pay Later configurator module.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\PayLaterConfigurator
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\PayLaterConfigurator;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint\SaveConfig;
|
||||
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Factory\ConfigFactory;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* Class PayLaterConfiguratorModule
|
||||
*/
|
||||
class PayLaterConfiguratorModule implements ModuleInterface {
|
||||
/**
|
||||
* Returns whether the module should be loaded.
|
||||
*/
|
||||
public static function is_enabled(): bool {
|
||||
return apply_filters(
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
'woocommerce.feature-flags.woocommerce_paypal_payments.paylater_configurator_enabled',
|
||||
getenv( 'PCP_PAYLATER_CONFIGURATOR' ) !== '0'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setup(): ServiceProviderInterface {
|
||||
return new ServiceProvider(
|
||||
require __DIR__ . '/../services.php',
|
||||
require __DIR__ . '/../extensions.php'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function run( ContainerInterface $c ): void {
|
||||
$messages_apply = $c->get( 'button.helper.messages-apply' );
|
||||
assert( $messages_apply instanceof MessagesApply );
|
||||
|
||||
$settings = $c->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
|
||||
$vault_enabled = $settings->has( 'vault_enabled' ) && $settings->get( 'vault_enabled' );
|
||||
|
||||
if ( $vault_enabled || ! $messages_apply->for_country() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . SaveConfig::ENDPOINT,
|
||||
static function () use ( $c ) {
|
||||
$endpoint = $c->get( 'paylater-configurator.endpoint.save-config' );
|
||||
assert( $endpoint instanceof SaveConfig );
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
$current_page_id = $c->get( 'wcgateway.current-ppcp-settings-page-id' );
|
||||
|
||||
if ( $current_page_id !== Settings::PAY_LATER_TAB_ID ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action(
|
||||
'init',
|
||||
static function () use ( $c, $settings ) {
|
||||
wp_enqueue_script(
|
||||
'ppcp-paylater-configurator-lib',
|
||||
'https://www.paypalobjects.com/merchant-library/merchant-configurator.js',
|
||||
array(),
|
||||
$c->get( 'ppcp.asset-version' ),
|
||||
true
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'ppcp-paylater-configurator',
|
||||
$c->get( 'paylater-configurator.url' ) . '/assets/js/paylater-configurator.js',
|
||||
array(),
|
||||
$c->get( 'ppcp.asset-version' ),
|
||||
true
|
||||
);
|
||||
|
||||
wp_enqueue_style(
|
||||
'ppcp-paylater-configurator-style',
|
||||
$c->get( 'paylater-configurator.url' ) . '/assets/css/paylater-configurator.css',
|
||||
array(),
|
||||
$c->get( 'ppcp.asset-version' )
|
||||
);
|
||||
|
||||
$config_factory = $c->get( 'paylater-configurator.factory.config' );
|
||||
assert( $config_factory instanceof ConfigFactory );
|
||||
|
||||
wp_localize_script(
|
||||
'ppcp-paylater-configurator',
|
||||
'PcpPayLaterConfigurator',
|
||||
array(
|
||||
'ajax' => array(
|
||||
'save_config' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( SaveConfig::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( SaveConfig::nonce() ),
|
||||
),
|
||||
),
|
||||
'config' => $config_factory->from_settings( $settings ),
|
||||
'merchantClientId' => $settings->get( 'client_id' ),
|
||||
'partnerClientId' => $c->get( 'api.partner_merchant_id' ),
|
||||
'publishButtonClassName' => 'ppcp-paylater-configurator-publishButton',
|
||||
'headerClassName' => 'ppcp-paylater-configurator-header',
|
||||
'subheaderClassName' => 'ppcp-paylater-configurator-subheader',
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key for the module.
|
||||
*
|
||||
* @return string|void
|
||||
*/
|
||||
public function getKey() {
|
||||
}
|
||||
}
|
39
modules/ppcp-paylater-configurator/webpack.config.js
Normal file
39
modules/ppcp-paylater-configurator/webpack.config.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
const path = require('path');
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
const DependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );
|
||||
|
||||
module.exports = {
|
||||
devtool: isProduction ? 'source-map' : 'eval-source-map',
|
||||
mode: isProduction ? 'production' : 'development',
|
||||
target: 'web',
|
||||
plugins: [ new DependencyExtractionWebpackPlugin() ],
|
||||
entry: {
|
||||
'paylater-configurator': path.resolve('./resources/js/paylater-configurator.js'),
|
||||
'paylater-configurator-style': path.resolve('./resources/css/paylater-configurator.scss'),
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'assets/'),
|
||||
filename: 'js/[name].js',
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.js?$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader',
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: 'css/[name].css',
|
||||
}
|
||||
},
|
||||
{loader:'sass-loader'}
|
||||
]
|
||||
}]
|
||||
}
|
||||
};
|
2201
modules/ppcp-paylater-configurator/yarn.lock
Normal file
2201
modules/ppcp-paylater-configurator/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
|
@ -196,7 +196,7 @@ class PayPalSubscriptionsModule implements ModuleInterface {
|
|||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function( $actions, $subscription ): array {
|
||||
function( $actions, $subscription = null ): array {
|
||||
if ( ! is_array( $actions ) || ! is_a( $subscription, WC_Subscription::class ) ) {
|
||||
return $actions;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ class SubscriptionsApiHandler {
|
|||
*/
|
||||
public function create_product( WC_Product $product ) {
|
||||
try {
|
||||
$subscription_product = $this->products_endpoint->create( $product->get_title(), $this->prepare_description( $product->get_description() ) );
|
||||
$subscription_product = $this->products_endpoint->create( $this->prepare_item_string( $product->get_title() ), $this->prepare_item_string( $product->get_description() ) );
|
||||
$product->update_meta_data( 'ppcp_subscription_product', $subscription_product->to_array() );
|
||||
$product->save();
|
||||
} catch ( RuntimeException $exception ) {
|
||||
|
@ -169,7 +169,7 @@ class SubscriptionsApiHandler {
|
|||
$catalog_product_name = $catalog_product->name() ?: '';
|
||||
$catalog_product_description = $catalog_product->description() ?: '';
|
||||
|
||||
$wc_product_description = $this->prepare_description( $product->get_description() ) ?: $product->get_title();
|
||||
$wc_product_description = $this->prepare_item_string( $product->get_description() ) ?: $this->prepare_item_string( $product->get_title() );
|
||||
|
||||
if ( $catalog_product_name !== $product->get_title() || $catalog_product_description !== $wc_product_description ) {
|
||||
$data = array();
|
||||
|
|
|
@ -12,7 +12,7 @@ import ErrorHandler from "../../../ppcp-button/resources/js/modules/ErrorHandler
|
|||
import {cardFieldStyles} from "../../../ppcp-button/resources/js/modules/Helper/CardFieldsHelper";
|
||||
|
||||
const errorHandler = new ErrorHandler(
|
||||
PayPalCommerceGateway.labels.error.generic,
|
||||
ppcp_add_payment_method.labels.error.generic,
|
||||
document.querySelector('.woocommerce-notices-wrapper')
|
||||
);
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\SavePaymentMethods;
|
||||
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CaptureCardPayment;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentTokenForGuest;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Helper\SavePaymentMethodsApplies;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
|
@ -57,6 +57,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'AT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'BE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -345,6 +369,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IE' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'IT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -393,6 +441,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LI' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'LT' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -465,6 +537,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'NO' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'NL' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -709,30 +805,17 @@ return array(
|
|||
$container->get( 'api.endpoint.payment-method-tokens' )
|
||||
);
|
||||
},
|
||||
'save-payment-methods.wc-payment-tokens' => static function( ContainerInterface $container ): WooCommercePaymentTokens {
|
||||
return new WooCommercePaymentTokens(
|
||||
$container->get( 'vaulting.payment-token-helper' ),
|
||||
$container->get( 'vaulting.payment-token-factory' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'save-payment-methods.endpoint.create-payment-token' => static function ( ContainerInterface $container ): CreatePaymentToken {
|
||||
return new CreatePaymentToken(
|
||||
$container->get( 'button.request-data' ),
|
||||
$container->get( 'api.endpoint.payment-method-tokens' ),
|
||||
$container->get( 'save-payment-methods.wc-payment-tokens' )
|
||||
$container->get( 'vaulting.wc-payment-tokens' )
|
||||
);
|
||||
},
|
||||
'save-payment-methods.endpoint.capture-card-payment' => static function( ContainerInterface $container ): CaptureCardPayment {
|
||||
return new CaptureCardPayment(
|
||||
'save-payment-methods.endpoint.create-payment-token-for-guest' => static function ( ContainerInterface $container ): CreatePaymentTokenForGuest {
|
||||
return new CreatePaymentTokenForGuest(
|
||||
$container->get( 'button.request-data' ),
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'api.factory.order' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'session.handler' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
$container->get( 'api.endpoint.payment-method-tokens' )
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -1,219 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* The Capture Card Payment endpoint.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use stdClass;
|
||||
use WC_Payment_Tokens;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\RequestTrait;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class CaptureCardPayment
|
||||
*/
|
||||
class CaptureCardPayment implements EndpointInterface {
|
||||
|
||||
use RequestTrait;
|
||||
|
||||
const ENDPOINT = 'ppc-capture-card-payment';
|
||||
|
||||
/**
|
||||
* The request data.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The host.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $host;
|
||||
|
||||
/**
|
||||
* The bearer.
|
||||
*
|
||||
* @var Bearer
|
||||
*/
|
||||
private $bearer;
|
||||
|
||||
/**
|
||||
* The order factory.
|
||||
*
|
||||
* @var OrderFactory
|
||||
*/
|
||||
private $order_factory;
|
||||
|
||||
/**
|
||||
* The purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
private $order_endpoint;
|
||||
|
||||
/**
|
||||
* The session handler.
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
private $session_handler;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* CaptureCardPayment constructor.
|
||||
*
|
||||
* @param RequestData $request_data The request data.
|
||||
* @param string $host The host.
|
||||
* @param Bearer $bearer The bearer.
|
||||
* @param OrderFactory $order_factory The order factory.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param SessionHandler $session_handler The session handler.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
string $host,
|
||||
Bearer $bearer,
|
||||
OrderFactory $order_factory,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
OrderEndpoint $order_endpoint,
|
||||
SessionHandler $session_handler,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->request_data = $request_data;
|
||||
$this->host = $host;
|
||||
$this->bearer = $bearer;
|
||||
$this->order_factory = $order_factory;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->logger = $logger;
|
||||
$this->session_handler = $session_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
|
||||
$tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id() );
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( $token->get_id() === (int) $data['payment_token'] ) {
|
||||
try {
|
||||
$order = $this->create_order( $token->get_token() );
|
||||
|
||||
$id = $order->id ?? '';
|
||||
$status = $order->status ?? '';
|
||||
$payment_source = isset( $order->payment_source->card ) ? 'card' : '';
|
||||
if ( $id && $status && $payment_source ) {
|
||||
WC()->session->set(
|
||||
'ppcp_saved_payment_card',
|
||||
array(
|
||||
'order_id' => $id,
|
||||
'status' => $status,
|
||||
'payment_source' => $payment_source,
|
||||
)
|
||||
);
|
||||
|
||||
wp_send_json_success();
|
||||
return true;
|
||||
}
|
||||
} catch ( RuntimeException $exception ) {
|
||||
wp_send_json_error();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wp_send_json_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates PayPal order from the given card vault id.
|
||||
*
|
||||
* @param string $vault_id Vault id.
|
||||
* @return stdClass
|
||||
* @throws RuntimeException When request fails.
|
||||
*/
|
||||
private function create_order( string $vault_id ): stdClass {
|
||||
$items = array( $this->purchase_unit_factory->from_wc_cart() );
|
||||
|
||||
$data = array(
|
||||
'intent' => 'CAPTURE',
|
||||
'purchase_units' => array_map(
|
||||
static function ( PurchaseUnit $item ): array {
|
||||
return $item->to_array( true, false );
|
||||
},
|
||||
$items
|
||||
),
|
||||
'payment_source' => array(
|
||||
'card' => array(
|
||||
'vault_id' => $vault_id,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$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',
|
||||
'PayPal-Request-Id' => uniqid( 'ppcp-', true ),
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( $response instanceof WP_Error ) {
|
||||
throw new RuntimeException( $response->get_error_message() );
|
||||
}
|
||||
|
||||
return json_decode( $response['body'] );
|
||||
}
|
||||
}
|
||||
|
|
@ -14,9 +14,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentMethodTokensEndpoint;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\WooCommercePaymentTokens;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
|
||||
|
||||
/**
|
||||
* Class CreatePaymentToken
|
||||
|
@ -96,7 +94,7 @@ class CreatePaymentToken implements EndpointInterface {
|
|||
)
|
||||
);
|
||||
|
||||
$result = $this->payment_method_tokens_endpoint->payment_tokens( $payment_source );
|
||||
$result = $this->payment_method_tokens_endpoint->create_payment_token( $payment_source );
|
||||
|
||||
if ( is_user_logged_in() && isset( $result->customer->id ) ) {
|
||||
$current_user_id = get_current_user_id();
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
/**
|
||||
* Create payment token for guest user.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint;
|
||||
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentMethodTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
|
||||
/**
|
||||
* Class UpdateCustomerId
|
||||
*/
|
||||
class CreatePaymentTokenForGuest implements EndpointInterface {
|
||||
|
||||
const ENDPOINT = 'ppc-update-customer-id';
|
||||
|
||||
/**
|
||||
* The request data.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The payment method tokens endpoint.
|
||||
*
|
||||
* @var PaymentMethodTokensEndpoint
|
||||
*/
|
||||
private $payment_method_tokens_endpoint;
|
||||
|
||||
/**
|
||||
* CreatePaymentToken constructor.
|
||||
*
|
||||
* @param RequestData $request_data The request data.
|
||||
* @param PaymentMethodTokensEndpoint $payment_method_tokens_endpoint The payment method tokens endpoint.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
PaymentMethodTokensEndpoint $payment_method_tokens_endpoint
|
||||
) {
|
||||
$this->request_data = $request_data;
|
||||
$this->payment_method_tokens_endpoint = $payment_method_tokens_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception On Error.
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
|
||||
/**
|
||||
* Suppress ArgumentTypeCoercion
|
||||
*
|
||||
* @psalm-suppress ArgumentTypeCoercion
|
||||
*/
|
||||
$payment_source = new PaymentSource(
|
||||
'token',
|
||||
(object) array(
|
||||
'id' => $data['vault_setup_token'],
|
||||
'type' => 'SETUP_TOKEN',
|
||||
)
|
||||
);
|
||||
|
||||
$result = $this->payment_method_tokens_endpoint->create_payment_token( $payment_source );
|
||||
WC()->session->set( 'ppcp_guest_payment_for_free_trial', $result );
|
||||
|
||||
wp_send_json_success();
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -19,9 +19,10 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CaptureCardPayment;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentTokenForGuest;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||
|
@ -89,14 +90,7 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||
assert( $logger instanceof LoggerInterface );
|
||||
|
||||
$localized_script_data = $this->add_id_token_to_script_data( $api, $logger, $localized_script_data );
|
||||
|
||||
$localized_script_data['ajax']['capture_card_payment'] = array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CaptureCardPayment::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( CaptureCardPayment::nonce() ),
|
||||
);
|
||||
|
||||
return $localized_script_data;
|
||||
return $this->add_id_token_to_script_data( $api, $logger, $localized_script_data );
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -148,6 +142,21 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
'vault' => array(
|
||||
'store_in_vault' => 'ON_SUCCESS',
|
||||
'usage_type' => 'MERCHANT',
|
||||
'permit_multiple_payment_tokens' => apply_filters( 'woocommerce_paypal_payments_permit_multiple_payment_tokens', false ),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} elseif ( $funding_source && $funding_source === 'apple_pay' ) {
|
||||
$data['payment_source'] = array(
|
||||
'apple_pay' => array(
|
||||
'stored_credential' => array(
|
||||
'payment_initiator' => 'CUSTOMER',
|
||||
'payment_type' => 'RECURRING',
|
||||
),
|
||||
'attributes' => array(
|
||||
'vault' => array(
|
||||
'store_in_vault' => 'ON_SUCCESS',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -159,6 +168,7 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
'vault' => array(
|
||||
'store_in_vault' => 'ON_SUCCESS',
|
||||
'usage_type' => 'MERCHANT',
|
||||
'permit_multiple_payment_tokens' => apply_filters( 'woocommerce_paypal_payments_permit_multiple_payment_tokens', false ),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -188,7 +198,7 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
|
||||
update_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', $customer_id );
|
||||
|
||||
$wc_payment_tokens = $c->get( 'save-payment-methods.wc-payment-tokens' );
|
||||
$wc_payment_tokens = $c->get( 'vaulting.wc-payment-tokens' );
|
||||
assert( $wc_payment_tokens instanceof WooCommercePaymentTokens );
|
||||
|
||||
if ( $wc_order->get_payment_method() === CreditCardGateway::ID ) {
|
||||
|
@ -207,11 +217,29 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
}
|
||||
|
||||
if ( $wc_order->get_payment_method() === PayPalGateway::ID ) {
|
||||
switch ( $payment_source->name() ) {
|
||||
case 'venmo':
|
||||
$wc_payment_tokens->create_payment_token_venmo(
|
||||
$wc_order->get_customer_id(),
|
||||
$token_id,
|
||||
$payment_source->properties()->email_address ?? ''
|
||||
);
|
||||
break;
|
||||
case 'apple_pay':
|
||||
$wc_payment_tokens->create_payment_token_applepay(
|
||||
$wc_order->get_customer_id(),
|
||||
$token_id
|
||||
);
|
||||
break;
|
||||
case 'paypal':
|
||||
default:
|
||||
$wc_payment_tokens->create_payment_token_paypal(
|
||||
$wc_order->get_customer_id(),
|
||||
$token_id,
|
||||
$payment_source->properties()->email_address ?? ''
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -254,7 +282,11 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
|
||||
$settings = $c->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
$verification_method = $settings->has( '3d_secure_contingency' ) ? $settings->get( '3d_secure_contingency' ) : '';
|
||||
|
||||
$verification_method =
|
||||
$settings->has( '3d_secure_contingency' )
|
||||
? apply_filters( 'woocommerce_paypal_payments_three_d_secure_contingency', $settings->get( '3d_secure_contingency' ) )
|
||||
: '';
|
||||
|
||||
$change_payment_method = wc_clean( wp_unslash( $_GET['change_payment_method'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification
|
||||
|
||||
|
@ -285,6 +317,14 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
'nonce' => wp_create_nonce( SubscriptionChangePaymentMethod::nonce() ),
|
||||
),
|
||||
),
|
||||
'labels' => array(
|
||||
'error' => array(
|
||||
'generic' => __(
|
||||
'Something went wrong. Please try again or choose another payment source.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
} catch ( RuntimeException $exception ) {
|
||||
|
@ -332,6 +372,16 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . CreatePaymentTokenForGuest::ENDPOINT,
|
||||
static function () use ( $c ) {
|
||||
$endpoint = $c->get( 'save-payment-methods.endpoint.create-payment-token-for-guest' );
|
||||
assert( $endpoint instanceof CreatePaymentTokenForGuest );
|
||||
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_before_delete_payment_token',
|
||||
function( string $token_id ) use ( $c ) {
|
||||
|
@ -368,16 +418,6 @@ class SavePaymentMethodsModule implements ModuleInterface {
|
|||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . CaptureCardPayment::ENDPOINT,
|
||||
static function () use ( $c ) {
|
||||
$endpoint = $c->get( 'save-payment-methods.endpoint.capture-card-payment' );
|
||||
assert( $endpoint instanceof CaptureCardPayment );
|
||||
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_paypal_payments_save_payment_methods_eligible',
|
||||
function() {
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Service to create WC Payment Tokens.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Applepay
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\SavePaymentMethods;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use stdClass;
|
||||
use WC_Payment_Token_CC;
|
||||
use WC_Payment_Tokens;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenFactory;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenPayPal;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
|
||||
/**
|
||||
* Class WooCommercePaymentTokens
|
||||
*/
|
||||
class WooCommercePaymentTokens {
|
||||
|
||||
/**
|
||||
* The payment token helper.
|
||||
*
|
||||
* @var PaymentTokenHelper
|
||||
*/
|
||||
private $payment_token_helper;
|
||||
|
||||
/**
|
||||
* The payment token factory.
|
||||
*
|
||||
* @var PaymentTokenFactory
|
||||
*/
|
||||
private $payment_token_factory;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* WooCommercePaymentTokens constructor.
|
||||
*
|
||||
* @param PaymentTokenHelper $payment_token_helper The payment token helper.
|
||||
* @param PaymentTokenFactory $payment_token_factory The payment token factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
PaymentTokenHelper $payment_token_helper,
|
||||
PaymentTokenFactory $payment_token_factory,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->payment_token_helper = $payment_token_helper;
|
||||
$this->payment_token_factory = $payment_token_factory;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a WC Payment Token for PayPal payment.
|
||||
*
|
||||
* @param int $customer_id The WC customer ID.
|
||||
* @param string $token The PayPal payment token.
|
||||
* @param string $email The PayPal customer email.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function create_payment_token_paypal(
|
||||
int $customer_id,
|
||||
string $token,
|
||||
string $email
|
||||
): int {
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, PayPalGateway::ID );
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $token ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$payment_token_paypal = $this->payment_token_factory->create( 'paypal' );
|
||||
assert( $payment_token_paypal instanceof PaymentTokenPayPal );
|
||||
|
||||
$payment_token_paypal->set_token( $token );
|
||||
$payment_token_paypal->set_user_id( $customer_id );
|
||||
$payment_token_paypal->set_gateway_id( PayPalGateway::ID );
|
||||
|
||||
if ( $email && is_email( $email ) ) {
|
||||
$payment_token_paypal->set_email( $email );
|
||||
}
|
||||
|
||||
try {
|
||||
$payment_token_paypal->save();
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error(
|
||||
"Could not create WC payment token PayPal for customer {$customer_id}. " . $exception->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
return $payment_token_paypal->get_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a WC Payment Token for Credit Card payment.
|
||||
*
|
||||
* @param int $customer_id The WC customer ID.
|
||||
* @param stdClass $payment_token The Credit Card payment token.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function create_payment_token_card( int $customer_id, stdClass $payment_token ): int {
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, CreditCardGateway::ID );
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $payment_token->id ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$token = new WC_Payment_Token_CC();
|
||||
$token->set_token( $payment_token->id );
|
||||
$token->set_user_id( get_current_user_id() );
|
||||
$token->set_gateway_id( CreditCardGateway::ID );
|
||||
|
||||
$token->set_last4( $payment_token->payment_source->card->last_digits ?? '' );
|
||||
$expiry = explode( '-', $payment_token->payment_source->card->expiry ?? '' );
|
||||
$token->set_expiry_year( $expiry[0] ?? '' );
|
||||
$token->set_expiry_month( $expiry[1] ?? '' );
|
||||
|
||||
$brand = $payment_token->payment_source->card->brand ?? __( 'N/A', 'woocommerce-paypal-payments' );
|
||||
if ( $brand ) {
|
||||
$token->set_card_type( $brand );
|
||||
}
|
||||
|
||||
try {
|
||||
$token->save();
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error(
|
||||
"Could not create WC payment token card for customer {$customer_id}. " . $exception->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
$token->save();
|
||||
return $token->get_id();
|
||||
}
|
||||
}
|
|
@ -126,6 +126,10 @@ class PaymentTokenChecker {
|
|||
return;
|
||||
}
|
||||
|
||||
if ( ! in_array( $wc_order->get_payment_method(), array( PayPalGateway::ID, CreditCardGateway::ID, CardButtonGateway::ID ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $wc_order->get_status() === 'processing' || 'capture' !== $intent ) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -78,6 +78,8 @@ class StatusReportModule implements ModuleInterface {
|
|||
|
||||
$had_ppec_plugin = PPECHelper::is_plugin_configured();
|
||||
|
||||
$subscription_mode_options = $c->get( 'wcgateway.settings.fields.subscriptions_mode_options' );
|
||||
|
||||
$items = array(
|
||||
array(
|
||||
'label' => esc_html__( 'Onboarded', 'woocommerce-paypal-payments' ),
|
||||
|
@ -169,7 +171,7 @@ class StatusReportModule implements ModuleInterface {
|
|||
'description' => esc_html__( 'Whether subscriptions are active and their mode.', 'woocommerce-paypal-payments' ),
|
||||
'value' => $this->subscriptions_mode_text(
|
||||
$subscription_helper->plugin_is_active(),
|
||||
$settings->has( 'subscriptions_mode' ) ? (string) $settings->get( 'subscriptions_mode' ) : '',
|
||||
$settings->has( 'subscriptions_mode' ) ? (string) $subscription_mode_options[ $settings->get( 'subscriptions_mode' ) ] : '',
|
||||
$subscriptions_mode_settings
|
||||
),
|
||||
),
|
||||
|
|
|
@ -56,4 +56,15 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'vaulting.wc-payment-tokens' => static function( ContainerInterface $container ): WooCommercePaymentTokens {
|
||||
return new WooCommercePaymentTokens(
|
||||
$container->get( 'vaulting.payment-token-helper' ),
|
||||
$container->get( 'vaulting.payment-token-factory' ),
|
||||
$container->get( 'api.endpoint.payment-tokens' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'vaulting.vault-v3-enabled' => static function( ContainerInterface $container ): bool {
|
||||
return $container->has( 'save-payment-methods.eligible' ) && $container->get( 'save-payment-methods.eligible' );
|
||||
},
|
||||
);
|
||||
|
|
31
modules/ppcp-vaulting/src/PaymentTokenApplePay.php
Normal file
31
modules/ppcp-vaulting/src/PaymentTokenApplePay.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* WooCommerce Payment token for ApplePay.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Vaulting
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||
|
||||
use WC_Payment_Token;
|
||||
|
||||
/**
|
||||
* Class PaymentTokenApplePay
|
||||
*/
|
||||
class PaymentTokenApplePay extends WC_Payment_Token {
|
||||
/**
|
||||
* Token Type String.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'ApplePay';
|
||||
|
||||
/**
|
||||
* Extra data.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $extra_data = array();
|
||||
}
|
|
@ -19,12 +19,16 @@ class PaymentTokenFactory {
|
|||
*
|
||||
* @param string $type The type of WC payment token.
|
||||
*
|
||||
* @return void|PaymentTokenPayPal
|
||||
* @return void|PaymentTokenPayPal|PaymentTokenVenmo|PaymentTokenApplePay
|
||||
*/
|
||||
public function create( string $type ) {
|
||||
switch ( $type ) {
|
||||
case 'paypal':
|
||||
return new PaymentTokenPayPal();
|
||||
case 'venmo':
|
||||
return new PaymentTokenVenmo();
|
||||
case 'apple_pay':
|
||||
return new PaymentTokenApplePay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,15 +21,39 @@ class PaymentTokenHelper {
|
|||
*
|
||||
* @param WC_Payment_Token[] $wc_tokens WC Payment Tokens.
|
||||
* @param string $token_id Payment Token ID.
|
||||
* @param ?string $class_name Class name of the token.
|
||||
* @return bool
|
||||
*/
|
||||
public function token_exist( array $wc_tokens, string $token_id ): bool {
|
||||
public function token_exist( array $wc_tokens, string $token_id, string $class_name = null ): bool {
|
||||
foreach ( $wc_tokens as $wc_token ) {
|
||||
if ( $wc_token->get_token() === $token_id ) {
|
||||
if ( null !== $class_name ) {
|
||||
if ( $wc_token instanceof $class_name ) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given token exist as WC Payment Token.
|
||||
*
|
||||
* @param array $wc_tokens WC Payment Tokens.
|
||||
* @param string $class_name Class name of the token.
|
||||
* @return null|WC_Payment_Token
|
||||
*/
|
||||
public function first_token_of_type( array $wc_tokens, string $class_name ) {
|
||||
foreach ( $wc_tokens as $wc_token ) {
|
||||
if ( $wc_token instanceof $class_name ) {
|
||||
return $wc_token;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
51
modules/ppcp-vaulting/src/PaymentTokenVenmo.php
Normal file
51
modules/ppcp-vaulting/src/PaymentTokenVenmo.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* WooCommerce Payment token for Venmo.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Vaulting
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||
|
||||
use WC_Payment_Token;
|
||||
|
||||
/**
|
||||
* Class PaymentTokenVenmo
|
||||
*/
|
||||
class PaymentTokenVenmo extends WC_Payment_Token {
|
||||
/**
|
||||
* Token Type String.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'Venmo';
|
||||
|
||||
/**
|
||||
* Extra data.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $extra_data = array(
|
||||
'email' => '',
|
||||
);
|
||||
|
||||
/**
|
||||
* Get PayPal account email.
|
||||
*
|
||||
* @return string PayPal account email.
|
||||
*/
|
||||
public function get_email() {
|
||||
return $this->get_meta( 'email' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set PayPal account email.
|
||||
*
|
||||
* @param string $email PayPal account email.
|
||||
*/
|
||||
public function set_email( $email ) {
|
||||
$this->add_meta_data( 'email', $email, true );
|
||||
}
|
||||
}
|
|
@ -107,7 +107,7 @@ class PaymentTokensMigration {
|
|||
}
|
||||
} elseif ( $token->source()->paypal ) {
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $id, PayPalGateway::ID );
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $token->id() ) ) {
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $token->id(), PaymentTokenPayPal::class ) ) {
|
||||
$this->logger->info( 'Token already exist for user ' . (string) $id );
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -81,11 +81,50 @@ class VaultingModule implements ModuleInterface {
|
|||
if ( $type === 'WC_Payment_Token_PayPal' ) {
|
||||
return PaymentTokenPayPal::class;
|
||||
}
|
||||
if ( $type === 'WC_Payment_Token_Venmo' ) {
|
||||
return PaymentTokenVenmo::class;
|
||||
}
|
||||
if ( $type === 'WC_Payment_Token_ApplePay' ) {
|
||||
return PaymentTokenApplePay::class;
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_get_customer_payment_tokens',
|
||||
/**
|
||||
* Filter available payment tokens depending on context.
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
* @psalm-suppress MissingClosureReturnType
|
||||
*/
|
||||
function( $tokens, $customer_id, $gateway_id ) {
|
||||
if ( ! is_array( $tokens ) ) {
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
$is_post = isset( $_SERVER['REQUEST_METHOD'] ) && $_SERVER['REQUEST_METHOD'] === 'POST';
|
||||
|
||||
// Exclude ApplePay tokens from payment pages.
|
||||
if (
|
||||
( is_checkout() || is_cart() || is_product() )
|
||||
&& ! $is_post // Don't check on POST so we have all payment methods on form submissions.
|
||||
) {
|
||||
foreach ( $tokens as $index => $token ) {
|
||||
if ( $token instanceof PaymentTokenApplePay ) {
|
||||
unset( $tokens[ $index ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
},
|
||||
10,
|
||||
3
|
||||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_payment_methods_list_item',
|
||||
/**
|
||||
|
@ -98,10 +137,18 @@ class VaultingModule implements ModuleInterface {
|
|||
return $item;
|
||||
}
|
||||
|
||||
if ( strtolower( $payment_token->get_type() ) === 'paypal' ) {
|
||||
assert( $payment_token instanceof PaymentTokenPayPal );
|
||||
$item['method']['brand'] = $payment_token->get_email();
|
||||
if ( $payment_token instanceof PaymentTokenPayPal ) {
|
||||
$item['method']['brand'] = 'PayPal / ' . $payment_token->get_email();
|
||||
return $item;
|
||||
}
|
||||
|
||||
if ( $payment_token instanceof PaymentTokenVenmo ) {
|
||||
$item['method']['brand'] = 'Venmo / ' . $payment_token->get_email();
|
||||
return $item;
|
||||
}
|
||||
|
||||
if ( $payment_token instanceof PaymentTokenApplePay ) {
|
||||
$item['method']['brand'] = 'ApplePay #' . ( (string) $payment_token->get_id() );
|
||||
return $item;
|
||||
}
|
||||
|
||||
|
|
326
modules/ppcp-vaulting/src/WooCommercePaymentTokens.php
Normal file
326
modules/ppcp-vaulting/src/WooCommercePaymentTokens.php
Normal file
|
@ -0,0 +1,326 @@
|
|||
<?php
|
||||
/**
|
||||
* Service to create WC Payment Tokens.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Applepay
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Vaulting;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use stdClass;
|
||||
use WC_Payment_Token_CC;
|
||||
use WC_Payment_Tokens;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
|
||||
/**
|
||||
* Class WooCommercePaymentTokens
|
||||
*/
|
||||
class WooCommercePaymentTokens {
|
||||
|
||||
/**
|
||||
* The payment token helper.
|
||||
*
|
||||
* @var PaymentTokenHelper
|
||||
*/
|
||||
private $payment_token_helper;
|
||||
|
||||
/**
|
||||
* The payment token factory.
|
||||
*
|
||||
* @var PaymentTokenFactory
|
||||
*/
|
||||
private $payment_token_factory;
|
||||
|
||||
/**
|
||||
* Payment tokens endpoint.
|
||||
*
|
||||
* @var PaymentTokensEndpoint
|
||||
*/
|
||||
private $payment_tokens_endpoint;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* WooCommercePaymentTokens constructor.
|
||||
*
|
||||
* @param PaymentTokenHelper $payment_token_helper The payment token helper.
|
||||
* @param PaymentTokenFactory $payment_token_factory The payment token factory.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
PaymentTokenHelper $payment_token_helper,
|
||||
PaymentTokenFactory $payment_token_factory,
|
||||
PaymentTokensEndpoint $payment_tokens_endpoint,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->payment_token_helper = $payment_token_helper;
|
||||
$this->payment_token_factory = $payment_token_factory;
|
||||
$this->payment_tokens_endpoint = $payment_tokens_endpoint;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a WC Payment Token for PayPal payment.
|
||||
*
|
||||
* @param int $customer_id The WC customer ID.
|
||||
* @param string $token The PayPal payment token.
|
||||
* @param string $email The PayPal customer email.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function create_payment_token_paypal(
|
||||
int $customer_id,
|
||||
string $token,
|
||||
string $email
|
||||
): int {
|
||||
|
||||
if ( $customer_id === 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, PayPalGateway::ID );
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $token, PaymentTokenPayPal::class ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Try to update existing token of type before creating a new one.
|
||||
$payment_token_paypal = $this->payment_token_helper->first_token_of_type( $wc_tokens, PaymentTokenPayPal::class );
|
||||
|
||||
if ( ! $payment_token_paypal ) {
|
||||
$payment_token_paypal = $this->payment_token_factory->create( 'paypal' );
|
||||
}
|
||||
|
||||
assert( $payment_token_paypal instanceof PaymentTokenPayPal );
|
||||
|
||||
$payment_token_paypal->set_token( $token );
|
||||
$payment_token_paypal->set_user_id( $customer_id );
|
||||
$payment_token_paypal->set_gateway_id( PayPalGateway::ID );
|
||||
|
||||
if ( $email && is_email( $email ) ) {
|
||||
$payment_token_paypal->set_email( $email );
|
||||
}
|
||||
|
||||
try {
|
||||
$payment_token_paypal->save();
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error(
|
||||
"Could not create WC payment token PayPal for customer {$customer_id}. " . $exception->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
return $payment_token_paypal->get_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a WC Payment Token for Venmo payment.
|
||||
*
|
||||
* @param int $customer_id The WC customer ID.
|
||||
* @param string $token The Venmo payment token.
|
||||
* @param string $email The Venmo customer email.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function create_payment_token_venmo(
|
||||
int $customer_id,
|
||||
string $token,
|
||||
string $email
|
||||
): int {
|
||||
|
||||
if ( $customer_id === 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, PayPalGateway::ID );
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $token, PaymentTokenVenmo::class ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Try to update existing token of type before creating a new one.
|
||||
$payment_token_venmo = $this->payment_token_helper->first_token_of_type( $wc_tokens, PaymentTokenVenmo::class );
|
||||
|
||||
if ( ! $payment_token_venmo ) {
|
||||
$payment_token_venmo = $this->payment_token_factory->create( 'venmo' );
|
||||
}
|
||||
|
||||
assert( $payment_token_venmo instanceof PaymentTokenVenmo );
|
||||
|
||||
$payment_token_venmo->set_token( $token );
|
||||
$payment_token_venmo->set_user_id( $customer_id );
|
||||
$payment_token_venmo->set_gateway_id( PayPalGateway::ID );
|
||||
|
||||
if ( $email && is_email( $email ) ) {
|
||||
$payment_token_venmo->set_email( $email );
|
||||
}
|
||||
|
||||
try {
|
||||
$payment_token_venmo->save();
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error(
|
||||
"Could not create WC payment token Venmo for customer {$customer_id}. " . $exception->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
return $payment_token_venmo->get_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a WC Payment Token for ApplePay payment.
|
||||
*
|
||||
* @param int $customer_id The WC customer ID.
|
||||
* @param string $token The ApplePay payment token.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function create_payment_token_applepay(
|
||||
int $customer_id,
|
||||
string $token
|
||||
): int {
|
||||
|
||||
if ( $customer_id === 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, PayPalGateway::ID );
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $token, PaymentTokenApplePay::class ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Try to update existing token of type before creating a new one.
|
||||
$payment_token_applepay = $this->payment_token_helper->first_token_of_type( $wc_tokens, PaymentTokenApplePay::class );
|
||||
|
||||
if ( ! $payment_token_applepay ) {
|
||||
$payment_token_applepay = $this->payment_token_factory->create( 'apple_pay' );
|
||||
}
|
||||
|
||||
assert( $payment_token_applepay instanceof PaymentTokenApplePay );
|
||||
|
||||
$payment_token_applepay->set_token( $token );
|
||||
$payment_token_applepay->set_user_id( $customer_id );
|
||||
$payment_token_applepay->set_gateway_id( PayPalGateway::ID );
|
||||
|
||||
try {
|
||||
$payment_token_applepay->save();
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error(
|
||||
"Could not create WC payment token ApplePay for customer {$customer_id}. " . $exception->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
return $payment_token_applepay->get_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a WC Payment Token for Credit Card payment.
|
||||
*
|
||||
* @param int $customer_id The WC customer ID.
|
||||
* @param stdClass $payment_token The Credit Card payment token.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function create_payment_token_card( int $customer_id, stdClass $payment_token ): int {
|
||||
if ( $customer_id === 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, CreditCardGateway::ID );
|
||||
if ( $this->payment_token_helper->token_exist( $wc_tokens, $payment_token->id ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$token = new WC_Payment_Token_CC();
|
||||
$token->set_token( $payment_token->id );
|
||||
$token->set_user_id( $customer_id );
|
||||
$token->set_gateway_id( CreditCardGateway::ID );
|
||||
|
||||
$token->set_last4( $payment_token->payment_source->card->last_digits ?? '' );
|
||||
$expiry = explode( '-', $payment_token->payment_source->card->expiry ?? '' );
|
||||
$token->set_expiry_year( $expiry[0] ?? '' );
|
||||
$token->set_expiry_month( $expiry[1] ?? '' );
|
||||
|
||||
$brand = $payment_token->payment_source->card->brand ?? __( 'N/A', 'woocommerce-paypal-payments' );
|
||||
if ( $brand ) {
|
||||
$token->set_card_type( $brand );
|
||||
}
|
||||
|
||||
try {
|
||||
$token->save();
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error(
|
||||
"Could not create WC payment token card for customer {$customer_id}. " . $exception->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
$token->save();
|
||||
return $token->get_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns PayPal payment tokens for the given WP user id.
|
||||
*
|
||||
* @param int $user_id WP user id.
|
||||
* @return array
|
||||
*/
|
||||
public function customer_tokens( int $user_id ): array {
|
||||
$customer_id = get_user_meta( $user_id, '_ppcp_target_customer_id', true );
|
||||
if ( ! $customer_id ) {
|
||||
$customer_id = get_user_meta( $user_id, 'ppcp_customer_id', true );
|
||||
}
|
||||
|
||||
try {
|
||||
$customer_tokens = $this->payment_tokens_endpoint->payment_tokens_for_customer( $customer_id );
|
||||
} catch ( RuntimeException $exception ) {
|
||||
$customer_tokens = array();
|
||||
}
|
||||
|
||||
return $customer_tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates WC payment tokens for the given WP user id using PayPal payment tokens as source.
|
||||
*
|
||||
* @param array $customer_tokens PayPal customer payment tokens.
|
||||
* @param int $user_id WP user id.
|
||||
* @return void
|
||||
*/
|
||||
public function create_wc_tokens( array $customer_tokens, int $user_id ): void {
|
||||
foreach ( $customer_tokens as $customer_token ) {
|
||||
if ( $customer_token['payment_source']->name() === 'paypal' ) {
|
||||
$this->create_payment_token_paypal(
|
||||
$user_id,
|
||||
$customer_token['id'],
|
||||
$customer_token['payment_source']->properties()->email_address ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
if ( $customer_token['payment_source']->name() === 'card' ) {
|
||||
/**
|
||||
* Suppress ArgumentTypeCoercion
|
||||
*
|
||||
* @psalm-suppress ArgumentTypeCoercion
|
||||
*/
|
||||
$this->create_payment_token_card(
|
||||
$user_id,
|
||||
(object) array(
|
||||
'id' => $customer_token['id'],
|
||||
'payment_source' => (object) array(
|
||||
$customer_token['payment_source']->name() => $customer_token['payment_source']->properties(),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,8 @@ use WooCommerce\PayPalCommerce\Common\Pattern\SingletonDecorator;
|
|||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Admin\RenderReauthorizeAction;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\CaptureCardPayment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\RefreshFeatureStatusEndpoint;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
@ -102,7 +104,10 @@ return array(
|
|||
$api_shop_country,
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'api.factory.paypal-checkout-url' ),
|
||||
$container->get( 'wcgateway.place-order-button-text' )
|
||||
$container->get( 'wcgateway.place-order-button-text' ),
|
||||
$container->get( 'api.endpoint.payment-tokens' ),
|
||||
$container->get( 'vaulting.vault-v3-enabled' ),
|
||||
$container->get( 'vaulting.wc-payment-tokens' )
|
||||
);
|
||||
},
|
||||
'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway {
|
||||
|
@ -128,9 +133,15 @@ return array(
|
|||
$state,
|
||||
$transaction_url_provider,
|
||||
$subscription_helper,
|
||||
$logger,
|
||||
$payments_endpoint,
|
||||
$vaulted_credit_card_handler
|
||||
$vaulted_credit_card_handler,
|
||||
$container->get( 'onboarding.environment' ),
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'wcgateway.endpoint.capture-card-payment' ),
|
||||
$container->get( 'api.prefix' ),
|
||||
$container->get( 'api.endpoint.payment-tokens' ),
|
||||
$container->get( 'vaulting.wc-payment-tokens' ),
|
||||
$logger
|
||||
);
|
||||
},
|
||||
'wcgateway.card-button-gateway' => static function ( ContainerInterface $container ): CardButtonGateway {
|
||||
|
@ -381,19 +392,25 @@ return array(
|
|||
$notice = $container->get( 'wcgateway.notice.authorize-order-action' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$subscription_helper = $container->get( 'wc-subscriptions.helper' );
|
||||
$amount_factory = $container->get( 'api.factory.amount' );
|
||||
return new AuthorizedPaymentsProcessor(
|
||||
$order_endpoint,
|
||||
$payments_endpoint,
|
||||
$logger,
|
||||
$notice,
|
||||
$settings,
|
||||
$subscription_helper
|
||||
$subscription_helper,
|
||||
$amount_factory
|
||||
);
|
||||
},
|
||||
'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.render-reauthorize-action' => static function ( ContainerInterface $container ): RenderReauthorizeAction {
|
||||
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
||||
return new RenderReauthorizeAction( $column );
|
||||
},
|
||||
'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail {
|
||||
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
||||
return new PaymentStatusOrderDetail( $column );
|
||||
|
@ -405,7 +422,6 @@ return array(
|
|||
'wcgateway.admin.fees-renderer' => static function ( ContainerInterface $container ): FeesRenderer {
|
||||
return new FeesRenderer();
|
||||
},
|
||||
|
||||
'wcgateway.settings.should-render-settings' => static function ( ContainerInterface $container ): bool {
|
||||
|
||||
$sections = array(
|
||||
|
@ -420,13 +436,15 @@ return array(
|
|||
|
||||
return array_key_exists( $current_page_id, $sections );
|
||||
},
|
||||
|
||||
'wcgateway.settings.fields.subscriptions_mode' => static function ( ContainerInterface $container ): array {
|
||||
$subscription_mode_options = array(
|
||||
'wcgateway.settings.fields.subscriptions_mode_options' => static function ( ContainerInterface $container ): array {
|
||||
return array(
|
||||
'vaulting_api' => __( 'PayPal Vaulting', 'woocommerce-paypal-payments' ),
|
||||
'subscriptions_api' => __( 'PayPal Subscriptions', 'woocommerce-paypal-payments' ),
|
||||
'disable_paypal_subscriptions' => __( 'Disable PayPal for subscriptions', 'woocommerce-paypal-payments' ),
|
||||
);
|
||||
},
|
||||
'wcgateway.settings.fields.subscriptions_mode' => static function ( ContainerInterface $container ): array {
|
||||
$subscription_mode_options = $container->get( 'wcgateway.settings.fields.subscriptions_mode_options' );
|
||||
|
||||
$billing_agreements_endpoint = $container->get( 'api.endpoint.billing-agreements' );
|
||||
$reference_transaction_enabled = $billing_agreements_endpoint->reference_transaction_enabled();
|
||||
|
@ -441,7 +459,7 @@ return array(
|
|||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Utilize PayPal Vaulting for flexible subscription processing with saved payment methods, create “PayPal Subscriptions” to bill customers at regular intervals, or disable PayPal for subscription-type products.', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'vaulting_api',
|
||||
'default' => array_key_first( $subscription_mode_options ),
|
||||
'options' => $subscription_mode_options,
|
||||
'screens' => array(
|
||||
State::STATE_ONBOARDED,
|
||||
|
@ -964,11 +982,6 @@ return array(
|
|||
unset( $fields['subscriptions_mode'] );
|
||||
}
|
||||
|
||||
$billing_agreements_endpoint = $container->get( 'api.endpoint.billing-agreements' );
|
||||
if ( ! $billing_agreements_endpoint->reference_transaction_enabled() ) {
|
||||
unset( $fields['vault_enabled'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on your store location, some credit cards can't be used.
|
||||
* Here, we filter them out.
|
||||
|
@ -1006,10 +1019,10 @@ return array(
|
|||
'ideal' => _x( 'iDEAL', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'mybank' => _x( 'MyBank', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'p24' => _x( 'Przelewy24', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'sofort' => _x( 'Sofort', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'venmo' => _x( 'Venmo', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'trustly' => _x( 'Trustly', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'paylater' => _x( 'Pay Later', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'paylater' => _x( 'PayPal Pay Later', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'paypal' => _x( 'PayPal', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -1032,6 +1045,7 @@ return array(
|
|||
array_flip(
|
||||
array(
|
||||
'paylater',
|
||||
'paypal',
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -1634,4 +1648,17 @@ return array(
|
|||
)
|
||||
);
|
||||
},
|
||||
'wcgateway.endpoint.capture-card-payment' => static function( ContainerInterface $container ): CaptureCardPayment {
|
||||
return new CaptureCardPayment(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'api.factory.order' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'session.handler' ),
|
||||
$container->get( 'wc-subscriptions.helpers.real-time-account-updater' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -9,9 +9,6 @@ declare( strict_types=1 );
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Admin;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
|
||||
/**
|
||||
* Class RenderAuthorizeAction
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* Renders the order action "Reauthorize PayPal payment"
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Admin
|
||||
*/
|
||||
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Admin;
|
||||
|
||||
/**
|
||||
* Class RenderReauthorizeAction
|
||||
*/
|
||||
class RenderReauthorizeAction {
|
||||
/**
|
||||
* The capture info column.
|
||||
*
|
||||
* @var OrderTablePaymentStatusColumn
|
||||
*/
|
||||
private $column;
|
||||
|
||||
/**
|
||||
* PaymentStatusOrderDetail constructor.
|
||||
*
|
||||
* @param OrderTablePaymentStatusColumn $column The capture info column.
|
||||
*/
|
||||
public function __construct( OrderTablePaymentStatusColumn $column ) {
|
||||
$this->column = $column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the action into the $order_actions array based on the WooCommerce order.
|
||||
*
|
||||
* @param array $order_actions The actions to render into.
|
||||
* @param \WC_Order $wc_order The order for which to render the action.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function render( array $order_actions, \WC_Order $wc_order ) : array {
|
||||
|
||||
if ( ! $this->should_render_for_order( $wc_order ) ) {
|
||||
return $order_actions;
|
||||
}
|
||||
|
||||
$order_actions['ppcp_reauthorize_order'] = esc_html__(
|
||||
'Reauthorize PayPal payment',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
return $order_actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the action should be rendered for a certain WooCommerce order.
|
||||
*
|
||||
* @param \WC_Order $order The Woocommerce order.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function should_render_for_order( \WC_Order $order ) : bool {
|
||||
$status = $order->get_status();
|
||||
$not_allowed_statuses = array( 'refunded', 'cancelled', 'failed' );
|
||||
return $this->column->should_render_for_order( $order ) &&
|
||||
! $this->column->is_captured( $order ) &&
|
||||
! in_array( $status, $not_allowed_statuses, true );
|
||||
}
|
||||
}
|
|
@ -9,12 +9,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Assets;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingAgreementsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\RefreshFeatureStatusEndpoint;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\Endpoint\ResubscribeEndpoint;
|
||||
|
||||
/**
|
||||
* Class SettingsPageAssets
|
||||
|
@ -105,6 +105,13 @@ class SettingsPageAssets {
|
|||
*/
|
||||
private $is_acdc_enabled;
|
||||
|
||||
/**
|
||||
* Billing Agreements endpoint.
|
||||
*
|
||||
* @var BillingAgreementsEndpoint
|
||||
*/
|
||||
private $billing_agreements_endpoint;
|
||||
|
||||
/**
|
||||
* Assets constructor.
|
||||
*
|
||||
|
@ -120,6 +127,7 @@ class SettingsPageAssets {
|
|||
* @param array $all_funding_sources The list of all existing funding sources.
|
||||
* @param bool $is_settings_page Whether it's a settings page of this plugin.
|
||||
* @param bool $is_acdc_enabled Whether the ACDC gateway is enabled.
|
||||
* @param BillingAgreementsEndpoint $billing_agreements_endpoint Billing Agreements endpoint.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
|
@ -133,7 +141,8 @@ class SettingsPageAssets {
|
|||
array $disabled_sources,
|
||||
array $all_funding_sources,
|
||||
bool $is_settings_page,
|
||||
bool $is_acdc_enabled
|
||||
bool $is_acdc_enabled,
|
||||
BillingAgreementsEndpoint $billing_agreements_endpoint
|
||||
) {
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
|
@ -147,6 +156,7 @@ class SettingsPageAssets {
|
|||
$this->all_funding_sources = $all_funding_sources;
|
||||
$this->is_settings_page = $is_settings_page;
|
||||
$this->is_acdc_enabled = $is_acdc_enabled;
|
||||
$this->billing_agreements_endpoint = $billing_agreements_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -250,6 +260,13 @@ class SettingsPageAssets {
|
|||
),
|
||||
),
|
||||
),
|
||||
'reference_transaction_enabled' => $this->billing_agreements_endpoint->reference_transaction_enabled(),
|
||||
'vaulting_must_enable_advanced_wallet_message' => sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
esc_html__( 'Your PayPal account must be enabled for the %1$sAdvanced PayPal Wallet%2$s to use PayPal Vaulting.', 'woocommerce-paypal-payments' ),
|
||||
'<a href="/wp-admin/admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=ppcp-connection#field-credentials_feature_onboarding_heading">',
|
||||
'</a>'
|
||||
),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
186
modules/ppcp-wc-gateway/src/Endpoint/CaptureCardPayment.php
Normal file
186
modules/ppcp-wc-gateway/src/Endpoint/CaptureCardPayment.php
Normal file
|
@ -0,0 +1,186 @@
|
|||
<?php
|
||||
/**
|
||||
* The Capture Card Payment endpoint.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Endpoint;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use stdClass;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\RequestTrait;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\RealTimeAccountUpdaterHelper;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class CaptureCardPayment
|
||||
*/
|
||||
class CaptureCardPayment {
|
||||
|
||||
use RequestTrait;
|
||||
|
||||
/**
|
||||
* The host.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $host;
|
||||
|
||||
/**
|
||||
* The bearer.
|
||||
*
|
||||
* @var Bearer
|
||||
*/
|
||||
private $bearer;
|
||||
|
||||
/**
|
||||
* The order factory.
|
||||
*
|
||||
* @var OrderFactory
|
||||
*/
|
||||
private $order_factory;
|
||||
|
||||
/**
|
||||
* The purchase unit factory.
|
||||
*
|
||||
* @var PurchaseUnitFactory
|
||||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
private $order_endpoint;
|
||||
|
||||
/**
|
||||
* The session handler.
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
private $session_handler;
|
||||
|
||||
/**
|
||||
* Real Time Account Updater helper.
|
||||
*
|
||||
* @var RealTimeAccountUpdaterHelper
|
||||
*/
|
||||
private $real_time_account_updater_helper;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* CaptureCardPayment constructor.
|
||||
*
|
||||
* @param string $host The host.
|
||||
* @param Bearer $bearer The bearer.
|
||||
* @param OrderFactory $order_factory The order factory.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param SessionHandler $session_handler The session handler.
|
||||
* @param RealTimeAccountUpdaterHelper $real_time_account_updater_helper Real Time Account Updater helper.
|
||||
* @param Settings $settings The settings.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
string $host,
|
||||
Bearer $bearer,
|
||||
OrderFactory $order_factory,
|
||||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
OrderEndpoint $order_endpoint,
|
||||
SessionHandler $session_handler,
|
||||
RealTimeAccountUpdaterHelper $real_time_account_updater_helper,
|
||||
Settings $settings,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->host = $host;
|
||||
$this->bearer = $bearer;
|
||||
$this->order_factory = $order_factory;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->real_time_account_updater_helper = $real_time_account_updater_helper;
|
||||
$this->settings = $settings;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates PayPal order from the given card vault id.
|
||||
*
|
||||
* @param string $vault_id Vault id.
|
||||
* @param string $custom_id Custom id.
|
||||
* @param string $invoice_id Invoice id.
|
||||
* @return stdClass
|
||||
* @throws RuntimeException When request fails.
|
||||
*/
|
||||
public function create_order( string $vault_id, string $custom_id, string $invoice_id ): stdClass {
|
||||
$intent = $this->settings->has( 'intent' ) && strtoupper( (string) $this->settings->get( 'intent' ) ) === 'AUTHORIZE' ? 'AUTHORIZE' : 'CAPTURE';
|
||||
$items = array( $this->purchase_unit_factory->from_wc_cart() );
|
||||
|
||||
$data = array(
|
||||
'intent' => $intent,
|
||||
'purchase_units' => array_map(
|
||||
static function ( PurchaseUnit $item ): array {
|
||||
return $item->to_array( true, false );
|
||||
},
|
||||
$items
|
||||
),
|
||||
'payment_source' => array(
|
||||
'card' => array(
|
||||
'vault_id' => $vault_id,
|
||||
'stored_credential' => array(
|
||||
'payment_initiator' => 'CUSTOMER',
|
||||
'payment_type' => 'UNSCHEDULED',
|
||||
'usage' => 'SUBSEQUENT',
|
||||
),
|
||||
),
|
||||
),
|
||||
'custom_id' => $custom_id,
|
||||
'invoice_id' => $invoice_id,
|
||||
);
|
||||
|
||||
$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',
|
||||
'PayPal-Request-Id' => uniqid( 'ppcp-', true ),
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( $response instanceof WP_Error ) {
|
||||
throw new RuntimeException( $response->get_error_message() );
|
||||
}
|
||||
|
||||
return json_decode( $response['body'] );
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ class FundingSourceRenderer {
|
|||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $own_funding_sources = array( 'venmo', 'paylater' );
|
||||
protected $own_funding_sources = array( 'venmo', 'paylater', 'paypal' );
|
||||
|
||||
/**
|
||||
* FundingSourceRenderer constructor.
|
||||
|
@ -56,12 +56,14 @@ class FundingSourceRenderer {
|
|||
* @param string $id The ID of the funding source, such as 'venmo'.
|
||||
*/
|
||||
public function render_name( string $id ): string {
|
||||
$id = $this->sanitize_id( $id );
|
||||
|
||||
if ( array_key_exists( $id, $this->funding_sources ) ) {
|
||||
if ( in_array( $id, $this->own_funding_sources, true ) ) {
|
||||
return $this->funding_sources[ $id ];
|
||||
}
|
||||
return sprintf(
|
||||
/* translators: %s - Sofort, BLIK, iDeal, Mercado Pago, etc. */
|
||||
/* translators: %s - BLIK, iDeal, Mercado Pago, etc. */
|
||||
__( '%s (via PayPal)', 'woocommerce-paypal-payments' ),
|
||||
$this->funding_sources[ $id ]
|
||||
);
|
||||
|
@ -78,9 +80,11 @@ class FundingSourceRenderer {
|
|||
* @param string $id The ID of the funding source, such as 'venmo'.
|
||||
*/
|
||||
public function render_description( string $id ): string {
|
||||
$id = $this->sanitize_id( $id );
|
||||
|
||||
if ( array_key_exists( $id, $this->funding_sources ) ) {
|
||||
return sprintf(
|
||||
/* translators: %s - Sofort, BLIK, iDeal, Mercado Pago, etc. */
|
||||
/* translators: %s - BLIK, iDeal, Mercado Pago, etc. */
|
||||
__( 'Pay via %s.', 'woocommerce-paypal-payments' ),
|
||||
$this->funding_sources[ $id ]
|
||||
);
|
||||
|
@ -90,4 +94,14 @@ class FundingSourceRenderer {
|
|||
$this->settings->get( 'description' )
|
||||
: __( 'Pay via PayPal.', 'woocommerce-paypal-payments' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the id to a standard format.
|
||||
*
|
||||
* @param string $id The funding source id.
|
||||
* @return string
|
||||
*/
|
||||
private function sanitize_id( string $id ): string {
|
||||
return str_replace( '_', '', strtolower( $id ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,27 +13,35 @@ use Exception;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WC_Payment_Tokens;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\VaultedCreditCardHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\CaptureCardPayment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
|
||||
/**
|
||||
* Class CreditCardGateway
|
||||
*/
|
||||
class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||
|
||||
use ProcessPaymentTrait, GatewaySettingsRendererTrait, TransactionIdHandlingTrait;
|
||||
use ProcessPaymentTrait, GatewaySettingsRendererTrait, TransactionIdHandlingTrait, PaymentsStatusHandlingTrait, FreeTrialHandlerTrait;
|
||||
|
||||
const ID = 'ppcp-credit-card-gateway';
|
||||
|
||||
|
@ -114,13 +122,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
*/
|
||||
protected $subscription_helper;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* The payments endpoint
|
||||
*
|
||||
|
@ -128,6 +129,55 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
*/
|
||||
protected $payments_endpoint;
|
||||
|
||||
/**
|
||||
* The environment.
|
||||
*
|
||||
* @var Environment
|
||||
*/
|
||||
private $environment;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
private $order_endpoint;
|
||||
|
||||
/**
|
||||
* Capture card payment.
|
||||
*
|
||||
* @var CaptureCardPayment
|
||||
*/
|
||||
private $capture_card_payment;
|
||||
|
||||
/**
|
||||
* The prefix.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $prefix;
|
||||
|
||||
/**
|
||||
* Payment tokens endpoint.
|
||||
*
|
||||
* @var PaymentTokensEndpoint
|
||||
*/
|
||||
private $payment_tokens_endpoint;
|
||||
|
||||
/**
|
||||
* WooCommerce payment tokens factory.
|
||||
*
|
||||
* @var WooCommercePaymentTokens
|
||||
*/
|
||||
private $wc_payment_tokens;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* CreditCardGateway constructor.
|
||||
*
|
||||
|
@ -140,9 +190,15 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
* @param State $state The state.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service able to provide view transaction url base.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentsEndpoint $payments_endpoint The payments endpoint.
|
||||
* @param VaultedCreditCardHandler $vaulted_credit_card_handler The vaulted credit card handler.
|
||||
* @param Environment $environment The environment.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param CaptureCardPayment $capture_card_payment Capture card payment.
|
||||
* @param string $prefix The prefix.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param WooCommercePaymentTokens $wc_payment_tokens WooCommerce payment tokens factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsRenderer $settings_renderer,
|
||||
|
@ -154,9 +210,15 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
State $state,
|
||||
TransactionUrlProvider $transaction_url_provider,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
LoggerInterface $logger,
|
||||
PaymentsEndpoint $payments_endpoint,
|
||||
VaultedCreditCardHandler $vaulted_credit_card_handler
|
||||
VaultedCreditCardHandler $vaulted_credit_card_handler,
|
||||
Environment $environment,
|
||||
OrderEndpoint $order_endpoint,
|
||||
CaptureCardPayment $capture_card_payment,
|
||||
string $prefix,
|
||||
PaymentTokensEndpoint $payment_tokens_endpoint,
|
||||
WooCommercePaymentTokens $wc_payment_tokens,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
|
@ -168,9 +230,15 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
$this->state = $state;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->logger = $logger;
|
||||
$this->payments_endpoint = $payments_endpoint;
|
||||
$this->vaulted_credit_card_handler = $vaulted_credit_card_handler;
|
||||
$this->environment = $environment;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->capture_card_payment = $capture_card_payment;
|
||||
$this->prefix = $prefix;
|
||||
$this->payment_tokens_endpoint = $payment_tokens_endpoint;
|
||||
$this->wc_payment_tokens = $wc_payment_tokens;
|
||||
$this->logger = $logger;
|
||||
|
||||
if ( $state->current_state() === State::STATE_ONBOARDED ) {
|
||||
$this->supports = array( 'refunds' );
|
||||
|
@ -246,8 +314,10 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
*/
|
||||
public function form() {
|
||||
add_action( 'gettext', array( $this, 'replace_credit_card_cvv_label' ), 10, 3 );
|
||||
add_action( 'gettext', array( $this, 'replace_credit_card_cvv_placeholder' ), 10, 3 );
|
||||
parent::form();
|
||||
remove_action( 'gettext', 'replace_credit_card_cvv_label' );
|
||||
remove_action( 'gettext', 'replace_credit_card_cvv_placeholder' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -267,6 +337,23 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
return __( 'CVV', 'woocommerce-paypal-payments' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace WooCommerce credit card CVV field placeholder.
|
||||
*
|
||||
* @param string $translation Translated text.
|
||||
* @param string $text Original text to translate.
|
||||
* @param string $domain Text domain.
|
||||
*
|
||||
* @return string Translated field.
|
||||
*/
|
||||
public function replace_credit_card_cvv_placeholder( string $translation, string $text, string $domain ): string {
|
||||
if ( 'woocommerce' !== $domain || 'CVC' !== $text || ! apply_filters( 'woocommerce_paypal_payments_card_fields_translate_card_cvv', true ) ) {
|
||||
return $translation;
|
||||
}
|
||||
|
||||
return __( 'CVV', 'woocommerce-paypal-payments' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icons of the gateway.
|
||||
*
|
||||
|
@ -366,19 +453,69 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
);
|
||||
}
|
||||
|
||||
$saved_payment_card = WC()->session->get( 'ppcp_saved_payment_card' );
|
||||
if ( $saved_payment_card ) {
|
||||
if ( $saved_payment_card['payment_source'] === 'card' && $saved_payment_card['status'] === 'COMPLETED' ) {
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_ID_META_KEY, $saved_payment_card['order_id'] );
|
||||
$wc_order->save_meta_data();
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$card_payment_token_id = wc_clean( wp_unslash( $_POST['wc-ppcp-credit-card-gateway-payment-token'] ?? '' ) );
|
||||
|
||||
$this->update_transaction_id( $saved_payment_card['order_id'], $wc_order );
|
||||
if ( $this->is_free_trial_order( $wc_order ) && $card_payment_token_id ) {
|
||||
$customer_tokens = $this->wc_payment_tokens->customer_tokens( get_current_user_id() );
|
||||
foreach ( $customer_tokens as $token ) {
|
||||
if ( $token['payment_source']->name() === 'card' ) {
|
||||
$wc_order->payment_complete();
|
||||
WC()->session->set( 'ppcp_saved_payment_card', null );
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $card_payment_token_id ) {
|
||||
$customer_tokens = $this->wc_payment_tokens->customer_tokens( get_current_user_id() );
|
||||
|
||||
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), self::ID );
|
||||
|
||||
if ( $customer_tokens && empty( $wc_tokens ) ) {
|
||||
$this->wc_payment_tokens->create_wc_tokens( $customer_tokens, get_current_user_id() );
|
||||
}
|
||||
|
||||
$customer_token_ids = array();
|
||||
foreach ( $customer_tokens as $customer_token ) {
|
||||
$customer_token_ids[] = $customer_token['id'];
|
||||
}
|
||||
|
||||
$tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id() );
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( $token->get_id() === (int) $card_payment_token_id ) {
|
||||
if ( ! in_array( $token->get_token(), $customer_token_ids, true ) ) {
|
||||
$token->delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
$custom_id = $wc_order->get_order_number();
|
||||
$invoice_id = $this->prefix . $wc_order->get_order_number();
|
||||
$create_order = $this->capture_card_payment->create_order( $token->get_token(), $custom_id, $invoice_id );
|
||||
|
||||
$order = $this->order_endpoint->order( $create_order->id );
|
||||
$wc_order->update_meta_data( PayPalGateway::INTENT_META_KEY, $order->intent() );
|
||||
|
||||
if ( $order->intent() === 'AUTHORIZE' ) {
|
||||
$order = $this->order_endpoint->authorize( $order );
|
||||
|
||||
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'false' );
|
||||
|
||||
if ( $this->subscription_helper->has_subscription( $wc_order->get_id() ) ) {
|
||||
$wc_order->update_meta_data( '_ppcp_captured_vault_webhook', 'false' );
|
||||
}
|
||||
}
|
||||
|
||||
$transaction_id = $this->get_paypal_order_transaction_id( $order );
|
||||
if ( $transaction_id ) {
|
||||
$this->update_transaction_id( $transaction_id, $wc_order );
|
||||
}
|
||||
|
||||
$this->handle_new_order_status( $order, $wc_order );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen a saved credit card payment from checkout page.
|
||||
|
|
|
@ -14,12 +14,14 @@ use Psr\Log\LoggerInterface;
|
|||
use WC_Order;
|
||||
use WC_Payment_Tokens;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
|
@ -48,9 +50,17 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
const ORDER_ID_META_KEY = '_ppcp_paypal_order_id';
|
||||
const ORDER_PAYMENT_MODE_META_KEY = '_ppcp_paypal_payment_mode';
|
||||
const ORDER_PAYMENT_SOURCE_META_KEY = '_ppcp_paypal_payment_source';
|
||||
const ORDER_PAYER_EMAIL_META_KEY = '_ppcp_paypal_payer_email';
|
||||
const FEES_META_KEY = '_ppcp_paypal_fees';
|
||||
const REFUND_FEES_META_KEY = '_ppcp_paypal_refund_fees';
|
||||
const REFUNDS_META_KEY = '_ppcp_refunds';
|
||||
const THREE_D_AUTH_RESULT_META_KEY = '_ppcp_paypal_3DS_auth_result';
|
||||
const FRAUD_RESULT_META_KEY = '_ppcp_paypal_fraud_result';
|
||||
|
||||
/**
|
||||
* List of payment sources wich we are expected to store the payer email in the WC Order metadata.
|
||||
*/
|
||||
const PAYMENT_SOURCES_WITH_PAYER_EMAIL = array( 'paypal', 'paylater', 'venmo' );
|
||||
|
||||
/**
|
||||
* The Settings Renderer.
|
||||
|
@ -171,6 +181,27 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
*/
|
||||
private $paypal_checkout_url_factory;
|
||||
|
||||
/**
|
||||
* Payment tokens endpoint.
|
||||
*
|
||||
* @var PaymentTokensEndpoint
|
||||
*/
|
||||
private $payment_tokens_endpoint;
|
||||
|
||||
/**
|
||||
* Whether Vault v3 module is enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $vault_v3_enabled;
|
||||
|
||||
/**
|
||||
* WooCommerce payment tokens.
|
||||
*
|
||||
* @var WooCommercePaymentTokens
|
||||
*/
|
||||
private $wc_payment_tokens;
|
||||
|
||||
/**
|
||||
* PayPalGateway constructor.
|
||||
*
|
||||
|
@ -191,6 +222,9 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param callable(string):string $paypal_checkout_url_factory The function return the PayPal checkout URL for the given order ID.
|
||||
* @param string $place_order_button_text The text for the standard "Place order" button.
|
||||
* @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint.
|
||||
* @param bool $vault_v3_enabled Whether Vault v3 module is enabled.
|
||||
* @param WooCommercePaymentTokens $wc_payment_tokens WooCommerce payment tokens.
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsRenderer $settings_renderer,
|
||||
|
@ -209,7 +243,10 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
string $api_shop_country,
|
||||
OrderEndpoint $order_endpoint,
|
||||
callable $paypal_checkout_url_factory,
|
||||
string $place_order_button_text
|
||||
string $place_order_button_text,
|
||||
PaymentTokensEndpoint $payment_tokens_endpoint,
|
||||
bool $vault_v3_enabled,
|
||||
WooCommercePaymentTokens $wc_payment_tokens
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
|
@ -229,6 +266,10 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
$this->api_shop_country = $api_shop_country;
|
||||
$this->paypal_checkout_url_factory = $paypal_checkout_url_factory;
|
||||
$this->order_button_text = $place_order_button_text;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->payment_tokens_endpoint = $payment_tokens_endpoint;
|
||||
$this->vault_v3_enabled = $vault_v3_enabled;
|
||||
$this->wc_payment_tokens = $wc_payment_tokens;
|
||||
|
||||
if ( $this->onboarded ) {
|
||||
$this->supports = array( 'refunds', 'tokenization' );
|
||||
|
@ -291,8 +332,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
'process_admin_options',
|
||||
)
|
||||
);
|
||||
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,13 +433,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
}
|
||||
|
||||
if ( $this->is_pay_later_tab() ) {
|
||||
return sprintf(
|
||||
// translators: %1$s is </ br> HTML tag and %2$s, %3$s are the opening and closing of HTML <i> tag.
|
||||
__( 'Let customers pay over time while you get paid up front — at no additional cost.%1$sPayPal’s pay later options are boosting merchant conversion rates and increasing cart sizes by 39%%. %2$s(PayPal Q2 Earnings-2021.)%3$s', 'woocommerce-paypal-payments' ),
|
||||
'</ br>',
|
||||
'<i>',
|
||||
'</ i>'
|
||||
);
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( is_admin() ) {
|
||||
|
@ -498,7 +531,49 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
$wc_order->save();
|
||||
}
|
||||
|
||||
if ( 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) && ! $this->subscription_helper->paypal_subscription_id() ) {
|
||||
if (
|
||||
'card' !== $funding_source
|
||||
&& $this->is_free_trial_order( $wc_order )
|
||||
&& ! $this->subscription_helper->paypal_subscription_id()
|
||||
) {
|
||||
$ppcp_guest_payment_for_free_trial = WC()->session->get( 'ppcp_guest_payment_for_free_trial' ) ?? null;
|
||||
if ( $this->vault_v3_enabled && $ppcp_guest_payment_for_free_trial ) {
|
||||
$customer_id = $ppcp_guest_payment_for_free_trial->customer->id ?? '';
|
||||
if ( $customer_id ) {
|
||||
update_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', $customer_id );
|
||||
}
|
||||
|
||||
if ( isset( $ppcp_guest_payment_for_free_trial->payment_source->paypal ) ) {
|
||||
$email = '';
|
||||
if ( isset( $ppcp_guest_payment_for_free_trial->payment_source->paypal->email_address ) ) {
|
||||
$email = $ppcp_guest_payment_for_free_trial->payment_source->paypal->email_address;
|
||||
}
|
||||
|
||||
$this->wc_payment_tokens->create_payment_token_paypal(
|
||||
$wc_order->get_customer_id(),
|
||||
$ppcp_guest_payment_for_free_trial->id,
|
||||
$email
|
||||
);
|
||||
}
|
||||
|
||||
WC()->session->set( 'ppcp_guest_payment_for_free_trial', null );
|
||||
|
||||
$wc_order->payment_complete();
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
|
||||
$customer_id = get_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', true );
|
||||
if ( $customer_id ) {
|
||||
$customer_tokens = $this->payment_tokens_endpoint->payment_tokens_for_customer( $customer_id );
|
||||
foreach ( $customer_tokens as $token ) {
|
||||
$payment_source_name = $token['payment_source']->name() ?? '';
|
||||
if ( $payment_source_name === 'paypal' || $payment_source_name === 'venmo' ) {
|
||||
$wc_order->payment_complete();
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( $user_id );
|
||||
if ( ! array_filter(
|
||||
|
@ -511,7 +586,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
}
|
||||
|
||||
$wc_order->payment_complete();
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
|
||||
|
|
|
@ -202,7 +202,13 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|||
'type' => 'text',
|
||||
'default' => get_bloginfo( 'name' ) ?? '',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Merchant name displayed in Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ),
|
||||
'description' => __( 'Merchant name displayed in Ratepay\'s payment instructions. Should not exceed 127 characters.', 'woocommerce-paypal-payments' ),
|
||||
'maxlength' => 127,
|
||||
'custom_attributes' => array(
|
||||
'pattern' => '.{1,127}',
|
||||
'autocomplete' => 'off',
|
||||
'required' => '',
|
||||
),
|
||||
),
|
||||
'logo_url' => array(
|
||||
'title' => __( 'Logo URL', 'woocommerce-paypal-payments' ),
|
||||
|
@ -210,6 +216,11 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Logo to be presented on Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ),
|
||||
'custom_attributes' => array(
|
||||
'pattern' => '.+',
|
||||
'autocomplete' => 'off',
|
||||
'required' => '',
|
||||
),
|
||||
),
|
||||
'customer_service_instructions' => array(
|
||||
'title' => __( 'Customer service instructions', 'woocommerce-paypal-payments' ),
|
||||
|
@ -217,6 +228,11 @@ class PayUponInvoiceGateway extends WC_Payment_Gateway {
|
|||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Customer service instructions to be presented on Ratepay\'s payment instructions.', 'woocommerce-paypal-payments' ),
|
||||
'custom_attributes' => array(
|
||||
'pattern' => '.+',
|
||||
'autocomplete' => 'off',
|
||||
'required' => '',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Processor;
|
||||
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\AmountFactory;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
|
@ -91,6 +93,20 @@ class AuthorizedPaymentsProcessor {
|
|||
*/
|
||||
private $subscription_helper;
|
||||
|
||||
/**
|
||||
* The amount factory.
|
||||
*
|
||||
* @var AmountFactory
|
||||
*/
|
||||
private $amount_factory;
|
||||
|
||||
/**
|
||||
* The reauthorization failure reason.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $reauthorization_failure_reason = '';
|
||||
|
||||
/**
|
||||
* AuthorizedPaymentsProcessor constructor.
|
||||
*
|
||||
|
@ -100,6 +116,7 @@ class AuthorizedPaymentsProcessor {
|
|||
* @param AuthorizeOrderActionNotice $notice The notice.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param AmountFactory $amount_factory The amount factory.
|
||||
*/
|
||||
public function __construct(
|
||||
OrderEndpoint $order_endpoint,
|
||||
|
@ -107,7 +124,8 @@ class AuthorizedPaymentsProcessor {
|
|||
LoggerInterface $logger,
|
||||
AuthorizeOrderActionNotice $notice,
|
||||
ContainerInterface $config,
|
||||
SubscriptionHelper $subscription_helper
|
||||
SubscriptionHelper $subscription_helper,
|
||||
AmountFactory $amount_factory
|
||||
) {
|
||||
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
|
@ -116,6 +134,7 @@ class AuthorizedPaymentsProcessor {
|
|||
$this->notice = $notice;
|
||||
$this->config = $config;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->amount_factory = $amount_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,6 +268,67 @@ class AuthorizedPaymentsProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reauthorizes an authorized payment for an WooCommerce order.
|
||||
*
|
||||
* @param WC_Order $wc_order The WooCommerce order.
|
||||
*
|
||||
* @return string The status or reauthorization id.
|
||||
*/
|
||||
public function reauthorize_payment( WC_Order $wc_order ): string {
|
||||
$this->reauthorization_failure_reason = '';
|
||||
|
||||
try {
|
||||
$order = $this->paypal_order_from_wc_order( $wc_order );
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( 'Could not get PayPal order from WC order: ' . $exception->getMessage() );
|
||||
if ( $exception->getCode() === 404 ) {
|
||||
return self::NOT_FOUND;
|
||||
}
|
||||
return self::INACCESSIBLE;
|
||||
}
|
||||
|
||||
$amount = $this->amount_factory->from_wc_order( $wc_order );
|
||||
|
||||
$authorizations = $this->all_authorizations( $order );
|
||||
$uncaptured_authorizations = $this->authorizations_to_capture( ...$authorizations );
|
||||
|
||||
if ( ! $uncaptured_authorizations ) {
|
||||
if ( $this->captured_authorizations( ...$authorizations ) ) {
|
||||
$this->logger->info( 'Authorizations already captured.' );
|
||||
return self::ALREADY_CAPTURED;
|
||||
}
|
||||
|
||||
$this->logger->info( 'Bad authorization.' );
|
||||
return self::BAD_AUTHORIZATION;
|
||||
}
|
||||
|
||||
$authorization = end( $uncaptured_authorizations );
|
||||
|
||||
try {
|
||||
$this->payments_endpoint->reauthorize( $authorization->id(), new Money( $amount->value(), $amount->currency_code() ) );
|
||||
} catch ( PayPalApiException $exception ) {
|
||||
$this->reauthorization_failure_reason = $exception->details()[0]->description ?? null;
|
||||
$this->logger->error( 'Reauthorization failed: ' . $exception->name() . ' | ' . $this->reauthorization_failure_reason );
|
||||
return self::FAILED;
|
||||
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error( 'Failed to capture authorization: ' . $exception->getMessage() );
|
||||
return self::FAILED;
|
||||
}
|
||||
|
||||
return self::SUCCESSFUL;
|
||||
}
|
||||
|
||||
/**
|
||||
* The reason for a failed reauthorization.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function reauthorization_failure_reason(): string {
|
||||
return $this->reauthorization_failure_reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Voids authorizations for the given PayPal order.
|
||||
*
|
||||
|
@ -392,4 +472,5 @@ class AuthorizedPaymentsProcessor {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
/**
|
||||
* Common operations performed for handling the ACDC order info.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Processor
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Processor;
|
||||
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\FraudProcessorResponse;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\CardAuthenticationResultFactory;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
|
||||
/**
|
||||
* Trait CreditCardOrderInfoHandlingTrait.
|
||||
*/
|
||||
trait CreditCardOrderInfoHandlingTrait {
|
||||
|
||||
/**
|
||||
* Handles the 3DS details.
|
||||
*
|
||||
* Adds the order note with 3DS details.
|
||||
* Adds the order meta with 3DS details.
|
||||
*
|
||||
* @param Order $order The PayPal order.
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
*/
|
||||
protected function handle_three_d_secure(
|
||||
Order $order,
|
||||
WC_Order $wc_order
|
||||
): void {
|
||||
|
||||
$payment_source = $order->payment_source();
|
||||
if ( ! $payment_source || $payment_source->name() !== 'card' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$authentication_result = $payment_source->properties()->authentication_result ?? null;
|
||||
|
||||
if ( $authentication_result ) {
|
||||
$card_authentication_result_factory = new CardAuthenticationResultFactory();
|
||||
$result = $card_authentication_result_factory->from_paypal_response( $authentication_result );
|
||||
|
||||
$three_d_response_order_note_title = __( '3DS Authentication Result', 'woocommerce-paypal-payments' );
|
||||
/* translators: %1$s is 3DS order note title, %2$s is 3DS order note result markup */
|
||||
$three_d_response_order_note_format = __( '%1$s %2$s', 'woocommerce-paypal-payments' );
|
||||
$three_d_response_order_note_result_format = '<ul class="ppcp_3ds_result">
|
||||
<li>%1$s</li>
|
||||
<li>%2$s</li>
|
||||
<li>%3$s</li>
|
||||
</ul>';
|
||||
$three_d_response_order_note_result = sprintf(
|
||||
$three_d_response_order_note_result_format,
|
||||
/* translators: %s is liability shift */
|
||||
sprintf( __( 'Liability Shift: %s', 'woocommerce-paypal-payments' ), esc_html( $result->liability_shift() ) ),
|
||||
/* translators: %s is enrollment status */
|
||||
sprintf( __( 'Enrollment Status: %s', 'woocommerce-paypal-payments' ), esc_html( $result->enrollment_status() ) ),
|
||||
/* translators: %s is authentication status */
|
||||
sprintf( __( 'Authentication Status: %s', 'woocommerce-paypal-payments' ), esc_html( $result->authentication_result() ) )
|
||||
);
|
||||
$three_d_response_order_note = sprintf(
|
||||
$three_d_response_order_note_format,
|
||||
esc_html( $three_d_response_order_note_title ),
|
||||
wp_kses_post( $three_d_response_order_note_result )
|
||||
);
|
||||
|
||||
$wc_order->add_order_note( $three_d_response_order_note );
|
||||
|
||||
$wc_order->update_meta_data( PayPalGateway::THREE_D_AUTH_RESULT_META_KEY, $result->to_array() );
|
||||
$wc_order->save_meta_data();
|
||||
|
||||
/**
|
||||
* Fired when the 3DS information is added to WC order.
|
||||
*/
|
||||
do_action( 'woocommerce_paypal_payments_three_d_secure_added', $wc_order, $order );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the fraud processor response details.
|
||||
*
|
||||
* Adds the order note with the fraud processor response details.
|
||||
* Adds the order meta with the fraud processor response details.
|
||||
*
|
||||
* @param FraudProcessorResponse $fraud The fraud processor response (AVS, CVV ...).
|
||||
* @param Order $order The PayPal order.
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
*/
|
||||
protected function handle_fraud( FraudProcessorResponse $fraud, Order $order, WC_Order $wc_order ): void {
|
||||
$payment_source = $order->payment_source();
|
||||
if ( ! $payment_source || $payment_source->name() !== 'card' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fraud_responses = $fraud->to_array();
|
||||
$card_brand = $payment_source->properties()->brand ?? __( 'N/A', 'woocommerce-paypal-payments' );
|
||||
$card_last_digits = $payment_source->properties()->last_digits ?? __( 'N/A', 'woocommerce-paypal-payments' );
|
||||
|
||||
$avs_response_order_note_title = __( 'Address Verification Result', 'woocommerce-paypal-payments' );
|
||||
/* translators: %1$s is AVS order note title, %2$s is AVS order note result markup */
|
||||
$avs_response_order_note_format = __( '%1$s %2$s', 'woocommerce-paypal-payments' );
|
||||
$avs_response_order_note_result_format = '<ul class="ppcp_avs_result">
|
||||
<li>%1$s</li>
|
||||
<ul class="ppcp_avs_result_inner">
|
||||
<li>%2$s</li>
|
||||
<li>%3$s</li>
|
||||
</ul>
|
||||
<li>%4$s</li>
|
||||
<li>%5$s</li>
|
||||
</ul>';
|
||||
$avs_response_order_note_result = sprintf(
|
||||
$avs_response_order_note_result_format,
|
||||
/* translators: %s is fraud AVS code */
|
||||
sprintf( __( 'AVS: %s', 'woocommerce-paypal-payments' ), esc_html( $fraud_responses['avs_code'] ) ),
|
||||
/* translators: %s is fraud AVS address match */
|
||||
sprintf( __( 'Address Match: %s', 'woocommerce-paypal-payments' ), esc_html( $fraud_responses['address_match'] ) ),
|
||||
/* translators: %s is fraud AVS postal match */
|
||||
sprintf( __( 'Postal Match: %s', 'woocommerce-paypal-payments' ), esc_html( $fraud_responses['postal_match'] ) ),
|
||||
/* translators: %s is card brand */
|
||||
sprintf( __( 'Card Brand: %s', 'woocommerce-paypal-payments' ), esc_html( $card_brand ) ),
|
||||
/* translators: %s card last digits */
|
||||
sprintf( __( 'Card Last Digits: %s', 'woocommerce-paypal-payments' ), esc_html( $card_last_digits ) )
|
||||
);
|
||||
$avs_response_order_note = sprintf(
|
||||
$avs_response_order_note_format,
|
||||
esc_html( $avs_response_order_note_title ),
|
||||
wp_kses_post( $avs_response_order_note_result )
|
||||
);
|
||||
$wc_order->add_order_note( $avs_response_order_note );
|
||||
|
||||
$cvv_response_order_note_format = '<ul class="ppcp_cvv_result"><li>%1$s</li></ul>';
|
||||
$cvv_response_order_note = sprintf(
|
||||
$cvv_response_order_note_format,
|
||||
/* translators: %s is fraud CVV match */
|
||||
sprintf( __( 'CVV2 Match: %s', 'woocommerce-paypal-payments' ), esc_html( $fraud_responses['cvv_match'] ) )
|
||||
);
|
||||
$wc_order->add_order_note( $cvv_response_order_note );
|
||||
|
||||
$meta_details = array_merge(
|
||||
$fraud_responses,
|
||||
array(
|
||||
'card_brand' => $card_brand,
|
||||
'card_last_digits' => $card_last_digits,
|
||||
)
|
||||
);
|
||||
$wc_order->update_meta_data( PayPalGateway::FRAUD_RESULT_META_KEY, $meta_details );
|
||||
$wc_order->save_meta_data();
|
||||
|
||||
/**
|
||||
* Fired when the fraud result information is added to WC order.
|
||||
*/
|
||||
do_action( 'woocommerce_paypal_payments_fraud_result_added', $wc_order, $order );
|
||||
}
|
||||
}
|
|
@ -45,6 +45,18 @@ trait OrderMetaTrait {
|
|||
$wc_order->update_meta_data( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY, $payment_source );
|
||||
}
|
||||
|
||||
$payer = $order->payer();
|
||||
if (
|
||||
$payer
|
||||
&& $payment_source
|
||||
&& in_array( $payment_source, PayPalGateway::PAYMENT_SOURCES_WITH_PAYER_EMAIL, true )
|
||||
) {
|
||||
$payer_email = $payer->email_address();
|
||||
if ( $payer_email ) {
|
||||
$wc_order->update_meta_data( PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email );
|
||||
}
|
||||
}
|
||||
|
||||
$wc_order->save();
|
||||
|
||||
do_action( 'woocommerce_paypal_payments_woocommerce_order_created', $wc_order, $order );
|
||||
|
|
|
@ -112,6 +112,10 @@ trait PaymentsStatusHandlingTrait {
|
|||
'on-hold',
|
||||
__( 'Awaiting payment.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
/**
|
||||
* Fired when PayPal order is authorized.
|
||||
*/
|
||||
do_action( 'woocommerce_paypal_payments_order_authorized', $wc_order, $authorization );
|
||||
break;
|
||||
case AuthorizationStatus::DENIED:
|
||||
$wc_order->update_status(
|
||||
|
|
|
@ -22,6 +22,8 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payments;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\RefundCapture;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\RefundFeesUpdater;
|
||||
|
||||
|
@ -107,6 +109,10 @@ class RefundProcessor {
|
|||
*/
|
||||
public function process( WC_Order $wc_order, float $amount = null, string $reason = '' ) : bool {
|
||||
try {
|
||||
if ( ! in_array( $wc_order->get_payment_method(), array( PayPalGateway::ID, CreditCardGateway::ID, CardButtonGateway::ID ), true ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$order_id = $wc_order->get_meta( PayPalGateway::ORDER_ID_META_KEY );
|
||||
if ( ! $order_id ) {
|
||||
throw new RuntimeException( 'PayPal order ID not found in meta.' );
|
||||
|
|
|
@ -65,7 +65,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
<a href="https://woo.com/document/woocommerce-paypal-payments/#paypal-card-processing-acdc" target="_blank"><img alt="American Express" src="' . esc_url( $module_url ) . 'assets/images/amex.svg"/></a>
|
||||
<a href="https://woo.com/document/woocommerce-paypal-payments/#paypal-card-processing-acdc" target="_blank"><img alt="Discover" src="' . esc_url( $module_url ) . 'assets/images/discover.svg"/></a>
|
||||
<a href="https://woo.com/document/woocommerce-paypal-payments/#alternative-payment-methods" target="_blank"><img alt="iDEAL" src="' . esc_url( $module_url ) . 'assets/images/ideal-dark.svg"/></a>
|
||||
<a href="https://woo.com/document/woocommerce-paypal-payments/#alternative-payment-methods" target="_blank"><img alt="Sofort" src="' . esc_url( $module_url ) . 'assets/images/sofort.svg"/></a>
|
||||
<a href="https://woo.com/document/woocommerce-paypal-payments/#alternative-payment-methods" target="_blank"><img alt="BLIK" src="' . esc_url( $module_url ) . 'assets/images/blik.svg"/></a>
|
||||
</div>
|
||||
<div class="ppcp-onboarding-header-apm-logos">
|
||||
<a href="https://woo.com/document/woocommerce-paypal-payments/#apple-pay" target="_blank"><img alt="Apple Pay" src="' . esc_url( $module_url ) . 'assets/images/button-Apple-Pay.png"/></a>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue