mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 12:25:15 +08:00
Merge branch 'trunk' into PCP-190-override-language-used-to-display-PayPal-buttons
# Conflicts: # modules/ppcp-button/services.php # modules/ppcp-button/src/Assets/SmartButton.php # modules/ppcp-wc-gateway/services.php
This commit is contained in:
commit
e3fbadf419
465 changed files with 41582 additions and 6679 deletions
10
.ddev/addon-metadata/phpmyadmin/manifest.yaml
Normal file
10
.ddev/addon-metadata/phpmyadmin/manifest.yaml
Normal file
|
@ -0,0 +1,10 @@
|
|||
name: phpmyadmin
|
||||
repository: ddev/ddev-phpmyadmin
|
||||
version: v0.3.0
|
||||
install_date: "2023-08-02T12:20:36+02:00"
|
||||
project_files:
|
||||
- docker-compose.phpmyadmin.yaml
|
||||
- docker-compose.phpmyadmin-norouter.yaml
|
||||
- commands/host/phpmyadmin
|
||||
global_files: []
|
||||
removal_actions: []
|
14
.ddev/addon-metadata/playwright/manifest.yaml
Normal file
14
.ddev/addon-metadata/playwright/manifest.yaml
Normal file
|
@ -0,0 +1,14 @@
|
|||
name: playwright
|
||||
repository: julienloizelet/ddev-playwright
|
||||
version: v2.0.1
|
||||
install_date: "2023-07-28T14:52:54+02:00"
|
||||
project_files:
|
||||
- commands/playwright/playwright
|
||||
- commands/playwright/playwright-install
|
||||
- playwright-build/Dockerfile
|
||||
- playwright-build/kasmvnc.yaml
|
||||
- playwright-build/xstartup
|
||||
- playwright-build/entrypoint.sh
|
||||
- docker-compose.playwright.yaml
|
||||
global_files: []
|
||||
removal_actions: []
|
52
.ddev/commands/host/phpmyadmin
Executable file
52
.ddev/commands/host/phpmyadmin
Executable file
|
@ -0,0 +1,52 @@
|
|||
#!/bin/bash
|
||||
|
||||
## #ddev-generated: If you want to edit and own this file, remove this line.
|
||||
## Description: Launch a browser with PhpMyAdmin
|
||||
## Usage: phpmyadmin
|
||||
## Example: "ddev phpmyadmin"
|
||||
|
||||
DDEV_PHPMYADMIN_PORT=8036
|
||||
DDEV_PHPMYADMIN_HTTPS_PORT=8037
|
||||
|
||||
FULLURL=${DDEV_PRIMARY_URL}
|
||||
HTTPS=""
|
||||
if [ ${DDEV_PRIMARY_URL%://*} = "https" ]; then HTTPS=true; fi
|
||||
|
||||
if [[ ! -z "${GITPOD_INSTANCE_ID}" ]] || [[ "${CODESPACES}" == "true" ]]; then
|
||||
FULLURL="${FULLURL/-${DDEV_HOST_WEBSERVER_PORT}/-${DDEV_PHPMYADMIN_PORT}}"
|
||||
else
|
||||
if [ "${HTTPS}" = "" ]; then
|
||||
FULLURL="${FULLURL%:[0-9]*}:${DDEV_PHPMYADMIN_PORT}"
|
||||
else
|
||||
FULLURL="${FULLURL%:[0-9]*}:${DDEV_PHPMYADMIN_HTTPS_PORT}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "${1:-}" ] ; then
|
||||
if [[ ${1::1} != "/" ]] ; then
|
||||
FULLURL="${FULLURL}/";
|
||||
fi
|
||||
|
||||
FULLURL="${FULLURL}${1}";
|
||||
fi
|
||||
|
||||
if [ "${DDEV_DEBUG:-}" = "true" ]; then
|
||||
printf "FULLURL $FULLURL\n" && exit 0
|
||||
fi
|
||||
|
||||
case $OSTYPE in
|
||||
linux-gnu)
|
||||
if [[ ! -z "${GITPOD_INSTANCE_ID}" ]]; then
|
||||
gp preview ${FULLURL}
|
||||
else
|
||||
xdg-open ${FULLURL}
|
||||
fi
|
||||
;;
|
||||
"darwin"*)
|
||||
open ${FULLURL}
|
||||
;;
|
||||
"win*"* | "msys"*)
|
||||
start ${FULLURL}
|
||||
;;
|
||||
esac
|
||||
|
14
.ddev/commands/playwright/playwright
Executable file
14
.ddev/commands/playwright/playwright
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
#ddev-generated
|
||||
# Remove the line above if you don't want this file to be overwritten when you run
|
||||
# ddev get julienloizelet/ddev-playwright
|
||||
#
|
||||
# This file comes from https://github.com/julienloizelet/ddev-playwright
|
||||
#
|
||||
cd /var/www/html || exit 1
|
||||
cd "${PLAYWRIGHT_TEST_DIR}" || exit 1
|
||||
|
||||
export PLAYWRIGHT_BROWSERS_PATH=0
|
||||
PRE="sudo -u pwuser PLAYWRIGHT_BROWSERS_PATH=0 "
|
||||
|
||||
$PRE yarn playwright "$@"
|
17
.ddev/commands/playwright/playwright-install
Executable file
17
.ddev/commands/playwright/playwright-install
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
#ddev-generated
|
||||
# Remove the line above if you don't want this file to be overwritten when you run
|
||||
# ddev get julienloizelet/ddev-playwright
|
||||
#
|
||||
# This file comes from https://github.com/julienloizelet/ddev-playwright
|
||||
#
|
||||
cd /var/www/html || exit 1
|
||||
cd "${PLAYWRIGHT_TEST_DIR}" || exit 1
|
||||
|
||||
export PLAYWRIGHT_BROWSERS_PATH=0
|
||||
PRE="sudo -u pwuser PLAYWRIGHT_BROWSERS_PATH=0 "
|
||||
|
||||
$PRE yarn install
|
||||
$PRE yarn playwright install --with-deps
|
||||
# Conditionally copy an .env file if an example file exists
|
||||
[ -f .env.example ] && [ ! -f .env ] && $PRE cp -n .env.example .env; exit 0
|
38
.ddev/commands/web/wp-cleanup
Executable file
38
.ddev/commands/web/wp-cleanup
Executable file
|
@ -0,0 +1,38 @@
|
|||
#!/bin/bash
|
||||
|
||||
show-help() {
|
||||
echo -e "\nDelete all posts -p [post type]"
|
||||
echo -e "\tExample: ddev wp-cleanup -p shop_order,product"
|
||||
echo -e "\nDelete all logs -l [wp-content path]"
|
||||
echo -e "\tExample: ddev wp-cleanup -l uploads/wc-logs\n"
|
||||
}
|
||||
|
||||
delete-posts() {
|
||||
for post in $(wp post list --post_type=$1 --format=ids --path=.ddev/wordpress); do
|
||||
wp post delete $post --force --path=.ddev/wordpress
|
||||
done
|
||||
}
|
||||
|
||||
delete-logs() {
|
||||
rm .ddev/wordpress/wp-content/$1/*.log
|
||||
}
|
||||
|
||||
declare -i param_counter=0
|
||||
|
||||
while getopts "p:l:h" arg; do
|
||||
case $arg in
|
||||
p)
|
||||
delete-posts $OPTARG
|
||||
param_counter+=1
|
||||
;;
|
||||
l)
|
||||
delete-logs $OPTARG
|
||||
param_counter+=1
|
||||
;;
|
||||
h) show-help ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ $param_counter -eq 0 ]; then
|
||||
show-help
|
||||
fi
|
|
@ -18,7 +18,7 @@ hooks:
|
|||
pre-start:
|
||||
- exec-host: "mkdir -p .ddev/wordpress/wp-content/plugins/${DDEV_PROJECT}"
|
||||
web_environment:
|
||||
- WP_VERSION=5.9.3
|
||||
- WP_VERSION=6.2.2
|
||||
- WP_LOCALE=en_US
|
||||
- WP_TITLE=WooCommerce PayPal Payments
|
||||
- WP_MULTISITE=true
|
||||
|
@ -26,7 +26,7 @@ web_environment:
|
|||
- ADMIN_USER=admin
|
||||
- ADMIN_PASS=admin
|
||||
- ADMIN_EMAIL=admin@example.com
|
||||
- WC_VERSION=6.1.0
|
||||
- WC_VERSION=7.7.2
|
||||
|
||||
# Key features of ddev's config.yaml:
|
||||
|
||||
|
|
4
.ddev/docker-compose.phpmyadmin-norouter.yaml
Normal file
4
.ddev/docker-compose.phpmyadmin-norouter.yaml
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ddev-generated
|
||||
# If omit_containers[ddev-router] then this file will be replaced
|
||||
# with another with a `ports` statement to directly expose port 80 to 8036
|
||||
services: {}
|
27
.ddev/docker-compose.phpmyadmin.yaml
Normal file
27
.ddev/docker-compose.phpmyadmin.yaml
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ddev-generated
|
||||
services:
|
||||
phpmyadmin:
|
||||
container_name: ddev-${DDEV_SITENAME}-phpmyadmin
|
||||
image: phpmyadmin:5
|
||||
working_dir: "/root"
|
||||
restart: "no"
|
||||
labels:
|
||||
com.ddev.site-name: ${DDEV_SITENAME}
|
||||
com.ddev.approot: $DDEV_APPROOT
|
||||
expose:
|
||||
- "80"
|
||||
environment:
|
||||
- PMA_USER=root
|
||||
- PMA_PASSWORD=root
|
||||
- PMA_HOST=db
|
||||
- PMA_PORT=3306
|
||||
- VIRTUAL_HOST=$DDEV_HOSTNAME
|
||||
- UPLOAD_LIMIT=4000M
|
||||
- HTTP_EXPOSE=8036:80
|
||||
- HTTPS_EXPOSE=8037:80
|
||||
healthcheck:
|
||||
interval: 120s
|
||||
timeout: 2s
|
||||
retries: 1
|
||||
depends_on:
|
||||
- db
|
38
.ddev/docker-compose.playwright.yaml
Normal file
38
.ddev/docker-compose.playwright.yaml
Normal file
|
@ -0,0 +1,38 @@
|
|||
#ddev-generated
|
||||
# Remove the line above if you don't want this file to be overwritten when you run
|
||||
# ddev get julienloizelet/ddev-playwright
|
||||
#
|
||||
# This file comes from https://github.com/julienloizelet/ddev-playwright
|
||||
#
|
||||
services:
|
||||
playwright:
|
||||
build:
|
||||
context: playwright-build
|
||||
container_name: ddev-${DDEV_SITENAME}-playwright
|
||||
hostname: ${DDEV_SITENAME}-playwright
|
||||
# These labels ensure this service is discoverable by ddev.
|
||||
labels:
|
||||
com.ddev.site-name: ${DDEV_SITENAME}
|
||||
com.ddev.approot: $DDEV_APPROOT
|
||||
environment:
|
||||
# Modify the PLAYWRIGHT_TEST_DIR folder path to suit your needs
|
||||
- PLAYWRIGHT_TEST_DIR=tests/Playwright
|
||||
- NETWORK_IFACE=eth0
|
||||
- DISPLAY=:1
|
||||
- VIRTUAL_HOST=$DDEV_HOSTNAME
|
||||
- HTTP_EXPOSE=8443:8444,9322:9323
|
||||
- HTTPS_EXPOSE=8444:8444,9323:9323
|
||||
- DDEV_UID=${DDEV_UID}
|
||||
- DDEV_GID=${DDEV_GID}
|
||||
expose:
|
||||
- "8444"
|
||||
- "9323"
|
||||
depends_on:
|
||||
- web
|
||||
volumes:
|
||||
- .:/mnt/ddev_config
|
||||
- ddev-global-cache:/mnt/ddev-global-cache
|
||||
- ../:/var/www/html:rw
|
||||
external_links:
|
||||
- ddev-router:${DDEV_HOSTNAME}
|
||||
working_dir: /var/www/html
|
57
.ddev/playwright-build/Dockerfile
Normal file
57
.ddev/playwright-build/Dockerfile
Normal file
|
@ -0,0 +1,57 @@
|
|||
#ddev-generated
|
||||
# Remove the line above if you don't want this file to be overwritten when you run
|
||||
# ddev get julienloizelet/ddev-playwright
|
||||
#
|
||||
# This file comes from https://github.com/julienloizelet/ddev-playwright
|
||||
#
|
||||
# If on arm64 machine, edit to use mcr.microsoft.com/playwright:focal-arm64
|
||||
FROM mcr.microsoft.com/playwright:focal
|
||||
|
||||
# Debian images by default disable apt caching, so turn it on until we finish
|
||||
# the build.
|
||||
RUN mv /etc/apt/apt.conf.d/docker-clean /etc/apt/docker-clean-disabled
|
||||
|
||||
USER root
|
||||
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update \
|
||||
&& apt-get install -y sudo
|
||||
|
||||
# Give the pwuser user full `sudo` privileges
|
||||
RUN echo "pwuser ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/pwuser \
|
||||
&& chmod 0440 /etc/sudoers.d/pwuser
|
||||
|
||||
# CAROOT for `mkcert` to use, has the CA config
|
||||
ENV CAROOT=/mnt/ddev-global-cache/mkcert
|
||||
|
||||
# Install the correct architecture binary of `mkcert`
|
||||
RUN export TARGETPLATFORM=linux/$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && mkdir -p /usr/local/bin && curl --fail -JL -s -o /usr/local/bin/mkcert "https://dl.filippo.io/mkcert/latest?for=${TARGETPLATFORM}"
|
||||
RUN chmod +x /usr/local/bin/mkcert
|
||||
|
||||
|
||||
# Install a window manager.
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update \
|
||||
&& apt-get install -y icewm xauth
|
||||
|
||||
# Install kasmvnc for remote access.
|
||||
RUN /bin/bash -c 'if [ $(arch) == "aarch64" ]; then KASM_ARCH=arm64; else KASM_ARCH=amd64; fi; wget https://github.com/kasmtech/KasmVNC/releases/download/v1.1.0/kasmvncserver_bullseye_1.1.0_${KASM_ARCH}.deb'
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get install -y ./kasmvncserver*.deb
|
||||
|
||||
# We're done with apt so disable caching again for the final image.
|
||||
RUN mv /etc/apt/docker-clean-disabled /etc/apt/apt.conf.d/docker-clean
|
||||
|
||||
# prepare KasmVNC
|
||||
RUN sudo -u pwuser mkdir /home/pwuser/.vnc
|
||||
COPY kasmvnc.yaml xstartup /home/pwuser/.vnc/
|
||||
RUN chown pwuser:pwuser /home/pwuser/.vnc/*
|
||||
RUN sudo -u pwuser touch /home/pwuser/.vnc/.de-was-selected
|
||||
RUN sudo -u pwuser /bin/bash -c 'echo -e "secret\nsecret\n" | kasmvncpasswd -wo -u pwuser' # We actually disable auth, but KASM complains without it
|
||||
|
||||
|
||||
COPY entrypoint.sh /root/entrypoint.sh
|
||||
ENTRYPOINT "/root/entrypoint.sh"
|
18
.ddev/playwright-build/entrypoint.sh
Executable file
18
.ddev/playwright-build/entrypoint.sh
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
#ddev-generated
|
||||
# Remove the line above if you don't want this file to be overwritten when you run
|
||||
# ddev get julienloizelet/ddev-playwright
|
||||
#
|
||||
# This file comes from https://github.com/julienloizelet/ddev-playwright
|
||||
#
|
||||
|
||||
# Change pwuser IDs to the host IDs supplied by DDEV
|
||||
usermod -u ${DDEV_UID} pwuser
|
||||
groupmod -g ${DDEV_GID} pwuser
|
||||
usermod -a -G ssl-cert pwuser
|
||||
|
||||
# Install DDEV certificate
|
||||
mkcert -install
|
||||
|
||||
# Run CMD from parameters as pwuser
|
||||
sudo -u pwuser vncserver -fg -disableBasicAuth
|
14
.ddev/playwright-build/kasmvnc.yaml
Normal file
14
.ddev/playwright-build/kasmvnc.yaml
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ddev-generated
|
||||
# Remove the line above if you don't want this file to be overwritten when you run
|
||||
# ddev get julienloizelet/ddev-playwright
|
||||
#
|
||||
# This file comes from https://github.com/julienloizelet/ddev-playwright
|
||||
#
|
||||
logging:
|
||||
log_writer_name: all
|
||||
log_dest: syslog
|
||||
level: 100
|
||||
|
||||
network:
|
||||
ssl:
|
||||
require_ssl: false
|
32
.ddev/playwright-build/xstartup
Executable file
32
.ddev/playwright-build/xstartup
Executable file
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh
|
||||
#ddev-generated
|
||||
# Remove the line above if you don't want this file to be overwritten when you run
|
||||
# ddev get julienloizelet/ddev-playwright
|
||||
#
|
||||
# This file comes from https://github.com/julienloizelet/ddev-playwright
|
||||
#
|
||||
|
||||
export DISPLAY=:1
|
||||
|
||||
unset SESSION_MANAGER
|
||||
unset DBUS_SESSION_BUS_ADDRESS
|
||||
OS=`uname -s`
|
||||
if [ $OS = 'Linux' ]; then
|
||||
case "$WINDOWMANAGER" in
|
||||
*gnome*)
|
||||
if [ -e /etc/SuSE-release ]; then
|
||||
PATH=$PATH:/opt/gnome/bin
|
||||
export PATH
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [ -x /etc/X11/xinit/xinitrc ]; then
|
||||
exec /etc/X11/xinit/xinitrc
|
||||
fi
|
||||
if [ -f /etc/X11/xinit/xinitrc ]; then
|
||||
exec sh /etc/X11/xinit/xinitrc
|
||||
fi
|
||||
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
|
||||
xterm -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &
|
||||
icewm-session
|
|
@ -1 +1,38 @@
|
|||
PPCP_E2E_WP_DIR=${ROOT_DIR}/.ddev/wordpress
|
||||
|
||||
BASEURL="https://woocommerce-paypal-payments.ddev.site"
|
||||
AUTHORIZATION="Bearer ABC123"
|
||||
|
||||
CHECKOUT_URL="/checkout"
|
||||
CHECKOUT_PAGE_ID=7
|
||||
CART_URL="/cart"
|
||||
BLOCK_CHECKOUT_URL="/checkout-block"
|
||||
BLOCK_CHECKOUT_PAGE_ID=22
|
||||
BLOCK_CART_URL="/cart-block"
|
||||
|
||||
PRODUCT_URL="/product/prod"
|
||||
PRODUCT_ID=123
|
||||
|
||||
SUBSCRIPTION_URL="/product/sub"
|
||||
|
||||
APM_ID="sofort"
|
||||
|
||||
WP_MERCHANT_USER="admin"
|
||||
WP_MERCHANT_PASSWORD="admin"
|
||||
|
||||
WP_CUSTOMER_USER="customer"
|
||||
WP_CUSTOMER_PASSWORD="password"
|
||||
|
||||
CUSTOMER_EMAIL="customer@example.com"
|
||||
CUSTOMER_PASSWORD="password"
|
||||
CUSTOMER_FIRST_NAME="John"
|
||||
CUSTOMER_LAST_NAME="Doe"
|
||||
CUSTOMER_COUNTRY="DE"
|
||||
CUSTOMER_ADDRESS="street 1"
|
||||
CUSTOMER_POSTCODE="12345"
|
||||
CUSTOMER_CITY="city"
|
||||
CUSTOMER_PHONE="1234567890"
|
||||
|
||||
CREDIT_CARD_NUMBER="1234567890"
|
||||
CREDIT_CARD_EXPIRATION="01/2042"
|
||||
CREDIT_CARD_CVV="123"
|
||||
|
|
18
.github/workflows/e2e.yml
vendored
18
.github/workflows/e2e.yml
vendored
|
@ -7,25 +7,21 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: ['7.2', '7.4', '8.1']
|
||||
wc-versions: ['5.9.5', '7.1.0']
|
||||
exclude:
|
||||
- php-versions: 7.2
|
||||
wc-versions: 7.1.0
|
||||
php-versions: ['7.3', '7.4', '8.1']
|
||||
wc-versions: ['5.9.5', '7.7.2']
|
||||
|
||||
name: PHP ${{ matrix.php-versions }} WC ${{ matrix.wc-versions }}
|
||||
steps:
|
||||
- uses: satackey/action-docker-layer-caching@v0.0.11
|
||||
continue-on-error: true
|
||||
|
||||
- uses: jonaseberle/github-action-setup-ddev@v1
|
||||
- uses: ddev/github-action-setup-ddev@v1
|
||||
with:
|
||||
autostart: false
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Configure DDEV
|
||||
run: ddev config --php-version ${{ matrix.php-versions }} --web-environment-add="WC_VERSION=${{ matrix.wc-versions }}"
|
||||
- name: Configure DDEV PHP
|
||||
run: ddev config --php-version ${{ matrix.php-versions }}
|
||||
- name: Configure DDEV WC
|
||||
run: ddev config --web-environment-add="WC_VERSION=${{ matrix.wc-versions }}"
|
||||
|
||||
- name: Start DDEV
|
||||
run: ddev start
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -11,3 +11,5 @@ modules/ppcp-wc-gateway/assets/css
|
|||
.env
|
||||
.env.e2e
|
||||
auth.json
|
||||
.DS_Store
|
||||
tests/.DS_Store
|
||||
|
|
|
@ -50,6 +50,27 @@ namespace Vendidero\Germanized\Shipments {
|
|||
|
||||
public function add_note( $note, $added_by_user = false ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of items within this shipment.
|
||||
*
|
||||
* @return ShipmentItem[]
|
||||
*/
|
||||
public function get_items() {
|
||||
}
|
||||
}
|
||||
|
||||
class ShipmentItem extends WC_Data {
|
||||
|
||||
/**
|
||||
* Get order ID this meta belongs to.
|
||||
*
|
||||
* @param string $context What the value is for. Valid values are 'view' and 'edit'.
|
||||
* @return int
|
||||
*/
|
||||
public function get_order_item_id( $context = 'view' ) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
if (!defined('PAYPAL_INTEGRATION_DATE')) {
|
||||
define('PAYPAL_INTEGRATION_DATE', '2023-06-02');
|
||||
}
|
||||
if (!defined('EP_PAGES')) {
|
||||
define('EP_PAGES', 4096);
|
||||
}
|
||||
|
@ -8,6 +11,13 @@ if (!defined('MONTH_IN_SECONDS')) {
|
|||
if (!defined('HOUR_IN_SECONDS')) {
|
||||
define('HOUR_IN_SECONDS', 60 * MINUTE_IN_SECONDS);
|
||||
}
|
||||
if (!defined('MINUTE_IN_SECONDS')) {
|
||||
define( 'MINUTE_IN_SECONDS', 60 );
|
||||
}
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
define('ABSPATH', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the next occurrence of a scheduled action.
|
||||
|
@ -25,6 +35,17 @@ if (!defined('HOUR_IN_SECONDS')) {
|
|||
*
|
||||
* @return string|null The scheduled action ID if a scheduled action was found, or null if no matching action found.
|
||||
*/
|
||||
function as_unschedule_action($hook, $args = array(), $group = '')
|
||||
{
|
||||
}
|
||||
function as_unschedule_action($hook, $args = array(), $group = '') {}
|
||||
|
||||
/**
|
||||
* Schedule an action to run one time
|
||||
*
|
||||
* @param int $timestamp When the job will run.
|
||||
* @param string $hook The hook to trigger.
|
||||
* @param array $args Arguments to pass when the hook triggers.
|
||||
* @param string $group The group to assign this job to.
|
||||
* @param bool $unique Whether the action should be unique.
|
||||
*
|
||||
* @return int The action ID.
|
||||
*/
|
||||
function as_schedule_single_action( $timestamp, $hook, $args = array(), $group = '', $unique = false ) {}
|
||||
|
|
381
.psalm/wcblocks.php
Normal file
381
.psalm/wcblocks.php
Normal file
|
@ -0,0 +1,381 @@
|
|||
<?php
|
||||
namespace Automattic\WooCommerce\Blocks\Integrations {
|
||||
/**
|
||||
* Integration.Interface
|
||||
*
|
||||
* Integrations must use this interface when registering themselves with blocks,
|
||||
*/
|
||||
interface IntegrationInterface
|
||||
{
|
||||
/**
|
||||
* The name of the integration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name();
|
||||
|
||||
/**
|
||||
* When called invokes any initialization/setup for the integration.
|
||||
*/
|
||||
public function initialize();
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue in the frontend context.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_script_handles();
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue in the editor context.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_editor_script_handles();
|
||||
|
||||
/**
|
||||
* An array of key, value pairs of data made available to the block on the client side.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_script_data();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Automattic\WooCommerce\Blocks\Payments {
|
||||
use Automattic\WooCommerce\Blocks\Integrations\IntegrationInterface;
|
||||
|
||||
interface PaymentMethodTypeInterface extends IntegrationInterface
|
||||
{
|
||||
/**
|
||||
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active();
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue for this payment method in
|
||||
* the frontend context
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_payment_method_script_handles();
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue for this payment method in
|
||||
* the admin context
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_payment_method_script_handles_for_admin();
|
||||
|
||||
/**
|
||||
* An array of key, value pairs of data made available to payment methods
|
||||
* client side.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_payment_method_data();
|
||||
|
||||
/**
|
||||
* Get array of supported features.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_supported_features();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Automattic\WooCommerce\Blocks\Payments\Integrations
|
||||
{
|
||||
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodTypeInterface;
|
||||
|
||||
/**
|
||||
* AbstractPaymentMethodType class.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
abstract class AbstractPaymentMethodType implements PaymentMethodTypeInterface
|
||||
{
|
||||
/**
|
||||
* Payment method name defined by payment methods extending this class.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = '';
|
||||
|
||||
/**
|
||||
* Settings from the WP options table
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $settings = [];
|
||||
|
||||
/**
|
||||
* Get a setting from the settings array if set.
|
||||
*
|
||||
* @param string $name Setting name.
|
||||
* @param mixed $default Value that is returned if the setting does not exist.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_setting($name, $default = '')
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the payment method.
|
||||
*/
|
||||
public function get_name()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_active()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue for this payment method in
|
||||
* the frontend context
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_payment_method_script_handles()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue for this payment method in
|
||||
* the admin context
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_payment_method_script_handles_for_admin()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of supported features.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_supported_features()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of key, value pairs of data made available to payment methods
|
||||
* client side.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_payment_method_data()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue in the frontend context.
|
||||
*
|
||||
* Alias of get_payment_method_script_handles. Defined by IntegrationInterface.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_script_handles()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue in the admin context.
|
||||
*
|
||||
* Alias of get_payment_method_script_handles_for_admin. Defined by IntegrationInterface.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_editor_script_handles()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of key, value pairs of data made available to the block on the client side.
|
||||
*
|
||||
* Alias of get_payment_method_data. Defined by IntegrationInterface.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_script_data()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Automattic\WooCommerce\Blocks\Integrations {
|
||||
/**
|
||||
* Class used for tracking registered integrations with various Block types.
|
||||
*/
|
||||
class IntegrationRegistry
|
||||
{
|
||||
/**
|
||||
* Integration identifier is used to construct hook names and is given when the integration registry is initialized.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $registry_identifier = '';
|
||||
|
||||
/**
|
||||
* Registered integrations, as `$name => $instance` pairs.
|
||||
*
|
||||
* @var IntegrationInterface[]
|
||||
*/
|
||||
protected $registered_integrations = [];
|
||||
|
||||
/**
|
||||
* Initializes all registered integrations.
|
||||
*
|
||||
* Integration identifier is used to construct hook names and is given when the integration registry is initialized.
|
||||
*
|
||||
* @param string $registry_identifier Identifier for this registry.
|
||||
*/
|
||||
public function initialize($registry_identifier = '')
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an integration.
|
||||
*
|
||||
* @param IntegrationInterface $integration An instance of IntegrationInterface.
|
||||
*
|
||||
* @return boolean True means registered successfully.
|
||||
*/
|
||||
public function register(IntegrationInterface $integration)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an integration is already registered.
|
||||
*
|
||||
* @param string $name Integration name.
|
||||
* @return bool True if the integration is registered, false otherwise.
|
||||
*/
|
||||
public function is_registered($name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-register an integration.
|
||||
*
|
||||
* @param string|IntegrationInterface $name Integration name, or alternatively a IntegrationInterface instance.
|
||||
* @return boolean|IntegrationInterface Returns the unregistered integration instance if unregistered successfully.
|
||||
*/
|
||||
public function unregister($name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a registered Integration by name.
|
||||
*
|
||||
* @param string $name Integration name.
|
||||
* @return IntegrationInterface|null The registered integration, or null if it is not registered.
|
||||
*/
|
||||
public function get_registered($name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all registered integrations.
|
||||
*
|
||||
* @return IntegrationInterface[]
|
||||
*/
|
||||
public function get_all_registered()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all registered integration's script handles for the editor.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_all_registered_editor_script_handles()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all registered integration's script handles.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_all_registered_script_handles()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all registered integration's script data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_all_registered_script_data()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Automattic\WooCommerce\Blocks\Payments {
|
||||
use Automattic\WooCommerce\Blocks\Integrations\IntegrationRegistry;
|
||||
|
||||
/**
|
||||
* Class used for interacting with payment method types.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
final class PaymentMethodRegistry extends IntegrationRegistry
|
||||
{
|
||||
/**
|
||||
* Integration identifier is used to construct hook names and is given when the integration registry is initialized.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $registry_identifier = 'payment_method_type';
|
||||
|
||||
/**
|
||||
* Retrieves all registered payment methods that are also active.
|
||||
*
|
||||
* @return PaymentMethodTypeInterface[]
|
||||
*/
|
||||
public function get_all_active_registered()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all registered payment method script handles, but only for active payment methods.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_all_active_payment_method_script_dependencies()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all registered payment method script data, but only for active payment methods.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_all_registered_script_data()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers and validates payment requirements callbacks.
|
||||
*
|
||||
* @see Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema::register_payment_requirements()
|
||||
*
|
||||
* @param array $args Args to pass to register_payment_requirements.
|
||||
* @returns boolean|\WP_Error True on success, WP_Error on fail.
|
||||
*/
|
||||
function woocommerce_store_api_register_payment_requirements( $args ) {
|
||||
}
|
|
@ -1631,7 +1631,7 @@ function wcs_get_order_items_product_id($item_id)
|
|||
*
|
||||
* When acting on cart items or order items, Subscriptions often needs to use an item's canonical product ID. For
|
||||
* items representing a variation, that means the 'variation_id' value, if the item is not a variation, that means
|
||||
* the 'product_id value. This function helps save keystrokes on the idiom to check if an item is to a variation or not.
|
||||
* the product_id value. This function helps save keystrokes on the idiom to check if an item is to a variation or not.
|
||||
*
|
||||
* @param array or object $item Either a cart item, order/subscription line item, or a product.
|
||||
*/
|
||||
|
@ -2084,3 +2084,39 @@ function wcs_find_matching_line_item($order, $subscription_item, $match_type = '
|
|||
function wcs_order_contains_product($order, $product)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get page ID for a specific WC resource.
|
||||
*
|
||||
* @param string $for Name of the resource.
|
||||
*
|
||||
* @return string Page ID. Empty string if resource not found.
|
||||
*/
|
||||
function wc_get_page_screen_id( $for ) {}
|
||||
|
||||
/**
|
||||
* Subscription Product Variation Class
|
||||
*
|
||||
* The subscription product variation class extends the WC_Product_Variation product class
|
||||
* to create subscription product variations.
|
||||
*
|
||||
* @class WC_Product_Subscription
|
||||
* @package WooCommerce Subscriptions
|
||||
* @category Class
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3
|
||||
*
|
||||
*/
|
||||
class WC_Product_Subscription_Variation extends WC_Product_Variation {}
|
||||
|
||||
/**
|
||||
* Variable Subscription Product Class
|
||||
*
|
||||
* This class extends the WC Variable product class to create variable products with recurring payments.
|
||||
*
|
||||
* @class WC_Product_Variable_Subscription
|
||||
* @package WooCommerce Subscriptions
|
||||
* @category Class
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3
|
||||
*
|
||||
*/
|
||||
class WC_Product_Variable_Subscription extends WC_Product_Variable {}
|
||||
|
|
651
.psalm/wpcli.php
Normal file
651
.psalm/wpcli.php
Normal file
|
@ -0,0 +1,651 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Various utilities for WP-CLI commands.
|
||||
*/
|
||||
class WP_CLI {
|
||||
/**
|
||||
* Set the logger instance.
|
||||
*
|
||||
* @param object $logger Logger instance to set.
|
||||
*/
|
||||
public static function set_logger( $logger ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the logger instance.
|
||||
*
|
||||
* @return object $logger Logger instance.
|
||||
*/
|
||||
public static function get_logger() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Configurator instance
|
||||
*
|
||||
* @return Configurator
|
||||
*/
|
||||
public static function get_configurator() {
|
||||
}
|
||||
|
||||
public static function get_root_command() {
|
||||
}
|
||||
|
||||
public static function get_runner() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FileCache
|
||||
*/
|
||||
public static function get_cache() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the context in which WP-CLI should be run
|
||||
*/
|
||||
public static function set_url( $url ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WpHttpCacheManager
|
||||
*/
|
||||
public static function get_http_cache_manager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Colorize a string for output.
|
||||
*
|
||||
* Yes, you can change the color of command line text too. For instance,
|
||||
* here's how `WP_CLI::success()` colorizes "Success: "
|
||||
*
|
||||
* ```
|
||||
* WP_CLI::colorize( "%GSuccess:%n " )
|
||||
* ```
|
||||
*
|
||||
* Uses `\cli\Colors::colorize()` to transform color tokens to display
|
||||
* settings. Choose from the following tokens (and note 'reset'):
|
||||
*
|
||||
* * %y => ['color' => 'yellow'],
|
||||
* * %g => ['color' => 'green'],
|
||||
* * %b => ['color' => 'blue'],
|
||||
* * %r => ['color' => 'red'],
|
||||
* * %p => ['color' => 'magenta'],
|
||||
* * %m => ['color' => 'magenta'],
|
||||
* * %c => ['color' => 'cyan'],
|
||||
* * %w => ['color' => 'grey'],
|
||||
* * %k => ['color' => 'black'],
|
||||
* * %n => ['color' => 'reset'],
|
||||
* * %Y => ['color' => 'yellow', 'style' => 'bright'],
|
||||
* * %G => ['color' => 'green', 'style' => 'bright'],
|
||||
* * %B => ['color' => 'blue', 'style' => 'bright'],
|
||||
* * %R => ['color' => 'red', 'style' => 'bright'],
|
||||
* * %P => ['color' => 'magenta', 'style' => 'bright'],
|
||||
* * %M => ['color' => 'magenta', 'style' => 'bright'],
|
||||
* * %C => ['color' => 'cyan', 'style' => 'bright'],
|
||||
* * %W => ['color' => 'grey', 'style' => 'bright'],
|
||||
* * %K => ['color' => 'black', 'style' => 'bright'],
|
||||
* * %N => ['color' => 'reset', 'style' => 'bright'],
|
||||
* * %3 => ['background' => 'yellow'],
|
||||
* * %2 => ['background' => 'green'],
|
||||
* * %4 => ['background' => 'blue'],
|
||||
* * %1 => ['background' => 'red'],
|
||||
* * %5 => ['background' => 'magenta'],
|
||||
* * %6 => ['background' => 'cyan'],
|
||||
* * %7 => ['background' => 'grey'],
|
||||
* * %0 => ['background' => 'black'],
|
||||
* * %F => ['style' => 'blink'],
|
||||
* * %U => ['style' => 'underline'],
|
||||
* * %8 => ['style' => 'inverse'],
|
||||
* * %9 => ['style' => 'bright'],
|
||||
* * %_ => ['style' => 'bright']
|
||||
*
|
||||
* @access public
|
||||
* @category Output
|
||||
*
|
||||
* @param string $string String to colorize for output, with color tokens.
|
||||
* @return string Colorized string.
|
||||
*/
|
||||
public static function colorize( $string ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a callback to be executed at a certain point.
|
||||
*
|
||||
* Hooks conceptually are very similar to WordPress actions. WP-CLI hooks
|
||||
* are typically called before WordPress is loaded.
|
||||
*
|
||||
* WP-CLI hooks include:
|
||||
*
|
||||
* * `before_add_command:<command>` - Before the command is added.
|
||||
* * `after_add_command:<command>` - After the command was added.
|
||||
* * `before_invoke:<command>` (1) - Just before a command is invoked.
|
||||
* * `after_invoke:<command>` (1) - Just after a command is invoked.
|
||||
* * `find_command_to_run_pre` - Just before WP-CLI finds the command to run.
|
||||
* * `before_registering_contexts` (1) - Before the contexts are registered.
|
||||
* * `before_wp_load` - Just before the WP load process begins.
|
||||
* * `before_wp_config_load` - After wp-config.php has been located.
|
||||
* * `after_wp_config_load` - After wp-config.php has been loaded into scope.
|
||||
* * `after_wp_load` - Just after the WP load process has completed.
|
||||
* * `before_run_command` (3) - Just before the command is executed.
|
||||
*
|
||||
* The parentheses behind the hook name denote the number of arguments
|
||||
* being passed into the hook. For such hooks, the callback should return
|
||||
* the first argument again, making them work like a WP filter.
|
||||
*
|
||||
* WP-CLI commands can create their own hooks with `WP_CLI::do_hook()`.
|
||||
*
|
||||
* If additional arguments are passed through the `WP_CLI::do_hook()` call,
|
||||
* these will be passed on to the callback provided by `WP_CLI::add_hook()`.
|
||||
*
|
||||
* ```
|
||||
* # `wp network meta` confirms command is executing in multisite context.
|
||||
* WP_CLI::add_command( 'network meta', 'Network_Meta_Command', array(
|
||||
* 'before_invoke' => function ( $name ) {
|
||||
* if ( !is_multisite() ) {
|
||||
* WP_CLI::error( 'This is not a multisite installation.' );
|
||||
* }
|
||||
* }
|
||||
* ) );
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Registration
|
||||
*
|
||||
* @param string $when Identifier for the hook.
|
||||
* @param mixed $callback Callback to execute when hook is called.
|
||||
* @return null
|
||||
*/
|
||||
public static function add_hook( $when, $callback ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute callbacks registered to a given hook.
|
||||
*
|
||||
* See `WP_CLI::add_hook()` for details on WP-CLI's internal hook system.
|
||||
* Commands can provide and call their own hooks.
|
||||
*
|
||||
* @access public
|
||||
* @category Registration
|
||||
*
|
||||
* @param string $when Identifier for the hook.
|
||||
* @param mixed ...$args Optional. Arguments that will be passed onto the
|
||||
* callback provided by `WP_CLI::add_hook()`.
|
||||
* @return null|mixed Returns the first optional argument if optional
|
||||
* arguments were passed, otherwise returns null.
|
||||
*/
|
||||
public static function do_hook( $when, ...$args ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback to a WordPress action or filter.
|
||||
*
|
||||
* `add_action()` without needing access to `add_action()`. If WordPress is
|
||||
* already loaded though, you should use `add_action()` (and `add_filter()`)
|
||||
* instead.
|
||||
*
|
||||
* @access public
|
||||
* @category Registration
|
||||
*
|
||||
* @param string $tag Named WordPress action or filter.
|
||||
* @param mixed $function_to_add Callable to execute when the action or filter is evaluated.
|
||||
* @param integer $priority Priority to add the callback as.
|
||||
* @param integer $accepted_args Number of arguments to pass to callback.
|
||||
* @return true
|
||||
*/
|
||||
public static function add_wp_hook( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a command to WP-CLI.
|
||||
*
|
||||
* WP-CLI supports using any callable class, function, or closure as a
|
||||
* command. `WP_CLI::add_command()` is used for both internal and
|
||||
* third-party command registration.
|
||||
*
|
||||
* Command arguments are parsed from PHPDoc by default, but also can be
|
||||
* supplied as an optional third argument during registration.
|
||||
*
|
||||
* ```
|
||||
* # Register a custom 'foo' command to output a supplied positional param.
|
||||
* #
|
||||
* # $ wp foo bar --append=qux
|
||||
* # Success: bar qux
|
||||
*
|
||||
* /**
|
||||
* * My awesome closure command
|
||||
* *
|
||||
* * <message>
|
||||
* * : An awesome message to display
|
||||
* *
|
||||
* * --append=<message>
|
||||
* * : An awesome message to append to the original message.
|
||||
* *
|
||||
* * @when before_wp_load
|
||||
* *\/
|
||||
* $foo = function( $args, $assoc_args ) {
|
||||
* WP_CLI::success( $args[0] . ' ' . $assoc_args['append'] );
|
||||
* };
|
||||
* WP_CLI::add_command( 'foo', $foo );
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Registration
|
||||
*
|
||||
* @param string $name Name for the command (e.g. "post list" or "site empty").
|
||||
* @param callable $callable Command implementation as a class, function or closure.
|
||||
* @param array $args {
|
||||
* Optional. An associative array with additional registration parameters.
|
||||
*
|
||||
* @type callable $before_invoke Callback to execute before invoking the command.
|
||||
* @type callable $after_invoke Callback to execute after invoking the command.
|
||||
* @type string $shortdesc Short description (80 char or less) for the command.
|
||||
* @type string $longdesc Description of arbitrary length for examples, etc.
|
||||
* @type string $synopsis The synopsis for the command (string or array).
|
||||
* @type string $when Execute callback on a named WP-CLI hook (e.g. before_wp_load).
|
||||
* @type bool $is_deferred Whether the command addition had already been deferred.
|
||||
* }
|
||||
* @return bool True on success, false if deferred, hard error if registration failed.
|
||||
*/
|
||||
public static function add_command( $name, $callable, $args = [] ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of outstanding deferred command additions.
|
||||
*
|
||||
* @return array Array of outstanding command additions.
|
||||
*/
|
||||
public static function get_deferred_additions() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a command addition from the list of outstanding deferred additions.
|
||||
*/
|
||||
public static function remove_deferred_addition( $name ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display informational message without prefix, and ignore `--quiet`.
|
||||
*
|
||||
* Message is written to STDOUT. `WP_CLI::log()` is typically recommended;
|
||||
* `WP_CLI::line()` is included for historical compat.
|
||||
*
|
||||
* @access public
|
||||
* @category Output
|
||||
*
|
||||
* @param string $message Message to display to the end user.
|
||||
* @return null
|
||||
*/
|
||||
public static function line( $message = '' ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display informational message without prefix.
|
||||
*
|
||||
* Message is written to STDOUT, or discarded when `--quiet` flag is supplied.
|
||||
*
|
||||
* ```
|
||||
* # `wp cli update` lets user know of each step in the update process.
|
||||
* WP_CLI::log( sprintf( 'Downloading from %s...', $download_url ) );
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Output
|
||||
*
|
||||
* @param string $message Message to write to STDOUT.
|
||||
*/
|
||||
public static function log( $message ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display success message prefixed with "Success: ".
|
||||
*
|
||||
* Success message is written to STDOUT.
|
||||
*
|
||||
* Typically recommended to inform user of successful script conclusion.
|
||||
*
|
||||
* ```
|
||||
* # wp rewrite flush expects 'rewrite_rules' option to be set after flush.
|
||||
* flush_rewrite_rules( \WP_CLI\Utils\get_flag_value( $assoc_args, 'hard' ) );
|
||||
* if ( ! get_option( 'rewrite_rules' ) ) {
|
||||
* WP_CLI::warning( "Rewrite rules are empty." );
|
||||
* } else {
|
||||
* WP_CLI::success( 'Rewrite rules flushed.' );
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Output
|
||||
*
|
||||
* @param string $message Message to write to STDOUT.
|
||||
* @return null
|
||||
*/
|
||||
public static function success( $message ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display debug message prefixed with "Debug: " when `--debug` is used.
|
||||
*
|
||||
* Debug message is written to STDERR, and includes script execution time.
|
||||
*
|
||||
* Helpful for optionally showing greater detail when needed. Used throughout
|
||||
* WP-CLI bootstrap process for easier debugging and profiling.
|
||||
*
|
||||
* ```
|
||||
* # Called in `WP_CLI\Runner::set_wp_root()`.
|
||||
* private static function set_wp_root( $path ) {
|
||||
* define( 'ABSPATH', Utils\trailingslashit( $path ) );
|
||||
* WP_CLI::debug( 'ABSPATH defined: ' . ABSPATH );
|
||||
* $_SERVER['DOCUMENT_ROOT'] = realpath( $path );
|
||||
* }
|
||||
*
|
||||
* # Debug details only appear when `--debug` is used.
|
||||
* # $ wp --debug
|
||||
* # [...]
|
||||
* # Debug: ABSPATH defined: /srv/www/wordpress-develop.dev/src/ (0.225s)
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Output
|
||||
*
|
||||
* @param string|WP_Error|Exception|Throwable $message Message to write to STDERR.
|
||||
* @param string|bool $group Organize debug message to a specific group.
|
||||
* Use `false` to not group the message.
|
||||
* @return null
|
||||
*/
|
||||
public static function debug( $message, $group = false ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display warning message prefixed with "Warning: ".
|
||||
*
|
||||
* Warning message is written to STDERR.
|
||||
*
|
||||
* Use instead of `WP_CLI::debug()` when script execution should be permitted
|
||||
* to continue.
|
||||
*
|
||||
* ```
|
||||
* # `wp plugin activate` skips activation when plugin is network active.
|
||||
* $status = $this->get_status( $plugin->file );
|
||||
* // Network-active is the highest level of activation status
|
||||
* if ( 'active-network' === $status ) {
|
||||
* WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." );
|
||||
* continue;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Output
|
||||
*
|
||||
* @param string|WP_Error|Exception|Throwable $message Message to write to STDERR.
|
||||
* @return null
|
||||
*/
|
||||
public static function warning( $message ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display error message prefixed with "Error: " and exit script.
|
||||
*
|
||||
* Error message is written to STDERR. Defaults to halting script execution
|
||||
* with return code 1.
|
||||
*
|
||||
* Use `WP_CLI::warning()` instead when script execution should be permitted
|
||||
* to continue.
|
||||
*
|
||||
* ```
|
||||
* # `wp cache flush` considers flush failure to be a fatal error.
|
||||
* if ( false === wp_cache_flush() ) {
|
||||
* WP_CLI::error( 'The object cache could not be flushed.' );
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Output
|
||||
*
|
||||
* @param string|WP_Error|Exception|Throwable $message Message to write to STDERR.
|
||||
* @param boolean|integer $exit True defaults to exit(1).
|
||||
* @return null
|
||||
*/
|
||||
public static function error( $message, $exit = true ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Halt script execution with a specific return code.
|
||||
*
|
||||
* Permits script execution to be overloaded by `WP_CLI::runcommand()`
|
||||
*
|
||||
* @access public
|
||||
* @category Output
|
||||
*
|
||||
* @param integer $return_code
|
||||
* @return never
|
||||
*/
|
||||
public static function halt( $return_code ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a multi-line error message in a red box. Doesn't exit script.
|
||||
*
|
||||
* Error message is written to STDERR.
|
||||
*
|
||||
* @access public
|
||||
* @category Output
|
||||
*
|
||||
* @param array $message_lines Multi-line error message to be displayed.
|
||||
*/
|
||||
public static function error_multi_line( $message_lines ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for confirmation before running a destructive operation.
|
||||
*
|
||||
* If 'y' is provided to the question, the script execution continues. If
|
||||
* 'n' or any other response is provided to the question, script exits.
|
||||
*
|
||||
* ```
|
||||
* # `wp db drop` asks for confirmation before dropping the database.
|
||||
*
|
||||
* WP_CLI::confirm( "Are you sure you want to drop the database?", $assoc_args );
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Input
|
||||
*
|
||||
* @param string $question Question to display before the prompt.
|
||||
* @param array $assoc_args Skips prompt if 'yes' is provided.
|
||||
*/
|
||||
public static function confirm( $question, $assoc_args = [] ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read value from a positional argument or from STDIN.
|
||||
*
|
||||
* @param array $args The list of positional arguments.
|
||||
* @param int $index At which position to check for the value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_value_from_arg_or_stdin( $args, $index ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a value, from various formats.
|
||||
*
|
||||
* @access public
|
||||
* @category Input
|
||||
*
|
||||
* @param mixed $raw_value
|
||||
* @param array $assoc_args
|
||||
*/
|
||||
public static function read_value( $raw_value, $assoc_args = [] ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a value, in various formats
|
||||
*
|
||||
* @param mixed $value Value to display.
|
||||
* @param array $assoc_args Arguments passed to the command, determining format.
|
||||
*/
|
||||
public static function print_value( $value, $assoc_args = [] ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a WP_Error or Exception into a string
|
||||
*
|
||||
* @param string|WP_Error|Exception|Throwable $errors
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function error_to_string( $errors ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch an arbitrary external process that takes over I/O.
|
||||
*
|
||||
* ```
|
||||
* # `wp core download` falls back to the `tar` binary when PharData isn't available
|
||||
* if ( ! class_exists( 'PharData' ) ) {
|
||||
* $cmd = "tar xz --strip-components=1 --directory=%s -f $tarball";
|
||||
* WP_CLI::launch( Utils\esc_cmd( $cmd, $dest ) );
|
||||
* return;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Execution
|
||||
*
|
||||
* @param string $command External process to launch.
|
||||
* @param boolean $exit_on_error Whether to exit if the command returns an elevated return code.
|
||||
* @param boolean $return_detailed Whether to return an exit status (default) or detailed execution results.
|
||||
* @return int|ProcessRun The command exit status, or a ProcessRun object for full details.
|
||||
*/
|
||||
public static function launch( $command, $exit_on_error = true, $return_detailed = false ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a WP-CLI command in a new process reusing the current runtime arguments.
|
||||
*
|
||||
* Use `WP_CLI::runcommand()` instead, which is easier to use and works better.
|
||||
*
|
||||
* Note: While this command does persist a limited set of runtime arguments,
|
||||
* it *does not* persist environment variables. Practically speaking, WP-CLI
|
||||
* packages won't be loaded when using WP_CLI::launch_self() because the
|
||||
* launched process doesn't have access to the current process $HOME.
|
||||
*
|
||||
* @access public
|
||||
* @category Execution
|
||||
*
|
||||
* @param string $command WP-CLI command to call.
|
||||
* @param array $args Positional arguments to include when calling the command.
|
||||
* @param array $assoc_args Associative arguments to include when calling the command.
|
||||
* @param bool $exit_on_error Whether to exit if the command returns an elevated return code.
|
||||
* @param bool $return_detailed Whether to return an exit status (default) or detailed execution results.
|
||||
* @param array $runtime_args Override one or more global args (path,url,user,allow-root)
|
||||
* @return int|ProcessRun The command exit status, or a ProcessRun instance
|
||||
*/
|
||||
public static function launch_self( $command, $args = [], $assoc_args = [], $exit_on_error = true, $return_detailed = false, $runtime_args = [] ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the PHP binary used when executing WP-CLI.
|
||||
*
|
||||
* Environment values permit specific binaries to be indicated.
|
||||
*
|
||||
* Note: moved to Utils, left for BC.
|
||||
*
|
||||
* @access public
|
||||
* @category System
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_php_binary() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that a global configuration parameter does exist.
|
||||
*
|
||||
* @access public
|
||||
* @category Input
|
||||
*
|
||||
* @param string $key Config parameter key to check.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_config( $key ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get values of global configuration parameters.
|
||||
*
|
||||
* Provides access to `--path=<path>`, `--url=<url>`, and other values of
|
||||
* the [global configuration parameters](https://wp-cli.org/config/).
|
||||
*
|
||||
* ```
|
||||
* WP_CLI::log( 'The --url=<url> value is: ' . WP_CLI::get_config( 'url' ) );
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Input
|
||||
*
|
||||
* @param string $key Get value for a specific global configuration parameter.
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get_config( $key = null ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a WP-CLI command.
|
||||
*
|
||||
* Launches a new child process to run a specified WP-CLI command.
|
||||
* Optionally:
|
||||
*
|
||||
* * Run the command in an existing process.
|
||||
* * Prevent halting script execution on error.
|
||||
* * Capture and return STDOUT, or full details about command execution.
|
||||
* * Parse JSON output if the command rendered it.
|
||||
*
|
||||
* ```
|
||||
* $options = array(
|
||||
* 'return' => true, // Return 'STDOUT'; use 'all' for full object.
|
||||
* 'parse' => 'json', // Parse captured STDOUT to JSON array.
|
||||
* 'launch' => false, // Reuse the current process.
|
||||
* 'exit_error' => true, // Halt script execution on error.
|
||||
* );
|
||||
* $plugins = WP_CLI::runcommand( 'plugin list --format=json', $options );
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Execution
|
||||
*
|
||||
* @param string $command WP-CLI command to run, including arguments.
|
||||
* @param array $options Configuration options for command execution.
|
||||
* @return mixed
|
||||
*/
|
||||
public static function runcommand( $command, $options = [] ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a given command within the current process using the same global
|
||||
* parameters.
|
||||
*
|
||||
* Use `WP_CLI::runcommand()` instead, which is easier to use and works better.
|
||||
*
|
||||
* To run a command using a new process with the same global parameters,
|
||||
* use WP_CLI::launch_self(). To run a command using a new process with
|
||||
* different global parameters, use WP_CLI::launch().
|
||||
*
|
||||
* ```
|
||||
* ob_start();
|
||||
* WP_CLI::run_command( array( 'cli', 'cmd-dump' ) );
|
||||
* $ret = ob_get_clean();
|
||||
* ```
|
||||
*
|
||||
* @access public
|
||||
* @category Execution
|
||||
*
|
||||
* @param array $args Positional arguments including command name.
|
||||
* @param array $assoc_args
|
||||
*/
|
||||
public static function run_command( $args, $assoc_args = [] ) {
|
||||
}
|
||||
}
|
|
@ -73,6 +73,8 @@ Enable xdebug via `$ ddev xdebug`, and press `Start Listening for PHP Debug Conn
|
|||
After creating the server in the PHPStorm dialog, you need to set the local project path for the server plugin path.
|
||||
It should look [like this](https://i.imgur.com/ofsF1Mc.png).
|
||||
|
||||
See [tests/playwright](tests/playwright) for e2e (browser-based) tests.
|
||||
|
||||
## Test account setup
|
||||
|
||||
You will need a PayPal sandbox merchant and customer accounts to configure the plugin and make test purchases with it.
|
||||
|
|
121
api/order-functions.php
Normal file
121
api/order-functions.php
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
/**
|
||||
* The API for operations with orders.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Api
|
||||
*
|
||||
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Api;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\PPCP;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\RefundFeesUpdater;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
|
||||
/**
|
||||
* Returns the PayPal order.
|
||||
*
|
||||
* @param string|WC_Order $paypal_id_or_wc_order The ID of PayPal order or a WC order (with the ID in meta).
|
||||
* @throws InvalidArgumentException When the argument cannot be used for retrieving the order.
|
||||
* @throws Exception When the operation fails.
|
||||
*/
|
||||
function ppcp_get_paypal_order( $paypal_id_or_wc_order ): Order {
|
||||
if ( $paypal_id_or_wc_order instanceof WC_Order ) {
|
||||
$paypal_id_or_wc_order = $paypal_id_or_wc_order->get_meta( PayPalGateway::ORDER_ID_META_KEY );
|
||||
if ( ! $paypal_id_or_wc_order ) {
|
||||
throw new InvalidArgumentException( 'PayPal order ID not found in meta.' );
|
||||
}
|
||||
}
|
||||
if ( ! is_string( $paypal_id_or_wc_order ) ) {
|
||||
throw new InvalidArgumentException( 'Invalid PayPal order ID, string expected.' );
|
||||
}
|
||||
|
||||
$order_endpoint = PPCP::container()->get( 'api.endpoint.order' );
|
||||
assert( $order_endpoint instanceof OrderEndpoint );
|
||||
|
||||
return $order_endpoint->order( $paypal_id_or_wc_order );
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures 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_capture_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 captured.' );
|
||||
}
|
||||
$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->capture_authorized_payment( $wc_order ) ) {
|
||||
throw new RuntimeException( 'Capture failed.' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refunds the PayPal order.
|
||||
* Note that you can use wc_refund_payment() to trigger the refund in WC and PayPal.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @param float $amount The refund amount.
|
||||
* @param string $reason The reason for the refund.
|
||||
* @return string The PayPal refund ID.
|
||||
* @throws InvalidArgumentException When the order cannot be refunded.
|
||||
* @throws Exception When the operation fails.
|
||||
*/
|
||||
function ppcp_refund_order( WC_Order $wc_order, float $amount, string $reason = '' ): string {
|
||||
$order = ppcp_get_paypal_order( $wc_order );
|
||||
|
||||
$refund_processor = PPCP::container()->get( 'wcgateway.processor.refunds' );
|
||||
assert( $refund_processor instanceof RefundProcessor );
|
||||
|
||||
return $refund_processor->refund( $order, $wc_order, $amount, $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Voids the authorization.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
* @throws InvalidArgumentException When the order cannot be voided.
|
||||
* @throws Exception When the operation fails.
|
||||
*/
|
||||
function ppcp_void_order( WC_Order $wc_order ): void {
|
||||
$order = ppcp_get_paypal_order( $wc_order );
|
||||
|
||||
$refund_processor = PPCP::container()->get( 'wcgateway.processor.refunds' );
|
||||
assert( $refund_processor instanceof RefundProcessor );
|
||||
|
||||
$refund_processor->void( $order );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the PayPal refund fees totals on an order.
|
||||
*
|
||||
* @param WC_Order $wc_order The WC order.
|
||||
*/
|
||||
function ppcp_update_order_refund_fees( WC_Order $wc_order ): void {
|
||||
$updater = PPCP::container()->get( 'wcgateway.helper.refund-fees-updater' );
|
||||
assert( $updater instanceof RefundFeesUpdater );
|
||||
$updater->update( $wc_order );
|
||||
}
|
|
@ -16,10 +16,18 @@ use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
|||
|
||||
return function (
|
||||
string $root_dir,
|
||||
ContainerInterface ...$additional_containers
|
||||
array $additional_containers = array(),
|
||||
array $additional_modules = array()
|
||||
): ContainerInterface {
|
||||
/**
|
||||
* Skip path check.
|
||||
*
|
||||
* @psalm-suppress UnresolvableInclude
|
||||
*/
|
||||
$modules = ( require "$root_dir/modules.php" )( $root_dir );
|
||||
|
||||
$modules = array_merge( $modules, $additional_modules );
|
||||
|
||||
/**
|
||||
* Use this filter to add custom module or remove some of existing ones.
|
||||
* Modules able to access container, add services and modify existing ones.
|
||||
|
@ -39,6 +47,11 @@ return function (
|
|||
// may want to consider fixing it later (pass proxy as parent to DelegatingContainer)
|
||||
// for now not fixed since we were using this behavior for long time and fixing it now may break things.
|
||||
$container = new DelegatingContainer( $provider );
|
||||
/**
|
||||
* Skip iterable vs array check.
|
||||
*
|
||||
* @psalm-suppress PossiblyInvalidArgument
|
||||
*/
|
||||
$app_container = new CachingContainer(
|
||||
new CompositeContainer(
|
||||
array_merge(
|
||||
|
|
187
changelog.txt
187
changelog.txt
|
@ -1,5 +1,192 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 2.4.0 - 2023-10-31 =
|
||||
* Fix - Mini-Cart Bug cause of wrong DOM-Structure in v2.3.1 #1735
|
||||
* Fix - ACDC disappearing after plugin updates #1751
|
||||
* Fix - Subscription module hooks #1748
|
||||
* Fix - Ensure PayPal Subscriptions API products description is 1-127 characters #1738
|
||||
* Fix - Add validation on the Plan Name field to not accept a blank value #1754
|
||||
* Enhancement - Improve Pay Later messages and add Shop, Home locations #1770
|
||||
* Enhancement - Use api-m PayPal API URLs #1740
|
||||
* Enhancement - Google Pay Settings improvements #1719
|
||||
* Enhancement - Apple Pay transaction improvements #1767
|
||||
* Enhancement - Change default ACDC title #1750
|
||||
* Enhancement - Cart simulation improvements #1753
|
||||
* Enhancement - Billing schedule fields not greyed out when PayPal Subscriptions product is connected #1755
|
||||
* Enhancement - Check validation errors when submitting in block #1528
|
||||
* Enhancement - Improve handling of server error when submitting block #1785
|
||||
* Enhancement - Extend Apple Pay country eligibility #1781
|
||||
* Enhancement - Apple Pay validation notice improvements #1783
|
||||
* Enhancement - Apple Pay payment process issues #1789
|
||||
* Enhancement - Disable the tracking if payment is not captured #1780
|
||||
* Enhancement - Place order button remains - Could not retrieve order #1786
|
||||
* Enhancement - Google Pay for variable product greyed out but clickable #1788
|
||||
* Enhancement - Merchant credential validation & remove PAYEE object #1795
|
||||
|
||||
= 2.3.1 - 2023-09-26 =
|
||||
* Fix - Fatal error when saving product while WooCommerce Subscriptions plugin is not active #1731
|
||||
* Fix - Validate tracking data only for add/update Package Tracking #1729
|
||||
* Fix - Disable Package Tracking for order if transaction ID doesn't exist #1727
|
||||
|
||||
= 2.3.0 - 2023-09-26 =
|
||||
* Fix - Plus sign in PayPal account email address gets converted to space #771
|
||||
* Fix - Payment method dropdown option label on edit order screen for ppcp-gateway option displaying wrong name #1639
|
||||
* Fix - WooCommerce Bookings products don't remain in Cart as a guest when PayPal button active on single product #1645
|
||||
* Fix - Since version > 2.2.0 the PayPal Checkout button on single product pages does not redirect anymore #1664
|
||||
* Fix - PayPal fee and PayPal Payout do not change on order if we do partial refund #1578
|
||||
* Fix - Order does not contain intent error when using ACDC payment token while buyer is not present #1506
|
||||
* Fix - Error when product description linked with a PayPal subscription exceeds 127 characters #1700
|
||||
* Fix - $_POST uses the wrong key to hold the shipping method #1652
|
||||
* Fix - WC Payment Token created multiple times when webhook is received #1663
|
||||
* Fix - Subtotal mismatch line name shows on Account settings page when merchant is disconnected #1702
|
||||
* Fix - Warning prevents payments on Pay for Order page when debugging is enabled #1703
|
||||
* Fix - paypal-overlay-uid_ blocks page after closing PayPal popup on Pay for Order page | Terms checkbox validation fails on Pay for Order page #1704
|
||||
* Enhancement - Add support for HPOS for tracking module #1676
|
||||
* Enhancement - Billing agreements endpoint called too frequently for Reference Transactions check #1646
|
||||
* Enhancement - Do not declare subscription support for PayPal when only ACDC vaulting #1669
|
||||
* Enhancement - Apply Capture On Status Change only when order contains PayPal payment method #1595
|
||||
* Enhancement - Do not use transient expiration longer than one month to support memcached #1448
|
||||
* Enhancement - By disconnecting or disabling the plugin the connection should clear the Onboarding links from cache #1668
|
||||
* Enhancement - Upgrade tracking integration #1562
|
||||
* Enhancement - Include url & image_url in create order call #1649
|
||||
* Enhancement - Add compat layer for Yith tracking #1656
|
||||
* Enhancement - Improve invalid currency backend notice (1926) #1588
|
||||
* Enhancement - Hide ACDC footer frame via CSS to avoid empty space #1613
|
||||
* Enhancement - Compatibility with WooCommerce Product Add-Ons plugin #1586
|
||||
* Enhancement - Remove "no shipment" message after adding tracking #1674
|
||||
* Enhancement - Improve error & success validation messages #1675
|
||||
* Enhancement - Compatibility with third-party "Product Add-Ons" plugins #1601
|
||||
* Enhancement - PayPal logo flashes when switching between tabs #1345
|
||||
* Enhancement - Include url & image_url in create order call #1649
|
||||
* Enhancement - Include item_url & image_url to tracking call #1712
|
||||
* Enhancement - Update strings for tracking metabox #1714
|
||||
* Enhancement - Validate email address API credentials field #1691
|
||||
* Enhancement - Set payment method title for order edit page only if our gateway #1661
|
||||
* Enhancement - Fix missing Pay Later messages in cart + refactoring #1683
|
||||
* Enhancement - Product page PP button keep loading popup - "wc_add_to_cart_params is not defined" error in WooCommerce #1655
|
||||
* Enhancement - Remove PayPal Subscriptions API feature flag #1690
|
||||
* Enhancement - Don't send image_url when it is empty #1678
|
||||
* Enhancement - Subscription support depending on Vaulting setting instead of subscription mode setting #1697
|
||||
* Enhancement - Wrong PayPal subscription id on vaulted subscriptions #1699
|
||||
* Enhancement - Remove payment vaulted checker functionality (2030) #1711
|
||||
* Feature preview - Apple Pay integration #1514
|
||||
* Feature preview - Google Pay integration #1654
|
||||
|
||||
= 2.2.2 - 2023-08-29 =
|
||||
* Fix - High rate of auth voids on vaulted subscriptions for guest users #1529
|
||||
* Enhancement - HPOS compatibility issues #1594
|
||||
* Feature preview - PayPal Subscriptions API fixes and improvements #1600 #1607
|
||||
|
||||
= 2.2.1 - 2023-08-24 =
|
||||
* Fix - One-page checkout causes mini cart not showing the PP button on certain pages #1536
|
||||
* Fix - When onboarding loading the return_url too fast may cause the onboarding to fail #1565
|
||||
* Fix - PayPal button doesn't work for variable products on product page after recent 2.2.0 release #1533
|
||||
* Fix - Send payee_preferred correctly for instant payments #1489
|
||||
* Fix - Auto-disabled ACDC vaulting after updating to 2.1.0 #1490
|
||||
* Fix - PayPal Payments serializing formData of array inputs #1501
|
||||
* Fix - Buttons not working on single product page for WooCommerce Bookings product #1478
|
||||
* Enhancement - PayPal Later message price amount doesn't update dynamically #1585
|
||||
* Enhancement - Improve WC order creation in webhook #1530
|
||||
* Enhancement - Refactor hosted fields for early card detection #1554
|
||||
* Enhancement - Pay Later button and message get hidden when product/cart/checkout value is outside of range #1511
|
||||
* Enhancement - Add link to manual credential docs #1430
|
||||
* Enhancement - Validate Merchant ID field format when saving settings #1509
|
||||
* Enhancement - Include soft descriptor for card's activity #1427
|
||||
* Enhancement - Update Pay Later amount on the cart page and checkout when total changes #1441
|
||||
* Enhancement - Log Subscription Mode configuration in system report #1507
|
||||
* Enhancement - HPOS compatibility issues #1555
|
||||
* Feature preview - PayPal Subscriptions API fixes and improvements #1443
|
||||
|
||||
= 2.2.0 - 2023-07-17 =
|
||||
* Fix - Improve handling of APM payments when buyer did not return to Checkout #1233
|
||||
* Fix - Use order currency instead of shop currency on order-pay page #1363
|
||||
* Fix - Do not show broken card button gateway when no checkout location #1358
|
||||
* Fix - Smart buttons not greyed out/removed on single product when deselecting product variation #1469
|
||||
* Fix - Type error with advanced columns pro #1367
|
||||
* Fix - Undefined array key 0 when checking $retry_errors in process_payment method #1375
|
||||
* Fix - Advanced Card Processing gateway becomes invisible post-plugin update unless admin pages are accessed once #1432
|
||||
* Fix - Incompatibility with WooCommerce One Page Checkout (or similar use cases) in Version 2.1.0 #1473
|
||||
* Fix - Prevent Repetitive Token Migration and Database Overload After 2.1.0 Update #1461
|
||||
* Fix - Onboarding from connection page with CSRF parameter manipulates email and merchant id fields #1502
|
||||
* Fix - Do not complete non-checkout button orders via webhooks #1513
|
||||
* Enhancement - Remove feature flag requirement for express cart/checkout block integration #1483
|
||||
* Enhancement - Add notice when shop currency is unsupported #1433
|
||||
* Enhancement - Improve ACDC error message when empty fields #1360
|
||||
* Enhancement - Do not exclude free items #1362
|
||||
* Enhancement - Trigger WC checkout_error event #1384
|
||||
* Enhancement - Update wording in buttons previews #1408
|
||||
* Enhancement - Filter to conditionally block the PayPal buttons #1485
|
||||
* Enhancement - Display funding source on the admin order page #1450
|
||||
* Enhancement - Update system report plugin status for Vaulting #1471
|
||||
* Enhancement - Revert Elementor Pro Checkout hook compatibility #1482
|
||||
|
||||
= 2.1.0 - 2023-06-13 =
|
||||
* Fix - Performance issue #1182
|
||||
* Fix - Webhooks not registered when onboarding with manual credentials #1223
|
||||
* Fix - Boolean false type sent as empty value when setting cache #1313
|
||||
* Fix - Ajax vulnerabilities #1411
|
||||
* Enhancement - Save and display vaulted payment methods in WC Payment Token API #1059
|
||||
* Enhancement - Cache webhook verification results #1379
|
||||
* Enhancement - Refresh checkout totals after validation if needed #1294
|
||||
* Enhancement - Improve Divi and Elementor Pro compatibility #1254
|
||||
* Enhancement - Add MX and JP to ACDC #1415
|
||||
* Enhancement - Add fraudnet script to SGO filter #1366
|
||||
* Feature preview - Add express cart/checkout block #1346
|
||||
* Feature preview - Integrate PayPal Subscriptions API #1217
|
||||
|
||||
= 2.0.5 - 2023-05-31 =
|
||||
* Fix - Potential invalidation of merchant credentials #1339
|
||||
|
||||
= 2.0.4 - 2023-04-03 =
|
||||
* Fix - Allow Pay Later in mini-cart #1221
|
||||
* Fix - Duplicated auth error when credentials become wrong #1229
|
||||
* Fix - Webhook issues when switching sandbox, and delete all webhooks when unsubscribing #1239
|
||||
* Fix - High volume of traffic from merchant-integrations endpoint #1273
|
||||
* Fix - Add content type json to all fetch ajax endpoints #1275
|
||||
* Enhancement - Remove shortcodes from description #1226
|
||||
* Enhancement - Handle price suffix with price for product button check #1234
|
||||
* Enhancement - Show funding source as payment method #1220
|
||||
* Enhancement - Change "Enabled" to "Available" in status text #1237
|
||||
* Enhancement - Programmatically capturing/voiding authorized payments #590
|
||||
|
||||
= 2.0.3 - 2023-03-14 =
|
||||
* Fix - `DEVICE_DATA_NOT_AVAILABLE` error message when FraudNet is enabled #1177
|
||||
* Fix - Redirect to connection tab after manual credentials input #1201
|
||||
* Fix - Asking for address fields in checkout when not using them #1089
|
||||
* Fix - Validate before free trial #1170
|
||||
* Fix - Validate new user creation #1131
|
||||
* Fix - After Updating to 2.0.2, Site Health reports REST API error #1195
|
||||
* Fix - Do not send buyer-country for previews in live mode to avoid error #1186
|
||||
* Fix - PPEC compatibility layer does not take over subscriptions #1193
|
||||
* Fix - Checkout conflict with "All products for subscriptions" plugin #629
|
||||
* Fix - Pay Later on order pay page #1214
|
||||
* Fix - High volume of traffic from merchant-integrations endpoint #1241
|
||||
* Enhancement - Save checkout form before free trial redirect #1135
|
||||
* Enhancement - Add filter for controlling the ditching of items/breakdown #1146
|
||||
* Enhancement - Add patch order data filter #1147
|
||||
* Enhancement - Add filter for disabling fees on wc order admin pages #1153
|
||||
* Enhancement - Use wp_loaded for fraudnet loading to avoid warnings #1172
|
||||
* Enhancement - reCaptcha for WooCommerce support #1093
|
||||
* Enhancement - Make it possible to hide missing funding resource Trustly #1155
|
||||
* Enhancement - Add white color option #1167
|
||||
* Enhancement - Checkout validation for other fields #861
|
||||
* Enhancement - Mention PUI only for German shops and add line breaks #1169
|
||||
* Enhancement - Add filter to fallback tracking_data['carrier'] #1188
|
||||
* Enhancement - Error notices in checkout do not update / or are shown twice #1168
|
||||
* Enhancement - capture authorized payment by changing order status (or programmatically) #587
|
||||
|
||||
= 2.0.2 - 2023-01-31 =
|
||||
* Fix - Do not call PayPal get order by ID if it does not exist #1029
|
||||
* Fix - Type check error conflict with German Market #1056
|
||||
* Fix - Backend Storage for the PayPalRequestIdRepository does not scale #983
|
||||
* Fix - Ensure WC()->payment_gateways is not null #1128
|
||||
* Enhancement - Remove plugin data after uninstalling #1075
|
||||
* Enhancement - Add FraudNet to all payments #1040
|
||||
* Enhancement - Update "Standard Payments" tab settings #1065
|
||||
* Enhancement - Update PHP 7.2 requirement in all relevant files #1084
|
||||
* Enhancement - When PUI is enabled FraudNet should be also enabled #1129
|
||||
* Enhancement - Add PayPal-Request-Id if payment source exist #1132
|
||||
|
||||
= 2.0.1 - 2022-12-13 =
|
||||
* Fix - Error while syncing tracking data to PayPal -> Sync GZD Tracking #1020
|
||||
* Fix - Fix product price retrieval for variable product buttons #1000
|
||||
|
|
|
@ -29,8 +29,12 @@
|
|||
"autoload": {
|
||||
"psr-4": {
|
||||
"WooCommerce\\PayPalCommerce\\": "src",
|
||||
"WooCommerce\\PayPalCommerce\\Common\\": "lib/common/",
|
||||
"WooCommerce\\PayPalCommerce\\Vendor\\": "lib/packages/"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"api/order-functions.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
|
|
198
composer.lock
generated
198
composer.lock
generated
|
@ -521,16 +521,16 @@
|
|||
},
|
||||
{
|
||||
"name": "wikimedia/composer-merge-plugin",
|
||||
"version": "v2.0.1",
|
||||
"version": "v2.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/wikimedia/composer-merge-plugin.git",
|
||||
"reference": "8ca2ed8ab97c8ebce6b39d9943e9909bb4f18912"
|
||||
"reference": "a03d426c8e9fb2c9c569d9deeb31a083292788bc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/wikimedia/composer-merge-plugin/zipball/8ca2ed8ab97c8ebce6b39d9943e9909bb4f18912",
|
||||
"reference": "8ca2ed8ab97c8ebce6b39d9943e9909bb4f18912",
|
||||
"url": "https://api.github.com/repos/wikimedia/composer-merge-plugin/zipball/a03d426c8e9fb2c9c569d9deeb31a083292788bc",
|
||||
"reference": "a03d426c8e9fb2c9c569d9deeb31a083292788bc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -539,9 +539,12 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"composer/composer": "^1.1||^2.0",
|
||||
"php-parallel-lint/php-parallel-lint": "~1.1.0",
|
||||
"ext-json": "*",
|
||||
"mediawiki/mediawiki-phan-config": "0.11.1",
|
||||
"php-parallel-lint/php-parallel-lint": "~1.3.1",
|
||||
"phpspec/prophecy": "~1.15.0",
|
||||
"phpunit/phpunit": "^8.5||^9.0",
|
||||
"squizlabs/php_codesniffer": "~3.5.4"
|
||||
"squizlabs/php_codesniffer": "~3.7.1"
|
||||
},
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
|
@ -568,9 +571,9 @@
|
|||
"description": "Composer plugin to merge multiple composer.json files",
|
||||
"support": {
|
||||
"issues": "https://github.com/wikimedia/composer-merge-plugin/issues",
|
||||
"source": "https://github.com/wikimedia/composer-merge-plugin/tree/v2.0.1"
|
||||
"source": "https://github.com/wikimedia/composer-merge-plugin/tree/v2.1.0"
|
||||
},
|
||||
"time": "2021-02-24T05:28:06+00:00"
|
||||
"time": "2023-04-15T19:07:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "wp-oop/wordpress-interface",
|
||||
|
@ -794,16 +797,16 @@
|
|||
},
|
||||
{
|
||||
"name": "antecedent/patchwork",
|
||||
"version": "2.1.21",
|
||||
"version": "2.1.25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/antecedent/patchwork.git",
|
||||
"reference": "25c1fa0cd9a6e6d0d13863d8df8f050b6733f16d"
|
||||
"reference": "17314e042d45e0dacb0a494c2d1ef50e7621136a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/antecedent/patchwork/zipball/25c1fa0cd9a6e6d0d13863d8df8f050b6733f16d",
|
||||
"reference": "25c1fa0cd9a6e6d0d13863d8df8f050b6733f16d",
|
||||
"url": "https://api.github.com/repos/antecedent/patchwork/zipball/17314e042d45e0dacb0a494c2d1ef50e7621136a",
|
||||
"reference": "17314e042d45e0dacb0a494c2d1ef50e7621136a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -836,9 +839,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/antecedent/patchwork/issues",
|
||||
"source": "https://github.com/antecedent/patchwork/tree/2.1.21"
|
||||
"source": "https://github.com/antecedent/patchwork/tree/2.1.25"
|
||||
},
|
||||
"time": "2022-02-07T07:28:34+00:00"
|
||||
"time": "2023-02-19T12:51:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brain/monkey",
|
||||
|
@ -1430,30 +1433,30 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.4.1",
|
||||
"version": "1.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/instantiator.git",
|
||||
"reference": "10dcfce151b967d20fde1b34ae6640712c3891bc"
|
||||
"reference": "0a0fa9780f5d4e507415a065172d26a98d02047b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc",
|
||||
"reference": "10dcfce151b967d20fde1b34ae6640712c3891bc",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b",
|
||||
"reference": "0a0fa9780f5d4e507415a065172d26a98d02047b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^9",
|
||||
"doctrine/coding-standard": "^9 || ^11",
|
||||
"ext-pdo": "*",
|
||||
"ext-phar": "*",
|
||||
"phpbench/phpbench": "^0.16 || ^1",
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"phpstan/phpstan-phpunit": "^1",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"vimeo/psalm": "^4.22"
|
||||
"vimeo/psalm": "^4.30 || ^5.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -1480,7 +1483,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/instantiator/issues",
|
||||
"source": "https://github.com/doctrine/instantiator/tree/1.4.1"
|
||||
"source": "https://github.com/doctrine/instantiator/tree/1.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1496,7 +1499,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-03-03T08:28:38+00:00"
|
||||
"time": "2022-12-30T00:15:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "felixfbecker/advanced-json-rpc",
|
||||
|
@ -1601,24 +1604,24 @@
|
|||
},
|
||||
{
|
||||
"name": "graham-campbell/result-type",
|
||||
"version": "v1.1.0",
|
||||
"version": "v1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/GrahamCampbell/Result-Type.git",
|
||||
"reference": "a878d45c1914464426dc94da61c9e1d36ae262a8"
|
||||
"reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/a878d45c1914464426dc94da61c9e1d36ae262a8",
|
||||
"reference": "a878d45c1914464426dc94da61c9e1d36ae262a8",
|
||||
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831",
|
||||
"reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"phpoption/phpoption": "^1.9"
|
||||
"phpoption/phpoption": "^1.9.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5.28 || ^9.5.21"
|
||||
"phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -1647,7 +1650,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/GrahamCampbell/Result-Type/issues",
|
||||
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.0"
|
||||
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1659,7 +1662,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-07-30T15:56:11+00:00"
|
||||
"time": "2023-02-25T20:23:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hamcrest/hamcrest-php",
|
||||
|
@ -1783,16 +1786,16 @@
|
|||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.11.0",
|
||||
"version": "1.11.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
|
||||
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
|
||||
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1830,7 +1833,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.0"
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1838,20 +1841,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-03-03T13:19:32+00:00"
|
||||
"time": "2023-03-08T13:26:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "netresearch/jsonmapper",
|
||||
"version": "v4.1.0",
|
||||
"version": "v4.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cweiske/jsonmapper.git",
|
||||
"reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f"
|
||||
"reference": "f60565f8c0566a31acf06884cdaa591867ecc956"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
|
||||
"reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956",
|
||||
"reference": "f60565f8c0566a31acf06884cdaa591867ecc956",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1887,22 +1890,22 @@
|
|||
"support": {
|
||||
"email": "cweiske@cweiske.de",
|
||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0"
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0"
|
||||
},
|
||||
"time": "2022-12-08T20:46:14+00:00"
|
||||
"time": "2023-04-09T17:37:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.15.2",
|
||||
"version": "v4.16.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc"
|
||||
"reference": "19526a33fb561ef417e822e85f08a00db4059c17"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
|
||||
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17",
|
||||
"reference": "19526a33fb561ef417e822e85f08a00db4059c17",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1943,9 +1946,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0"
|
||||
},
|
||||
"time": "2022-11-12T15:38:23+00:00"
|
||||
"time": "2023-06-25T14:52:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "openlss/lib-array2xml",
|
||||
|
@ -2157,27 +2160,25 @@
|
|||
},
|
||||
{
|
||||
"name": "php-stubs/wordpress-stubs",
|
||||
"version": "v5.9.5",
|
||||
"version": "v5.9.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-stubs/wordpress-stubs.git",
|
||||
"reference": "13ecf204a7e6d215a7c0d23e2aa27940fe617717"
|
||||
"reference": "6a18d938d0aef39d091505a4a35b025fb6c10098"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/13ecf204a7e6d215a7c0d23e2aa27940fe617717",
|
||||
"reference": "13ecf204a7e6d215a7c0d23e2aa27940fe617717",
|
||||
"url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/6a18d938d0aef39d091505a4a35b025fb6c10098",
|
||||
"reference": "6a18d938d0aef39d091505a4a35b025fb6c10098",
|
||||
"shasum": ""
|
||||
},
|
||||
"replace": {
|
||||
"giacocorsiglia/wordpress-stubs": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "< 4.12.0",
|
||||
"php": "~7.3 || ~8.0",
|
||||
"php-stubs/generator": "^0.8.1",
|
||||
"php-stubs/generator": "^0.8.3",
|
||||
"phpdocumentor/reflection-docblock": "^5.3",
|
||||
"phpstan/phpstan": "^1.2"
|
||||
"phpstan/phpstan": "^1.10.12",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"suggest": {
|
||||
"paragonie/sodium_compat": "Pure PHP implementation of libsodium",
|
||||
|
@ -2198,9 +2199,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-stubs/wordpress-stubs/issues",
|
||||
"source": "https://github.com/php-stubs/wordpress-stubs/tree/v5.9.5"
|
||||
"source": "https://github.com/php-stubs/wordpress-stubs/tree/v5.9.6"
|
||||
},
|
||||
"time": "2022-11-09T05:32:14+00:00"
|
||||
"time": "2023-05-18T04:34:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpcompatibility/php-compatibility",
|
||||
|
@ -2538,24 +2539,24 @@
|
|||
},
|
||||
{
|
||||
"name": "phpoption/phpoption",
|
||||
"version": "1.9.0",
|
||||
"version": "1.9.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/schmittjoh/php-option.git",
|
||||
"reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab"
|
||||
"reference": "dd3a383e599f49777d8b628dadbb90cae435b87e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dc5ff11e274a90cc1c743f66c9ad700ce50db9ab",
|
||||
"reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab",
|
||||
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e",
|
||||
"reference": "dd3a383e599f49777d8b628dadbb90cae435b87e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8",
|
||||
"phpunit/phpunit": "^8.5.28 || ^9.5.21"
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -2597,7 +2598,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/schmittjoh/php-option/issues",
|
||||
"source": "https://github.com/schmittjoh/php-option/tree/1.9.0"
|
||||
"source": "https://github.com/schmittjoh/php-option/tree/1.9.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2609,7 +2610,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-07-30T15:51:26+00:00"
|
||||
"time": "2023-02-25T19:38:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
@ -2910,16 +2911,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "8.5.31",
|
||||
"version": "8.5.33",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "33c126b09a42de5c99e5e8032b54e8221264a74e"
|
||||
"reference": "7d1ff0e8c6b35db78ff13e3e05517d7cbf7aa32e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/33c126b09a42de5c99e5e8032b54e8221264a74e",
|
||||
"reference": "33c126b09a42de5c99e5e8032b54e8221264a74e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7d1ff0e8c6b35db78ff13e3e05517d7cbf7aa32e",
|
||||
"reference": "7d1ff0e8c6b35db78ff13e3e05517d7cbf7aa32e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2987,7 +2988,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.31"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.33"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3003,7 +3004,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-10-28T05:57:37+00:00"
|
||||
"time": "2023-02-27T13:04:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
|
@ -3136,16 +3137,16 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "3.0.3",
|
||||
"version": "3.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211"
|
||||
"reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211",
|
||||
"reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/6296a0c086dd0117c1b78b059374d7fcbe7545ae",
|
||||
"reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3190,7 +3191,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/3.0.3"
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/3.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3198,7 +3199,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-30T07:59:04+00:00"
|
||||
"time": "2023-05-07T05:30:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
|
@ -3736,16 +3737,16 @@
|
|||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.7.1",
|
||||
"version": "3.7.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
||||
"reference": "1359e176e9307e906dc3d890bcc9603ff6d90619"
|
||||
"reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619",
|
||||
"reference": "1359e176e9307e906dc3d890bcc9603ff6d90619",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879",
|
||||
"reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3781,27 +3782,28 @@
|
|||
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
|
||||
"keywords": [
|
||||
"phpcs",
|
||||
"standards"
|
||||
"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"
|
||||
},
|
||||
"time": "2022-06-18T07:21:10+00:00"
|
||||
"time": "2023-02-22T23:07:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.4.16",
|
||||
"version": "v5.4.26",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "8e9b9c8dfb33af6057c94e1b44846bee700dc5ef"
|
||||
"reference": "b504a3d266ad2bb632f196c0936ef2af5ff6e273"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/8e9b9c8dfb33af6057c94e1b44846bee700dc5ef",
|
||||
"reference": "8e9b9c8dfb33af6057c94e1b44846bee700dc5ef",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/b504a3d266ad2bb632f196c0936ef2af5ff6e273",
|
||||
"reference": "b504a3d266ad2bb632f196c0936ef2af5ff6e273",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3866,12 +3868,12 @@
|
|||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"cli",
|
||||
"command line",
|
||||
"command-line",
|
||||
"console",
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v5.4.16"
|
||||
"source": "https://github.com/symfony/console/tree/v5.4.26"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3887,7 +3889,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-25T14:09:27+00:00"
|
||||
"time": "2023-07-19T20:11:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
|
@ -4450,16 +4452,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v5.4.15",
|
||||
"version": "v5.4.26",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed"
|
||||
"reference": "1181fe9270e373537475e826873b5867b863883c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/571334ce9f687e3e6af72db4d3b2a9431e4fd9ed",
|
||||
"reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/1181fe9270e373537475e826873b5867b863883c",
|
||||
"reference": "1181fe9270e373537475e826873b5867b863883c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4516,7 +4518,7 @@
|
|||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v5.4.15"
|
||||
"source": "https://github.com/symfony/string/tree/v5.4.26"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4532,7 +4534,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-10-05T15:16:54+00:00"
|
||||
"time": "2023-06-28T12:46:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
## packages
|
||||
The packages that are likely to cause conflicts with other plugins (by loading multiple incompatible versions).
|
||||
Their namespaces are isolated by [Mozart](https://github.com/coenjacobs/mozart).
|
||||
|
||||
Currently, the packages are simply added in the repo to avoid making the build process more complex (Mozart has different PHP requirements).
|
||||
We need to isolate only PSR-11 containers and Dhii modularity packages, which are not supposed to change often.
|
||||
|
||||
## common
|
||||
This folder contains reusable classes or components that do not fit into any specific module.
|
||||
They are designed to be versatile and can be used by any module within the plugin.
|
||||
|
|
68
lib/common/Pattern/SingletonDecorator.php
Normal file
68
lib/common/Pattern/SingletonDecorator.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
/**
|
||||
* The Singleton Trait can be used to wrap an execution block, so it behaves like a Singleton.
|
||||
* It executes the callable once, on subsequent calls returns the same result.
|
||||
*/
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Common\Pattern;
|
||||
|
||||
/**
|
||||
* Class SingletonDecorator.
|
||||
*/
|
||||
class SingletonDecorator {
|
||||
|
||||
/**
|
||||
* The callable with the executing code
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
private $callable;
|
||||
|
||||
/**
|
||||
* The execution result
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
private $result;
|
||||
|
||||
/**
|
||||
* Indicates if the callable is resolved
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $executed = false;
|
||||
|
||||
/**
|
||||
* SingletonDecorator constructor.
|
||||
*
|
||||
* @param callable $callable
|
||||
*/
|
||||
public function __construct( callable $callable ) {
|
||||
$this->callable = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* The make constructor.
|
||||
*
|
||||
* @param callable $callable
|
||||
* @return self
|
||||
*/
|
||||
public static function make( callable $callable ): self {
|
||||
return new static( $callable );
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes a callable once and returns the same result on subsequent invokes.
|
||||
*
|
||||
* @param mixed ...$args Arguments to be passed to the callable.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __invoke( ...$args ) {
|
||||
if ( ! $this->executed ) {
|
||||
$this->result = call_user_func_array( $this->callable, $args );
|
||||
$this->executed = true;
|
||||
}
|
||||
|
||||
return $this->result;
|
||||
}
|
||||
}
|
41
lib/common/Pattern/SingletonTrait.php
Normal file
41
lib/common/Pattern/SingletonTrait.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/**
|
||||
* The Singleton Trait can be used to add singleton behaviour to a class.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Common\Pattern
|
||||
*/
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Common\Pattern;
|
||||
|
||||
/**
|
||||
* Class SingletonTrait.
|
||||
*/
|
||||
trait SingletonTrait {
|
||||
/**
|
||||
* The single instance of the class.
|
||||
*
|
||||
* @var self
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* Static method to get the instance of the Singleton class
|
||||
*
|
||||
* @return self|null
|
||||
*/
|
||||
public static function get_instance(): ?self {
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method to get the instance of the Singleton class
|
||||
*
|
||||
* @param self $instance
|
||||
* @return self
|
||||
*/
|
||||
protected static function set_instance( self $instance ): self {
|
||||
self::$instance = $instance;
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
}
|
24
modules.php
24
modules.php
|
@ -26,7 +26,31 @@ return function ( string $root_dir ): iterable {
|
|||
( require "$modules_dir/ppcp-vaulting/module.php" )(),
|
||||
( require "$modules_dir/ppcp-order-tracking/module.php" )(),
|
||||
( require "$modules_dir/ppcp-uninstall/module.php" )(),
|
||||
( require "$modules_dir/ppcp-blocks/module.php" )(),
|
||||
);
|
||||
if ( apply_filters(
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
'woocommerce.feature-flags.woocommerce_paypal_payments.applepay_enabled',
|
||||
getenv( 'PCP_APPLEPAY_ENABLED' ) !== '0'
|
||||
) ) {
|
||||
$modules[] = ( require "$modules_dir/ppcp-applepay/module.php" )();
|
||||
}
|
||||
|
||||
if ( apply_filters(
|
||||
//phpcs:disable WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
'woocommerce.feature-flags.woocommerce_paypal_payments.googlepay_enabled',
|
||||
getenv( 'PCP_GOOGLEPAY_ENABLED' ) !== '0'
|
||||
) ) {
|
||||
$modules[] = ( require "$modules_dir/ppcp-googlepay/module.php" )();
|
||||
}
|
||||
|
||||
if ( apply_filters(
|
||||
//phpcs:disable WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
'woocommerce.deprecated_flags.woocommerce_paypal_payments.saved_payment_checker_enabled',
|
||||
getenv( 'PCP_SAVED_PAYMENT_CHECKER_ENABLED' ) === '1'
|
||||
) ) {
|
||||
$modules[] = ( require "$modules_dir/ppcp-saved-payment-checker/module.php" )();
|
||||
}
|
||||
|
||||
return $modules;
|
||||
};
|
||||
|
|
|
@ -35,17 +35,26 @@ class Message {
|
|||
*/
|
||||
private $dismissable;
|
||||
|
||||
/**
|
||||
* The wrapper selector that will contain the notice.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $wrapper;
|
||||
|
||||
/**
|
||||
* Message constructor.
|
||||
*
|
||||
* @param string $message The message text.
|
||||
* @param string $type The message type.
|
||||
* @param bool $dismissable Whether the message is dismissable.
|
||||
* @param string $wrapper The wrapper selector that will contain the notice.
|
||||
*/
|
||||
public function __construct( string $message, string $type, bool $dismissable = true ) {
|
||||
public function __construct( string $message, string $type, bool $dismissable = true, string $wrapper = '' ) {
|
||||
$this->type = $type;
|
||||
$this->message = $message;
|
||||
$this->dismissable = $dismissable;
|
||||
$this->wrapper = $wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,4 +83,13 @@ class Message {
|
|||
public function is_dismissable(): bool {
|
||||
return $this->dismissable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapper selector that will contain the notice.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function wrapper(): string {
|
||||
return $this->wrapper;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,9 +41,10 @@ class Renderer implements RendererInterface {
|
|||
$messages = $this->repository->current_message();
|
||||
foreach ( $messages as $message ) {
|
||||
printf(
|
||||
'<div class="notice notice-%s %s"><p>%s</p></div>',
|
||||
'<div class="notice notice-%s %s" %s><p>%s</p></div>',
|
||||
$message->type(),
|
||||
( $message->is_dismissable() ) ? 'is-dismissible' : '',
|
||||
( $message->wrapper() ? sprintf( 'data-ppcp-wrapper="%s"', esc_attr( $message->wrapper() ) ) : '' ),
|
||||
wp_kses_post( $message->message() )
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry;
|
||||
use WooCommerce\PayPalCommerce\Common\Pattern\SingletonDecorator;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingSubscriptions;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\CatalogProducts;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingPlans;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerPayableBreakdown;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\BillingCycleFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentPreferencesFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\RefundFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PlanFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ProductFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\RefundPayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\SellerPayableBreakdownFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingOptionFactory;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\PayPalBearer;
|
||||
|
@ -49,12 +64,13 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderTransient;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\PurchaseUnitSanitizer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\OrderRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PartnerReferralsData;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayeeRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
return array(
|
||||
|
@ -105,7 +121,8 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' ),
|
||||
$container->get( 'api.factory.sellerstatus' ),
|
||||
$container->get( 'api.partner_merchant_id' ),
|
||||
$container->get( 'api.merchant_id' )
|
||||
$container->get( 'api.merchant_id' ),
|
||||
$container->get( 'api.helper.failure-registry' )
|
||||
);
|
||||
},
|
||||
'api.factory.sellerstatus' => static function ( ContainerInterface $container ) : SellerStatusFactory {
|
||||
|
@ -118,8 +135,7 @@ return array(
|
|||
$container->get( 'api.factory.payment-token' ),
|
||||
$container->get( 'api.factory.payment-token-action-links' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' ),
|
||||
$container->get( 'api.repository.customer' ),
|
||||
$container->get( 'api.repository.paypal-request-id' )
|
||||
$container->get( 'api.repository.customer' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.webhook' => static function ( ContainerInterface $container ) : WebhookEndpoint {
|
||||
|
@ -179,15 +195,15 @@ return array(
|
|||
$patch_collection_factory = $container->get( 'api.factory.patch-collection-factory' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings $settings
|
||||
*/
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
assert( $session_handler instanceof SessionHandler );
|
||||
$bn_code = $session_handler->bn_code();
|
||||
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
|
||||
$intent = $settings->has( 'intent' ) && strtoupper( (string) $settings->get( 'intent' ) ) === 'AUTHORIZE' ? 'AUTHORIZE' : 'CAPTURE';
|
||||
$application_context_repository = $container->get( 'api.repository.application-context' );
|
||||
$paypal_request_id = $container->get( 'api.repository.paypal-request-id' );
|
||||
$subscription_helper = $container->get( 'subscription.helper' );
|
||||
return new OrderEndpoint(
|
||||
$container->get( 'api.host' ),
|
||||
|
@ -197,10 +213,10 @@ return array(
|
|||
$intent,
|
||||
$logger,
|
||||
$application_context_repository,
|
||||
$paypal_request_id,
|
||||
$subscription_helper,
|
||||
$container->get( 'wcgateway.is-fraudnet-enabled' ),
|
||||
$container->get( 'wcgateway.fraudnet' )
|
||||
$container->get( 'wcgateway.fraudnet' ),
|
||||
$bn_code
|
||||
);
|
||||
},
|
||||
'api.endpoint.billing-agreements' => static function ( ContainerInterface $container ): BillingAgreementsEndpoint {
|
||||
|
@ -210,8 +226,29 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.repository.paypal-request-id' => static function( ContainerInterface $container ) : PayPalRequestIdRepository {
|
||||
return new PayPalRequestIdRepository();
|
||||
'api.endpoint.catalog-products' => static function ( ContainerInterface $container ): CatalogProducts {
|
||||
return new CatalogProducts(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'api.factory.product' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.billing-plans' => static function( ContainerInterface $container ): BillingPlans {
|
||||
return new BillingPlans(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'api.factory.billing-cycle' ),
|
||||
$container->get( 'api.factory.plan' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.billing-subscriptions' => static function( ContainerInterface $container ): BillingSubscriptions {
|
||||
return new BillingSubscriptions(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.repository.application-context' => static function( ContainerInterface $container ) : ApplicationContextRepository {
|
||||
|
||||
|
@ -261,24 +298,32 @@ return array(
|
|||
$container->get( 'api.factory.fraud-processor-response' )
|
||||
);
|
||||
},
|
||||
'api.factory.refund' => static function ( ContainerInterface $container ): RefundFactory {
|
||||
$amount_factory = $container->get( 'api.factory.amount' );
|
||||
return new RefundFactory(
|
||||
$amount_factory,
|
||||
$container->get( 'api.factory.seller-payable-breakdown' ),
|
||||
$container->get( 'api.factory.refund_payer' )
|
||||
);
|
||||
},
|
||||
'api.factory.purchase-unit' => static function ( ContainerInterface $container ): PurchaseUnitFactory {
|
||||
|
||||
$amount_factory = $container->get( 'api.factory.amount' );
|
||||
$payee_repository = $container->get( 'api.repository.payee' );
|
||||
$payee_factory = $container->get( 'api.factory.payee' );
|
||||
$item_factory = $container->get( 'api.factory.item' );
|
||||
$shipping_factory = $container->get( 'api.factory.shipping' );
|
||||
$payments_factory = $container->get( 'api.factory.payments' );
|
||||
$prefix = $container->get( 'api.prefix' );
|
||||
$soft_descriptor = $container->get( 'wcgateway.soft-descriptor' );
|
||||
$sanitizer = $container->get( 'api.helper.purchase-unit-sanitizer' );
|
||||
|
||||
return new PurchaseUnitFactory(
|
||||
$amount_factory,
|
||||
$payee_repository,
|
||||
$payee_factory,
|
||||
$item_factory,
|
||||
$shipping_factory,
|
||||
$payments_factory,
|
||||
$prefix
|
||||
$prefix,
|
||||
$soft_descriptor,
|
||||
$sanitizer
|
||||
);
|
||||
},
|
||||
'api.factory.patch-collection-factory' => static function ( ContainerInterface $container ): PatchCollectionFactory {
|
||||
|
@ -293,12 +338,19 @@ return array(
|
|||
);
|
||||
},
|
||||
'api.factory.shipping' => static function ( ContainerInterface $container ): ShippingFactory {
|
||||
$address_factory = $container->get( 'api.factory.address' );
|
||||
return new ShippingFactory( $address_factory );
|
||||
return new ShippingFactory(
|
||||
$container->get( 'api.factory.address' ),
|
||||
$container->get( 'api.factory.shipping-option' )
|
||||
);
|
||||
},
|
||||
'api.factory.shipping-preference' => static function ( ContainerInterface $container ): ShippingPreferenceFactory {
|
||||
return new ShippingPreferenceFactory();
|
||||
},
|
||||
'api.factory.shipping-option' => static function ( ContainerInterface $container ): ShippingOptionFactory {
|
||||
return new ShippingOptionFactory(
|
||||
$container->get( 'api.factory.money' )
|
||||
);
|
||||
},
|
||||
'api.factory.amount' => static function ( ContainerInterface $container ): AmountFactory {
|
||||
$item_factory = $container->get( 'api.factory.item' );
|
||||
return new AmountFactory(
|
||||
|
@ -314,6 +366,9 @@ return array(
|
|||
$address_factory = $container->get( 'api.factory.address' );
|
||||
return new PayerFactory( $address_factory );
|
||||
},
|
||||
'api.factory.refund_payer' => static function ( ContainerInterface $container ): RefundPayerFactory {
|
||||
return new RefundPayerFactory();
|
||||
},
|
||||
'api.factory.address' => static function ( ContainerInterface $container ): AddressFactory {
|
||||
return new AddressFactory();
|
||||
},
|
||||
|
@ -337,7 +392,8 @@ return array(
|
|||
'api.factory.payments' => static function ( ContainerInterface $container ): PaymentsFactory {
|
||||
$authorizations_factory = $container->get( 'api.factory.authorization' );
|
||||
$capture_factory = $container->get( 'api.factory.capture' );
|
||||
return new PaymentsFactory( $authorizations_factory, $capture_factory );
|
||||
$refund_factory = $container->get( 'api.factory.refund' );
|
||||
return new PaymentsFactory( $authorizations_factory, $capture_factory, $refund_factory );
|
||||
},
|
||||
'api.factory.authorization' => static function ( ContainerInterface $container ): AuthorizationFactory {
|
||||
return new AuthorizationFactory();
|
||||
|
@ -358,9 +414,30 @@ return array(
|
|||
$container->get( 'api.factory.platform-fee' )
|
||||
);
|
||||
},
|
||||
'api.factory.seller-payable-breakdown' => static function ( ContainerInterface $container ): SellerPayableBreakdownFactory {
|
||||
return new SellerPayableBreakdownFactory(
|
||||
$container->get( 'api.factory.money' ),
|
||||
$container->get( 'api.factory.platform-fee' )
|
||||
);
|
||||
},
|
||||
'api.factory.fraud-processor-response' => static function ( ContainerInterface $container ): FraudProcessorResponseFactory {
|
||||
return new FraudProcessorResponseFactory();
|
||||
},
|
||||
'api.factory.product' => static function( ContainerInterface $container ): ProductFactory {
|
||||
return new ProductFactory();
|
||||
},
|
||||
'api.factory.billing-cycle' => static function( ContainerInterface $container ): BillingCycleFactory {
|
||||
return new BillingCycleFactory( $container->get( 'api.shop.currency' ) );
|
||||
},
|
||||
'api.factory.payment-preferences' => static function( ContainerInterface $container ):PaymentPreferencesFactory {
|
||||
return new PaymentPreferencesFactory( $container->get( 'api.shop.currency' ) );
|
||||
},
|
||||
'api.factory.plan' => static function( ContainerInterface $container ): PlanFactory {
|
||||
return new PlanFactory(
|
||||
$container->get( 'api.factory.billing-cycle' ),
|
||||
$container->get( 'api.factory.payment-preferences' )
|
||||
);
|
||||
},
|
||||
'api.helpers.dccapplies' => static function ( ContainerInterface $container ) : DccApplies {
|
||||
return new DccApplies(
|
||||
$container->get( 'api.dcc-supported-country-currency-matrix' ),
|
||||
|
@ -635,6 +712,27 @@ return array(
|
|||
'SGD',
|
||||
'USD',
|
||||
),
|
||||
'MX' => array(
|
||||
'MXN',
|
||||
),
|
||||
'JP' => array(
|
||||
'AUD',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'JPY',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'USD',
|
||||
),
|
||||
)
|
||||
);
|
||||
},
|
||||
|
@ -691,6 +789,17 @@ return array(
|
|||
'amex' => array( 'CAD' ),
|
||||
'jcb' => array( 'CAD' ),
|
||||
),
|
||||
'MX' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array(),
|
||||
),
|
||||
'JP' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
'amex' => array( 'JPY' ),
|
||||
'jcb' => array( 'JPY' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
},
|
||||
|
@ -730,4 +839,23 @@ return array(
|
|||
'api.order-helper' => static function( ContainerInterface $container ): OrderHelper {
|
||||
return new OrderHelper();
|
||||
},
|
||||
'api.helper.order-transient' => static function( ContainerInterface $container ): OrderTransient {
|
||||
$cache = new Cache( 'ppcp-paypal-bearer' );
|
||||
$purchase_unit_sanitizer = $container->get( 'api.helper.purchase-unit-sanitizer' );
|
||||
return new OrderTransient( $cache, $purchase_unit_sanitizer );
|
||||
},
|
||||
'api.helper.failure-registry' => static function( ContainerInterface $container ): FailureRegistry {
|
||||
$cache = new Cache( 'ppcp-paypal-api-status-cache' );
|
||||
return new FailureRegistry( $cache );
|
||||
},
|
||||
'api.helper.purchase-unit-sanitizer' => SingletonDecorator::make(
|
||||
static function( ContainerInterface $container ): PurchaseUnitSanitizer {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
|
||||
$behavior = $settings->has( 'subtotal_mismatch_behavior' ) ? $settings->get( 'subtotal_mismatch_behavior' ) : null;
|
||||
$line_name = $settings->has( 'subtotal_mismatch_line_name' ) ? $settings->get( 'subtotal_mismatch_line_name' ) : null;
|
||||
return new PurchaseUnitSanitizer( $behavior, $line_name );
|
||||
}
|
||||
),
|
||||
);
|
||||
|
|
|
@ -9,10 +9,14 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient;
|
||||
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderTransient;
|
||||
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\ApiClient\Entity\Order;
|
||||
|
||||
/**
|
||||
* Class ApiModule
|
||||
|
@ -40,6 +44,56 @@ class ApiModule implements ModuleInterface {
|
|||
WC()->session->set( 'ppcp_fees', $fees );
|
||||
}
|
||||
);
|
||||
add_filter(
|
||||
'ppcp_create_order_request_body_data',
|
||||
function( array $data ) use ( $c ) {
|
||||
|
||||
foreach ( $data['purchase_units'] as $purchase_unit_index => $purchase_unit ) {
|
||||
foreach ( $purchase_unit['items'] as $item_index => $item ) {
|
||||
$data['purchase_units'][ $purchase_unit_index ]['items'][ $item_index ]['name'] =
|
||||
apply_filters( 'woocommerce_paypal_payments_cart_line_item_name', $item['name'], $item['cart_item_key'] ?? null );
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
);
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_paypal_order_created',
|
||||
function ( Order $order ) use ( $c ) {
|
||||
$transient = $c->has( 'api.helper.order-transient' ) ? $c->get( 'api.helper.order-transient' ) : null;
|
||||
|
||||
if ( $transient instanceof OrderTransient ) {
|
||||
$transient->on_order_created( $order );
|
||||
}
|
||||
},
|
||||
10,
|
||||
1
|
||||
);
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_woocommerce_order_created',
|
||||
function ( WC_Order $wc_order, Order $order ) use ( $c ) {
|
||||
$transient = $c->has( 'api.helper.order-transient' ) ? $c->get( 'api.helper.order-transient' ) : null;
|
||||
|
||||
if ( $transient instanceof OrderTransient ) {
|
||||
$transient->on_woocommerce_order_created( $wc_order, $order );
|
||||
}
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_clear_apm_product_status',
|
||||
function () use ( $c ) {
|
||||
$failure_registry = $c->has( 'api.helper.failure-registry' ) ? $c->get( 'api.helper.failure-registry' ) : null;
|
||||
|
||||
if ( $failure_registry instanceof FailureRegistry ) {
|
||||
$failure_registry->clear_failures( FailureRegistry::SELLER_STATUS_KEY );
|
||||
}
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||
|
||||
use Exception;
|
||||
use stdClass;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
|
@ -120,6 +121,10 @@ class BillingAgreementsEndpoint {
|
|||
*/
|
||||
public function reference_transaction_enabled(): bool {
|
||||
try {
|
||||
if ( wc_string_to_bool( get_transient( 'ppcp_reference_transaction_enabled' ) ) === true ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->is_request_logging_enabled = false;
|
||||
|
||||
try {
|
||||
|
@ -130,10 +135,12 @@ class BillingAgreementsEndpoint {
|
|||
);
|
||||
} finally {
|
||||
$this->is_request_logging_enabled = true;
|
||||
set_transient( 'ppcp_reference_transaction_enabled', true, MONTH_IN_SECONDS );
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch ( PayPalApiException $exception ) {
|
||||
} catch ( Exception $exception ) {
|
||||
delete_transient( 'ppcp_reference_transaction_enabled' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
263
modules/ppcp-api-client/src/Endpoint/BillingPlans.php
Normal file
263
modules/ppcp-api-client/src/Endpoint/BillingPlans.php
Normal file
|
@ -0,0 +1,263 @@
|
|||
<?php
|
||||
/**
|
||||
* The Billing Plans endpoint.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\BillingCycle;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Plan;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\BillingCycleFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PlanFactory;
|
||||
|
||||
/**
|
||||
* Class BillingPlans
|
||||
*/
|
||||
class BillingPlans {
|
||||
|
||||
use RequestTrait;
|
||||
|
||||
/**
|
||||
* The host.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $host;
|
||||
|
||||
/**
|
||||
* The bearer.
|
||||
*
|
||||
* @var Bearer
|
||||
*/
|
||||
private $bearer;
|
||||
|
||||
/**
|
||||
* Billing cycle factory
|
||||
*
|
||||
* @var BillingCycleFactory
|
||||
*/
|
||||
private $billing_cycle_factory;
|
||||
|
||||
/**
|
||||
* Plan factory
|
||||
*
|
||||
* @var PlanFactory
|
||||
*/
|
||||
private $plan_factory;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* BillingPlans constructor.
|
||||
*
|
||||
* @param string $host The host.
|
||||
* @param Bearer $bearer The bearer.
|
||||
* @param BillingCycleFactory $billing_cycle_factory Billing cycle factory.
|
||||
* @param PlanFactory $plan_factory Plan factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
string $host,
|
||||
Bearer $bearer,
|
||||
BillingCycleFactory $billing_cycle_factory,
|
||||
PlanFactory $plan_factory,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->host = $host;
|
||||
$this->bearer = $bearer;
|
||||
$this->billing_cycle_factory = $billing_cycle_factory;
|
||||
$this->plan_factory = $plan_factory;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a subscription plan.
|
||||
*
|
||||
* @param string $name Product name.
|
||||
* @param string $product_id Product ID.
|
||||
* @param array $billing_cycles Billing cycles.
|
||||
* @param array $payment_preferences Payment preferences.
|
||||
*
|
||||
* @return Plan
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function create(
|
||||
string $name,
|
||||
string $product_id,
|
||||
array $billing_cycles,
|
||||
array $payment_preferences
|
||||
): Plan {
|
||||
|
||||
$data = array(
|
||||
'name' => $name,
|
||||
'product_id' => $product_id,
|
||||
'billing_cycles' => $billing_cycles,
|
||||
'payment_preferences' => $payment_preferences,
|
||||
);
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/billing/plans';
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Not able to create plan.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 201 !== $status_code ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
|
||||
return $this->plan_factory->from_paypal_response( $json );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a plan,
|
||||
*
|
||||
* @param string $id Plan ID.
|
||||
*
|
||||
* @return Plan
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function plan( string $id ): Plan {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/billing/plans/' . $id;
|
||||
$args = array(
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Not able to get plan.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 !== $status_code ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
|
||||
return $this->plan_factory->from_paypal_response( $json );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates pricing.
|
||||
*
|
||||
* @param string $id Plan ID.
|
||||
* @param BillingCycle $billing_cycle Billing cycle.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function update_pricing( string $id, BillingCycle $billing_cycle ): void {
|
||||
$data = array(
|
||||
'pricing_schemes' => array(
|
||||
(object) array(
|
||||
'billing_cycle_sequence' => 1,
|
||||
'pricing_scheme' => $billing_cycle->pricing_scheme(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/billing/plans/' . $id . '/update-pricing-schemes';
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Could not update pricing.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 204 !== $status_code ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates a Subscription Plan.
|
||||
*
|
||||
* @param string $billing_plan_id The Plan ID.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function deactivate_plan( string $billing_plan_id ) {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/billing/plans/' . $billing_plan_id . '/deactivate';
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Could not deactivate plan.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 204 !== $status_code ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
219
modules/ppcp-api-client/src/Endpoint/BillingSubscriptions.php
Normal file
219
modules/ppcp-api-client/src/Endpoint/BillingSubscriptions.php
Normal file
|
@ -0,0 +1,219 @@
|
|||
<?php
|
||||
/**
|
||||
* The Billing Subscriptions endpoint.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use stdClass;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class BillingSubscriptions
|
||||
*/
|
||||
class BillingSubscriptions {
|
||||
|
||||
use RequestTrait;
|
||||
|
||||
/**
|
||||
* The host.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $host;
|
||||
|
||||
/**
|
||||
* The bearer.
|
||||
*
|
||||
* @var Bearer
|
||||
*/
|
||||
private $bearer;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* BillingSubscriptions constructor.
|
||||
*
|
||||
* @param string $host The host.
|
||||
* @param Bearer $bearer The bearer.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct( string $host, Bearer $bearer, LoggerInterface $logger ) {
|
||||
$this->host = $host;
|
||||
$this->bearer = $bearer;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspends a subscription.
|
||||
*
|
||||
* @param string $id Subscription ID.
|
||||
* @return void
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function suspend( string $id ):void {
|
||||
$data = array(
|
||||
'reason' => 'Suspended by customer',
|
||||
);
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/billing/subscriptions/' . $id . '/suspend';
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Not able to suspend subscription.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 204 !== $status_code ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates a subscription.
|
||||
*
|
||||
* @param string $id Subscription ID.
|
||||
* @return void
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function activate( string $id ): void {
|
||||
$data = array(
|
||||
'reason' => 'Reactivated by customer',
|
||||
);
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/billing/subscriptions/' . $id . '/activate';
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Not able to reactivate subscription.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 204 !== $status_code ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a Subscription.
|
||||
*
|
||||
* @param string $id Subscription ID.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function cancel( string $id ): void {
|
||||
$data = array(
|
||||
'reason' => 'Cancelled by customer',
|
||||
);
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/billing/subscriptions/' . $id . '/cancel';
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Not able to cancel subscription.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 204 !== $status_code ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Subscription object from the given ID.
|
||||
*
|
||||
* @param string $id Subscription ID.
|
||||
*
|
||||
* @return stdClass
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function subscription( string $id ): stdClass {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/billing/subscriptions/' . $id;
|
||||
$args = array(
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Not able to get subscription.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 !== $status_code ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
|
||||
}
|
196
modules/ppcp-api-client/src/Endpoint/CatalogProducts.php
Normal file
196
modules/ppcp-api-client/src/Endpoint/CatalogProducts.php
Normal file
|
@ -0,0 +1,196 @@
|
|||
<?php
|
||||
/**
|
||||
* The Catalog Products endpoint.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Product;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ProductFactory;
|
||||
|
||||
/**
|
||||
* Class CatalogProduct
|
||||
*/
|
||||
class CatalogProducts {
|
||||
use RequestTrait;
|
||||
|
||||
/**
|
||||
* The host.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $host;
|
||||
|
||||
/**
|
||||
* The bearer.
|
||||
*
|
||||
* @var Bearer
|
||||
*/
|
||||
private $bearer;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* Product factory.
|
||||
*
|
||||
* @var ProductFactory
|
||||
*/
|
||||
private $product_factory;
|
||||
|
||||
/**
|
||||
* CatalogProducts constructor.
|
||||
*
|
||||
* @param string $host The host.
|
||||
* @param Bearer $bearer The bearer.
|
||||
* @param ProductFactory $product_factory Product factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
string $host,
|
||||
Bearer $bearer,
|
||||
ProductFactory $product_factory,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->host = $host;
|
||||
$this->bearer = $bearer;
|
||||
$this->product_factory = $product_factory;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a product.
|
||||
*
|
||||
* @param string $name Product name.
|
||||
* @param string $description Product description.
|
||||
*
|
||||
* @return Product
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function create( string $name, string $description ): Product {
|
||||
$data = array(
|
||||
'name' => $name,
|
||||
'description' => $description ?: $name,
|
||||
);
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/catalogs/products';
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Not able to create product.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 201 !== $status_code ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
|
||||
return $this->product_factory->from_paypal_response( $json );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a Product.
|
||||
*
|
||||
* @param string $id Product ID.
|
||||
* @param array $data Data to update.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function update( string $id, array $data ): void {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/catalogs/products/' . $id;
|
||||
$args = array(
|
||||
'method' => 'PATCH',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Not able to update product.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 204 !== $status_code ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Product from the given ID.
|
||||
*
|
||||
* @param string $id Product ID.
|
||||
*
|
||||
* @return Product
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function product( string $id ): Product {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v1/catalogs/products/' . $id;
|
||||
$args = array(
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
||||
throw new RuntimeException( 'Not able to get product.' );
|
||||
}
|
||||
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 !== $status_code ) {
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
|
||||
return $this->product_factory->from_paypal_response( $json );
|
||||
}
|
||||
}
|
|
@ -103,7 +103,8 @@ class IdentityToken {
|
|||
);
|
||||
if (
|
||||
( $this->settings->has( 'vault_enabled' ) && $this->settings->get( 'vault_enabled' ) )
|
||||
&& defined( 'PPCP_FLAG_SUBSCRIPTION' ) && PPCP_FLAG_SUBSCRIPTION
|
||||
|| ( $this->settings->has( 'vault_enabled_dcc' ) && $this->settings->get( 'vault_enabled_dcc' ) )
|
||||
|| ( $this->settings->has( 'subscriptions_mode' ) && $this->settings->get( 'subscriptions_mode' ) === 'vaulting_api' )
|
||||
) {
|
||||
$customer_id = $this->customer_repository->customer_id_for_user( ( $user_id ) );
|
||||
update_user_meta( $user_id, 'ppcp_customer_id', $customer_id );
|
||||
|
|
|
@ -16,8 +16,8 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\CaptureStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PatchCollection;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentMethod;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
|
@ -26,7 +26,6 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PatchCollectionFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\ErrorResponse;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
|
||||
|
@ -116,13 +115,6 @@ class OrderEndpoint {
|
|||
*/
|
||||
private $bn_code;
|
||||
|
||||
/**
|
||||
* The paypal request id repository.
|
||||
*
|
||||
* @var PayPalRequestIdRepository
|
||||
*/
|
||||
private $paypal_request_id_repository;
|
||||
|
||||
/**
|
||||
* OrderEndpoint constructor.
|
||||
*
|
||||
|
@ -133,7 +125,6 @@ class OrderEndpoint {
|
|||
* @param string $intent The intent.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param ApplicationContextRepository $application_context_repository The application context repository.
|
||||
* @param PayPalRequestIdRepository $paypal_request_id_repository The paypal request id repository.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param bool $is_fraudnet_enabled true if FraudNet support is enabled in settings, otherwise false.
|
||||
* @param FraudNet $fraudnet The FraudNet entity.
|
||||
|
@ -147,7 +138,6 @@ class OrderEndpoint {
|
|||
string $intent,
|
||||
LoggerInterface $logger,
|
||||
ApplicationContextRepository $application_context_repository,
|
||||
PayPalRequestIdRepository $paypal_request_id_repository,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
bool $is_fraudnet_enabled,
|
||||
FraudNet $fraudnet,
|
||||
|
@ -162,7 +152,6 @@ class OrderEndpoint {
|
|||
$this->logger = $logger;
|
||||
$this->application_context_repository = $application_context_repository;
|
||||
$this->bn_code = $bn_code;
|
||||
$this->paypal_request_id_repository = $paypal_request_id_repository;
|
||||
$this->is_fraudnet_enabled = $is_fraudnet_enabled;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->fraudnet = $fraudnet;
|
||||
|
@ -189,8 +178,8 @@ class OrderEndpoint {
|
|||
* @param string $shipping_preference One of ApplicationContext::SHIPPING_PREFERENCE_ values.
|
||||
* @param Payer|null $payer The payer off the order.
|
||||
* @param PaymentToken|null $payment_token The payment token.
|
||||
* @param PaymentMethod|null $payment_method The payment method.
|
||||
* @param string $paypal_request_id The paypal request id.
|
||||
* @param string $user_action The user action.
|
||||
*
|
||||
* @return Order
|
||||
* @throws RuntimeException If the request fails.
|
||||
|
@ -200,20 +189,27 @@ class OrderEndpoint {
|
|||
string $shipping_preference,
|
||||
Payer $payer = null,
|
||||
PaymentToken $payment_token = null,
|
||||
PaymentMethod $payment_method = null,
|
||||
string $paypal_request_id = ''
|
||||
string $paypal_request_id = '',
|
||||
string $user_action = ApplicationContext::USER_ACTION_CONTINUE
|
||||
): Order {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$data = array(
|
||||
'intent' => ( $this->subscription_helper->cart_contains_subscription() || $this->subscription_helper->current_product_is_subscription() ) ? 'AUTHORIZE' : $this->intent,
|
||||
'intent' => apply_filters( 'woocommerce_paypal_payments_order_intent', $this->intent ),
|
||||
'purchase_units' => array_map(
|
||||
static function ( PurchaseUnit $item ): array {
|
||||
return $item->to_array();
|
||||
static function ( PurchaseUnit $item ) use ( $shipping_preference ): array {
|
||||
$data = $item->to_array();
|
||||
|
||||
if ( $shipping_preference !== ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE ) {
|
||||
// Shipping options are not allowed to be sent when not getting the address from PayPal.
|
||||
unset( $data['shipping']['options'] );
|
||||
}
|
||||
|
||||
return $data;
|
||||
},
|
||||
$items
|
||||
),
|
||||
'application_context' => $this->application_context_repository
|
||||
->current_context( $shipping_preference )->to_array(),
|
||||
->current_context( $shipping_preference, $user_action )->to_array(),
|
||||
);
|
||||
if ( $payer && ! empty( $payer->email_address() ) ) {
|
||||
$data['payer'] = $payer->to_array();
|
||||
|
@ -221,9 +217,6 @@ class OrderEndpoint {
|
|||
if ( $payment_token ) {
|
||||
$data['payment_source']['token'] = $payment_token->to_array();
|
||||
}
|
||||
if ( $payment_method ) {
|
||||
$data['payment_method'] = $payment_method->to_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* The filter can be used to modify the order creation request body data.
|
||||
|
@ -240,8 +233,6 @@ class OrderEndpoint {
|
|||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
||||
$paypal_request_id = $paypal_request_id ? $paypal_request_id : uniqid( 'ppcp-', true );
|
||||
$args['headers']['PayPal-Request-Id'] = $paypal_request_id;
|
||||
if ( $this->bn_code ) {
|
||||
$args['headers']['PayPal-Partner-Attribution-Id'] = $this->bn_code;
|
||||
}
|
||||
|
@ -250,6 +241,10 @@ class OrderEndpoint {
|
|||
$args['headers']['PayPal-Client-Metadata-Id'] = $this->fraudnet->session_id();
|
||||
}
|
||||
|
||||
if ( isset( $data['payment_source'] ) ) {
|
||||
$args['headers']['PayPal-Request-Id'] = uniqid( 'ppcp-', true );
|
||||
}
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$error = new RuntimeException(
|
||||
|
@ -286,7 +281,9 @@ class OrderEndpoint {
|
|||
throw $error;
|
||||
}
|
||||
$order = $this->order_factory->from_paypal_response( $json );
|
||||
$this->paypal_request_id_repository->set_for_order( $order, $paypal_request_id );
|
||||
|
||||
do_action( 'woocommerce_paypal_payments_paypal_order_created', $order );
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
|
@ -310,7 +307,6 @@ class OrderEndpoint {
|
|||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
'PayPal-Request-Id' => $this->paypal_request_id_repository->get_for_order( $order ),
|
||||
),
|
||||
);
|
||||
if ( $this->bn_code ) {
|
||||
|
@ -385,7 +381,6 @@ class OrderEndpoint {
|
|||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
'PayPal-Request-Id' => $this->paypal_request_id_repository->get_for_order( $order ),
|
||||
),
|
||||
);
|
||||
if ( $this->bn_code ) {
|
||||
|
@ -458,7 +453,6 @@ class OrderEndpoint {
|
|||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'PayPal-Request-Id' => $this->paypal_request_id_repository->get_for_order_id( $id ),
|
||||
),
|
||||
);
|
||||
if ( $this->bn_code ) {
|
||||
|
@ -469,14 +463,8 @@ class OrderEndpoint {
|
|||
$error = new RuntimeException(
|
||||
__( 'Could not retrieve order.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
$error->getMessage(),
|
||||
array(
|
||||
'args' => $args,
|
||||
'response' => $response,
|
||||
)
|
||||
);
|
||||
$this->logger->warning( $error->getMessage() );
|
||||
|
||||
throw $error;
|
||||
}
|
||||
$json = json_decode( $response['body'] );
|
||||
|
@ -511,8 +499,8 @@ class OrderEndpoint {
|
|||
);
|
||||
throw $error;
|
||||
}
|
||||
$order = $this->order_factory->from_paypal_response( $json );
|
||||
return $order;
|
||||
|
||||
return $this->order_factory->from_paypal_response( $json );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -530,25 +518,36 @@ class OrderEndpoint {
|
|||
return $order_to_update;
|
||||
}
|
||||
|
||||
$patches_array = $patches->to_array();
|
||||
if ( ! isset( $patches_array[0]['value']['shipping'] ) ) {
|
||||
$shipping = isset( $order_to_update->purchase_units()[0] ) && null !== $order_to_update->purchase_units()[0]->shipping() ? $order_to_update->purchase_units()[0]->shipping() : null;
|
||||
if ( $shipping ) {
|
||||
$patches_array[0]['value']['shipping'] = $shipping->to_array();
|
||||
}
|
||||
$this->patch( $order_to_update->id(), $patches );
|
||||
|
||||
$new_order = $this->order( $order_to_update->id() );
|
||||
return $new_order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches an order.
|
||||
*
|
||||
* @param string $order_id The PayPal order ID.
|
||||
* @param PatchCollection $patches The patches.
|
||||
*
|
||||
* @throws RuntimeException If the request fails.
|
||||
*/
|
||||
public function patch( string $order_id, PatchCollection $patches ): void {
|
||||
$patches_array = $patches->to_array();
|
||||
|
||||
/**
|
||||
* The filter can be used to modify the order patching request body data (the final prices, items).
|
||||
*/
|
||||
$patches_array = apply_filters( 'ppcp_patch_order_request_body_data', $patches_array );
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $order_to_update->id();
|
||||
$url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $order_id;
|
||||
$args = array(
|
||||
'method' => 'PATCH',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
'PayPal-Request-Id' => $this->paypal_request_id_repository->get_for_order(
|
||||
$order_to_update
|
||||
),
|
||||
),
|
||||
'body' => wp_json_encode( $patches_array ),
|
||||
);
|
||||
|
@ -558,11 +557,8 @@ class OrderEndpoint {
|
|||
$response = $this->request( $url, $args );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$error = new RuntimeException(
|
||||
__( 'Could not retrieve order.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
$error = new RuntimeException( 'Could not patch order.' );
|
||||
$this->logger->warning(
|
||||
$error->getMessage(),
|
||||
array(
|
||||
'args' => $args,
|
||||
|
@ -578,8 +574,7 @@ class OrderEndpoint {
|
|||
$json,
|
||||
$status_code
|
||||
);
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
$this->logger->warning(
|
||||
$error->getMessage(),
|
||||
array(
|
||||
'args' => $args,
|
||||
|
@ -588,9 +583,6 @@ class OrderEndpoint {
|
|||
);
|
||||
throw $error;
|
||||
}
|
||||
|
||||
$new_order = $this->order( $order_to_update->id() );
|
||||
return $new_order;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatus;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\SellerStatusFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry;
|
||||
|
||||
/**
|
||||
* Class PartnersEndpoint
|
||||
|
@ -65,6 +66,13 @@ class PartnersEndpoint {
|
|||
*/
|
||||
private $merchant_id;
|
||||
|
||||
/**
|
||||
* The failure registry.
|
||||
*
|
||||
* @var FailureRegistry
|
||||
*/
|
||||
private $failure_registry;
|
||||
|
||||
/**
|
||||
* PartnersEndpoint constructor.
|
||||
*
|
||||
|
@ -74,6 +82,7 @@ class PartnersEndpoint {
|
|||
* @param SellerStatusFactory $seller_status_factory The seller status factory.
|
||||
* @param string $partner_id The partner ID.
|
||||
* @param string $merchant_id The merchant ID.
|
||||
* @param FailureRegistry $failure_registry The API failure registry.
|
||||
*/
|
||||
public function __construct(
|
||||
string $host,
|
||||
|
@ -81,7 +90,8 @@ class PartnersEndpoint {
|
|||
LoggerInterface $logger,
|
||||
SellerStatusFactory $seller_status_factory,
|
||||
string $partner_id,
|
||||
string $merchant_id
|
||||
string $merchant_id,
|
||||
FailureRegistry $failure_registry
|
||||
) {
|
||||
$this->host = $host;
|
||||
$this->bearer = $bearer;
|
||||
|
@ -89,6 +99,7 @@ class PartnersEndpoint {
|
|||
$this->seller_status_factory = $seller_status_factory;
|
||||
$this->partner_id = $partner_id;
|
||||
$this->merchant_id = $merchant_id;
|
||||
$this->failure_registry = $failure_registry;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,9 +151,15 @@ class PartnersEndpoint {
|
|||
'response' => $response,
|
||||
)
|
||||
);
|
||||
|
||||
// Register the failure on api failure registry.
|
||||
$this->failure_registry->add_failure( FailureRegistry::SELLER_STATUS_KEY );
|
||||
|
||||
throw $error;
|
||||
}
|
||||
|
||||
$this->failure_registry->clear_failures( FailureRegistry::SELLER_STATUS_KEY );
|
||||
|
||||
$status = $this->seller_status_factory->from_paypal_reponse( $json );
|
||||
return $status;
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ class PayUponInvoiceOrderEndpoint {
|
|||
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
|
||||
'purchase_units' => array_map(
|
||||
static function ( PurchaseUnit $item ): array {
|
||||
return $item->to_array( false );
|
||||
return $item->to_array( true, false );
|
||||
},
|
||||
$items
|
||||
),
|
||||
|
@ -133,7 +133,7 @@ class PayUponInvoiceOrderEndpoint {
|
|||
'Content-Type' => 'application/json',
|
||||
'Prefer' => 'return=representation',
|
||||
'PayPal-Client-Metadata-Id' => $this->fraudnet->session_id(),
|
||||
'PayPal-Request-Id' => uniqid( 'ppcp-', true ),
|
||||
'PayPal-Request-Id' => uniqid( 'ppcp-', true ), // Request-Id header is required.
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
@ -166,8 +166,11 @@ class PayUponInvoiceOrderEndpoint {
|
|||
|
||||
throw new PayPalApiException( $json, $status_code );
|
||||
}
|
||||
$order = $this->order_factory->from_paypal_response( $json );
|
||||
|
||||
return $this->order_factory->from_paypal_response( $json );
|
||||
do_action( 'woocommerce_paypal_payments_paypal_order_created', $order );
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,6 +239,12 @@ class PayUponInvoiceOrderEndpoint {
|
|||
$tax_total = $data['purchase_units'][0]['amount']['breakdown']['tax_total']['value'];
|
||||
$item_total = $data['purchase_units'][0]['amount']['breakdown']['item_total']['value'];
|
||||
$shipping = $data['purchase_units'][0]['amount']['breakdown']['shipping']['value'];
|
||||
|
||||
$handling = isset( $data['purchase_units'][0]['amount']['breakdown']['handling'] ) ? $data['purchase_units'][0]['amount']['breakdown']['handling']['value'] : 0;
|
||||
$insurance = isset( $data['purchase_units'][0]['amount']['breakdown']['insurance'] ) ? $data['purchase_units'][0]['amount']['breakdown']['insurance']['value'] : 0;
|
||||
$shipping_discount = isset( $data['purchase_units'][0]['amount']['breakdown']['shipping_discount'] ) ? $data['purchase_units'][0]['amount']['breakdown']['shipping_discount']['value'] : 0;
|
||||
$discount = isset( $data['purchase_units'][0]['amount']['breakdown']['discount'] ) ? $data['purchase_units'][0]['amount']['breakdown']['discount']['value'] : 0;
|
||||
|
||||
$order_tax_total = $wc_order->get_total_tax();
|
||||
$tax_rate = round( ( $order_tax_total / $item_total ) * 100, 1 );
|
||||
|
||||
|
@ -263,7 +272,7 @@ class PayUponInvoiceOrderEndpoint {
|
|||
);
|
||||
|
||||
$total_amount = $data['purchase_units'][0]['amount']['value'];
|
||||
$breakdown_total = $item_total + $tax_total + $shipping;
|
||||
$breakdown_total = $item_total + $tax_total + $shipping + $handling + $insurance - $shipping_discount - $discount;
|
||||
$diff = round( $total_amount - $breakdown_total, 2 );
|
||||
if ( $diff === -0.01 || $diff === 0.01 ) {
|
||||
$data['purchase_units'][0]['amount']['value'] = number_format( $breakdown_total, 2, '.', '' );
|
||||
|
|
|
@ -19,7 +19,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentTokenActionLinksFactory;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentTokenFactory;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class PaymentTokenEndpoint
|
||||
|
@ -70,13 +70,6 @@ class PaymentTokenEndpoint {
|
|||
*/
|
||||
protected $customer_repository;
|
||||
|
||||
/**
|
||||
* The request id repository.
|
||||
*
|
||||
* @var PayPalRequestIdRepository
|
||||
*/
|
||||
private $request_id_repository;
|
||||
|
||||
/**
|
||||
* PaymentTokenEndpoint constructor.
|
||||
*
|
||||
|
@ -86,7 +79,6 @@ class PaymentTokenEndpoint {
|
|||
* @param PaymentTokenActionLinksFactory $payment_token_action_links_factory The PaymentTokenActionLinks factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param CustomerRepository $customer_repository The customer repository.
|
||||
* @param PayPalRequestIdRepository $request_id_repository The request id repository.
|
||||
*/
|
||||
public function __construct(
|
||||
string $host,
|
||||
|
@ -94,8 +86,7 @@ class PaymentTokenEndpoint {
|
|||
PaymentTokenFactory $factory,
|
||||
PaymentTokenActionLinksFactory $payment_token_action_links_factory,
|
||||
LoggerInterface $logger,
|
||||
CustomerRepository $customer_repository,
|
||||
PayPalRequestIdRepository $request_id_repository
|
||||
CustomerRepository $customer_repository
|
||||
) {
|
||||
|
||||
$this->host = $host;
|
||||
|
@ -104,11 +95,10 @@ class PaymentTokenEndpoint {
|
|||
$this->payment_token_action_links_factory = $payment_token_action_links_factory;
|
||||
$this->logger = $logger;
|
||||
$this->customer_repository = $customer_repository;
|
||||
$this->request_id_repository = $request_id_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the payment tokens for a user.
|
||||
* Returns the payment tokens for the given user id.
|
||||
*
|
||||
* @param int $id The user id.
|
||||
*
|
||||
|
@ -129,7 +119,67 @@ class PaymentTokenEndpoint {
|
|||
$response = $this->request( $url, $args );
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$error = new RuntimeException(
|
||||
__( 'Could not fetch payment token.', 'woocommerce-paypal-payments' )
|
||||
__( 'Could not fetch payment token for customer id.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
$error->getMessage(),
|
||||
array(
|
||||
'args' => $args,
|
||||
'response' => $response,
|
||||
)
|
||||
);
|
||||
throw $error;
|
||||
}
|
||||
$json = json_decode( $response['body'] );
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 !== $status_code ) {
|
||||
$error = new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
$error->getMessage(),
|
||||
array(
|
||||
'args' => $args,
|
||||
'response' => $response,
|
||||
)
|
||||
);
|
||||
throw $error;
|
||||
}
|
||||
|
||||
$tokens = array();
|
||||
foreach ( $json->payment_tokens as $token_value ) {
|
||||
$tokens[] = $this->factory->from_paypal_response( $token_value );
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the payment tokens for the given guest customer id.
|
||||
*
|
||||
* @param string $customer_id The guest customer id.
|
||||
*
|
||||
* @return PaymentToken[]
|
||||
* @throws RuntimeException If the request fails.
|
||||
*/
|
||||
public function for_guest( string $customer_id ): array {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/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 ) {
|
||||
$error = new RuntimeException(
|
||||
__( 'Could not fetch payment token for guest customer id.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
$this->logger->log(
|
||||
'warning',
|
||||
|
@ -208,6 +258,40 @@ class PaymentTokenEndpoint {
|
|||
return wp_remote_retrieve_response_code( $response ) === 204;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes payment token by the given id.
|
||||
*
|
||||
* @param string $token_id Token id.
|
||||
* @return bool
|
||||
*
|
||||
* @throws RuntimeException If something goes wrong while deleting the token.
|
||||
*/
|
||||
public function delete_token_by_id( string $token_id ): bool {
|
||||
$bearer = $this->bearer->bearer();
|
||||
|
||||
$url = trailingslashit( $this->host ) . 'v2/vault/payment-tokens/' . $token_id;
|
||||
$args = array(
|
||||
'method' => 'DELETE',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
);
|
||||
|
||||
$response = $this->request( $url, $args );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$error = new RuntimeException(
|
||||
__( 'Could not delete payment token.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
$this->logger->warning( $error->getMessage() );
|
||||
|
||||
throw $error;
|
||||
}
|
||||
|
||||
return wp_remote_retrieve_response_code( $response ) === 204;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the process of PayPal account vaulting (without payment), returns the links for further actions.
|
||||
*
|
||||
|
@ -243,14 +327,11 @@ class PaymentTokenEndpoint {
|
|||
),
|
||||
);
|
||||
|
||||
$request_id = uniqid( 'ppcp-vault', true );
|
||||
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Content-Type' => 'application/json',
|
||||
'Request-Id' => $request_id,
|
||||
),
|
||||
'body' => wp_json_encode( $data ),
|
||||
);
|
||||
|
@ -277,8 +358,6 @@ class PaymentTokenEndpoint {
|
|||
|
||||
$links = $this->payment_token_action_links_factory->from_paypal_response( $json );
|
||||
|
||||
$this->request_id_repository->set( "ppcp-vault-{$user_id}", $request_id );
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
|
@ -302,7 +381,6 @@ class PaymentTokenEndpoint {
|
|||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $bearer->token(),
|
||||
'Request-Id' => $this->request_id_repository->get( "ppcp-vault-{$user_id}" ),
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
);
|
||||
|
|
|
@ -13,7 +13,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Refund;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\RefundCapture;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\AuthorizationFactory;
|
||||
|
@ -196,13 +196,13 @@ class PaymentsEndpoint {
|
|||
/**
|
||||
* Refunds a payment.
|
||||
*
|
||||
* @param Refund $refund The refund to be processed.
|
||||
* @param RefundCapture $refund The refund to be processed.
|
||||
*
|
||||
* @return string Refund ID.
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function refund( Refund $refund ) : string {
|
||||
public function refund( RefundCapture $refund ) : string {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/payments/captures/' . $refund->for_capture()->id() . '/refund';
|
||||
$args = array(
|
||||
|
|
|
@ -17,6 +17,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookEventFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class WebhookEndpoint
|
||||
|
@ -175,12 +176,12 @@ class WebhookEndpoint {
|
|||
*
|
||||
* @param Webhook $hook The webhook to delete.
|
||||
*
|
||||
* @return bool
|
||||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function delete( Webhook $hook ): bool {
|
||||
public function delete( Webhook $hook ): void {
|
||||
if ( ! $hook->id() ) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
|
@ -193,12 +194,28 @@ class WebhookEndpoint {
|
|||
);
|
||||
$response = $this->request( $url, $args );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
if ( $response instanceof WP_Error ) {
|
||||
throw new RuntimeException(
|
||||
__( 'Not able to delete the webhook.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
return wp_remote_retrieve_response_code( $response ) === 204;
|
||||
|
||||
$status_code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( 204 !== $status_code ) {
|
||||
$json = null;
|
||||
/**
|
||||
* Use in array as consistency check.
|
||||
*
|
||||
* @psalm-suppress RedundantConditionGivenDocblockType
|
||||
*/
|
||||
if ( is_array( $response ) ) {
|
||||
$json = json_decode( $response['body'] );
|
||||
}
|
||||
throw new PayPalApiException(
|
||||
$json,
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,6 +41,9 @@ class ApplicationContext {
|
|||
self::USER_ACTION_PAY_NOW,
|
||||
);
|
||||
|
||||
const PAYMENT_METHOD_UNRESTRICTED = 'UNRESTRICTED';
|
||||
const PAYMENT_METHOD_IMMEDIATE_PAYMENT_REQUIRED = 'IMMEDIATE_PAYMENT_REQUIRED';
|
||||
|
||||
/**
|
||||
* The brand name.
|
||||
*
|
||||
|
@ -91,11 +94,11 @@ class ApplicationContext {
|
|||
private $cancel_url;
|
||||
|
||||
/**
|
||||
* The payment method.
|
||||
* The payment method preference.
|
||||
*
|
||||
* @var null
|
||||
* @var string
|
||||
*/
|
||||
private $payment_method;
|
||||
private $payment_method_preference;
|
||||
|
||||
/**
|
||||
* ApplicationContext constructor.
|
||||
|
@ -107,6 +110,7 @@ class ApplicationContext {
|
|||
* @param string $landing_page The landing page.
|
||||
* @param string $shipping_preference The shipping preference.
|
||||
* @param string $user_action The user action.
|
||||
* @param string $payment_method_preference The payment method preference.
|
||||
*
|
||||
* @throws RuntimeException When values are not valid.
|
||||
*/
|
||||
|
@ -117,7 +121,8 @@ class ApplicationContext {
|
|||
string $locale = '',
|
||||
string $landing_page = self::LANDING_PAGE_NO_PREFERENCE,
|
||||
string $shipping_preference = self::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||
string $user_action = self::USER_ACTION_CONTINUE
|
||||
string $user_action = self::USER_ACTION_CONTINUE,
|
||||
string $payment_method_preference = self::PAYMENT_METHOD_IMMEDIATE_PAYMENT_REQUIRED
|
||||
) {
|
||||
|
||||
if ( ! in_array( $landing_page, self::VALID_LANDING_PAGE_VALUES, true ) ) {
|
||||
|
@ -136,9 +141,7 @@ class ApplicationContext {
|
|||
$this->landing_page = $landing_page;
|
||||
$this->shipping_preference = $shipping_preference;
|
||||
$this->user_action = $user_action;
|
||||
|
||||
// Currently we have not implemented the payment method.
|
||||
$this->payment_method = null;
|
||||
$this->payment_method_preference = $payment_method_preference;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,12 +208,10 @@ class ApplicationContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the payment method.
|
||||
*
|
||||
* @return PaymentMethod|null
|
||||
* Returns the payment method preference.
|
||||
*/
|
||||
public function payment_method() {
|
||||
return $this->payment_method;
|
||||
public function payment_method_preference(): string {
|
||||
return $this->payment_method_preference;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,9 +224,6 @@ class ApplicationContext {
|
|||
if ( $this->user_action() ) {
|
||||
$data['user_action'] = $this->user_action();
|
||||
}
|
||||
if ( $this->payment_method() ) {
|
||||
$data['payment_method'] = $this->payment_method();
|
||||
}
|
||||
if ( $this->shipping_preference() ) {
|
||||
$data['shipping_preference'] = $this->shipping_preference();
|
||||
}
|
||||
|
@ -244,6 +242,11 @@ class ApplicationContext {
|
|||
if ( $this->cancel_url() ) {
|
||||
$data['cancel_url'] = $this->cancel_url();
|
||||
}
|
||||
if ( $this->payment_method_preference ) {
|
||||
$data['payment_method'] = array(
|
||||
'payee_preferred' => $this->payment_method_preference,
|
||||
);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
134
modules/ppcp-api-client/src/Entity/BillingCycle.php
Normal file
134
modules/ppcp-api-client/src/Entity/BillingCycle.php
Normal file
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
/**
|
||||
* The Billing Cycle object.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class BillingCycle
|
||||
*/
|
||||
class BillingCycle {
|
||||
|
||||
/**
|
||||
* Frequency.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $frequency;
|
||||
|
||||
/**
|
||||
* Sequence.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $sequence;
|
||||
|
||||
/**
|
||||
* Tenure Type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $tenure_type;
|
||||
|
||||
/**
|
||||
* Pricing scheme.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $pricing_scheme;
|
||||
|
||||
/**
|
||||
* Total cycles.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $total_cycles;
|
||||
|
||||
/**
|
||||
* BillingCycle constructor.
|
||||
*
|
||||
* @param array $frequency Frequency.
|
||||
* @param int $sequence Sequence.
|
||||
* @param string $tenure_type Tenure type.
|
||||
* @param array $pricing_scheme Pricing scheme.
|
||||
* @param int $total_cycles Total cycles.
|
||||
*/
|
||||
public function __construct(
|
||||
array $frequency,
|
||||
int $sequence,
|
||||
string $tenure_type,
|
||||
array $pricing_scheme = array(),
|
||||
int $total_cycles = 1
|
||||
) {
|
||||
$this->frequency = $frequency;
|
||||
$this->sequence = $sequence;
|
||||
$this->tenure_type = $tenure_type;
|
||||
$this->pricing_scheme = $pricing_scheme;
|
||||
$this->total_cycles = $total_cycles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns frequency.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frequency(): array {
|
||||
return $this->frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sequence.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function sequence(): int {
|
||||
return $this->sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns tenure type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function tenure_type(): string {
|
||||
return $this->tenure_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns pricing scheme.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function pricing_scheme(): array {
|
||||
return $this->pricing_scheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return total cycles.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function total_cycles(): int {
|
||||
return $this->total_cycles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Billing Cycle as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'frequency' => $this->frequency(),
|
||||
'sequence' => $this->sequence(),
|
||||
'tenure_type' => $this->tenure_type(),
|
||||
'pricing_scheme' => $this->pricing_scheme(),
|
||||
'total_cycles' => $this->total_cycles(),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -66,6 +66,20 @@ class Item {
|
|||
*/
|
||||
private $category;
|
||||
|
||||
/**
|
||||
* The product url.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* The product image url.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $image_url;
|
||||
|
||||
/**
|
||||
* The tax rate.
|
||||
*
|
||||
|
@ -73,6 +87,13 @@ class Item {
|
|||
*/
|
||||
protected $tax_rate;
|
||||
|
||||
/**
|
||||
* The cart item key.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $cart_item_key;
|
||||
|
||||
/**
|
||||
* Item constructor.
|
||||
*
|
||||
|
@ -83,7 +104,10 @@ class Item {
|
|||
* @param Money|null $tax The tax.
|
||||
* @param string $sku The SKU.
|
||||
* @param string $category The category.
|
||||
* @param string $url The product url.
|
||||
* @param string $image_url The product image url.
|
||||
* @param float $tax_rate The tax rate.
|
||||
* @param ?string $cart_item_key The cart key for this item.
|
||||
*/
|
||||
public function __construct(
|
||||
string $name,
|
||||
|
@ -93,7 +117,10 @@ class Item {
|
|||
Money $tax = null,
|
||||
string $sku = '',
|
||||
string $category = 'PHYSICAL_GOODS',
|
||||
float $tax_rate = 0
|
||||
string $url = '',
|
||||
string $image_url = '',
|
||||
float $tax_rate = 0,
|
||||
string $cart_item_key = null
|
||||
) {
|
||||
|
||||
$this->name = $name;
|
||||
|
@ -102,9 +129,11 @@ class Item {
|
|||
$this->description = $description;
|
||||
$this->tax = $tax;
|
||||
$this->sku = $sku;
|
||||
$this->category = ( self::DIGITAL_GOODS === $category ) ? self::DIGITAL_GOODS : self::PHYSICAL_GOODS;
|
||||
$this->category = $category;
|
||||
$this->url = $url;
|
||||
$this->image_url = $image_url;
|
||||
$this->tax_rate = $tax_rate;
|
||||
$this->cart_item_key = $cart_item_key;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,6 +199,24 @@ class Item {
|
|||
return $this->category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the url.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url():string {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image url.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function image_url():string {
|
||||
return $this->validate_image_url() ? $this->image_url : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tax rate.
|
||||
*
|
||||
|
@ -179,12 +226,21 @@ class Item {
|
|||
return round( (float) $this->tax_rate, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cart key for this item.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function cart_item_key():?string {
|
||||
return $this->cart_item_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() {
|
||||
public function to_array(): array {
|
||||
$item = array(
|
||||
'name' => $this->name(),
|
||||
'unit_amount' => $this->unit_amount()->to_array(),
|
||||
|
@ -192,8 +248,13 @@ class Item {
|
|||
'description' => $this->description(),
|
||||
'sku' => $this->sku(),
|
||||
'category' => $this->category(),
|
||||
'url' => $this->url(),
|
||||
);
|
||||
|
||||
if ( $this->image_url() ) {
|
||||
$item['image_url'] = $this->image_url();
|
||||
}
|
||||
|
||||
if ( $this->tax() ) {
|
||||
$item['tax'] = $this->tax()->to_array();
|
||||
}
|
||||
|
@ -202,6 +263,20 @@ class Item {
|
|||
$item['tax_rate'] = (string) $this->tax_rate();
|
||||
}
|
||||
|
||||
if ( $this->cart_item_key() ) {
|
||||
$item['cart_item_key'] = (string) $this->cart_item_key();
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the image url for PayPal request.
|
||||
*
|
||||
* @return bool true if valid, otherwise false.
|
||||
*/
|
||||
protected function validate_image_url(): bool {
|
||||
$pattern = '/^(https:)([\/|\.|\w|\s|-])*\.(?:jpg|gif|png|jpeg|JPG|GIF|PNG|JPEG)$/';
|
||||
return (bool) preg_match( $pattern, $this->image_url );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,8 +83,8 @@ class Patch {
|
|||
public function to_array(): array {
|
||||
return array(
|
||||
'op' => $this->op(),
|
||||
'value' => $this->value(),
|
||||
'path' => $this->path(),
|
||||
'value' => $this->value(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* The PaymentMethod object
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class PaymentMethod
|
||||
*/
|
||||
class PaymentMethod {
|
||||
|
||||
|
||||
const PAYER_SELECTED_DEFAULT = 'PAYPAL';
|
||||
|
||||
const PAYEE_PREFERRED_UNRESTRICTED = 'UNRESTRICTED';
|
||||
const PAYEE_PREFERRED_IMMEDIATE_PAYMENT_REQUIRED = 'IMMEDIATE_PAYMENT_REQUIRED';
|
||||
|
||||
/**
|
||||
* The preferred value.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $preferred;
|
||||
|
||||
/**
|
||||
* The selected value.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $selected;
|
||||
|
||||
/**
|
||||
* PaymentMethod constructor.
|
||||
*
|
||||
* @param string $preferred The preferred value.
|
||||
* @param string $selected The selected value.
|
||||
*/
|
||||
public function __construct(
|
||||
string $preferred = self::PAYEE_PREFERRED_UNRESTRICTED,
|
||||
string $selected = self::PAYER_SELECTED_DEFAULT
|
||||
) {
|
||||
|
||||
$this->preferred = $preferred;
|
||||
$this->selected = $selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the payer preferred value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function payee_preferred(): string {
|
||||
return $this->preferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the payer selected value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function payer_selected(): string {
|
||||
return $this->selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'payee_preferred' => $this->payee_preferred(),
|
||||
'payer_selected' => $this->payer_selected(),
|
||||
);
|
||||
}
|
||||
}
|
115
modules/ppcp-api-client/src/Entity/PaymentPreferences.php
Normal file
115
modules/ppcp-api-client/src/Entity/PaymentPreferences.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
/**
|
||||
* The Payment Preferences object.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class PaymentPreferences
|
||||
*/
|
||||
class PaymentPreferences {
|
||||
|
||||
/**
|
||||
* Setup fee.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $setup_fee;
|
||||
|
||||
/**
|
||||
* Auto bill outstanding.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $auto_bill_outstanding;
|
||||
|
||||
/**
|
||||
* Setup fee failure action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $setup_fee_failure_action;
|
||||
|
||||
/**
|
||||
* Payment failure threshold.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $payment_failure_threshold;
|
||||
|
||||
/**
|
||||
* PaymentPreferences constructor.
|
||||
*
|
||||
* @param array $setup_fee Setup fee.
|
||||
* @param bool $auto_bill_outstanding Auto bill outstanding.
|
||||
* @param string $setup_fee_failure_action Setup fee failure action.
|
||||
* @param int $payment_failure_threshold payment failure threshold.
|
||||
*/
|
||||
public function __construct(
|
||||
array $setup_fee,
|
||||
bool $auto_bill_outstanding = true,
|
||||
string $setup_fee_failure_action = 'CONTINUE',
|
||||
int $payment_failure_threshold = 3
|
||||
) {
|
||||
|
||||
$this->setup_fee = $setup_fee;
|
||||
$this->auto_bill_outstanding = $auto_bill_outstanding;
|
||||
$this->setup_fee_failure_action = $setup_fee_failure_action;
|
||||
$this->payment_failure_threshold = $payment_failure_threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup fee.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function setup_fee(): array {
|
||||
return $this->setup_fee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto bill outstanding.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function auto_bill_outstanding(): bool {
|
||||
return $this->auto_bill_outstanding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup fee failure action.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function setup_fee_failure_action(): string {
|
||||
return $this->setup_fee_failure_action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment failure threshold.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function payment_failure_threshold(): int {
|
||||
return $this->payment_failure_threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Payment Preferences as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array():array {
|
||||
return array(
|
||||
'setup_fee' => $this->setup_fee(),
|
||||
'auto_bill_outstanding' => $this->auto_bill_outstanding(),
|
||||
'setup_fee_failure_action' => $this->setup_fee_failure_action(),
|
||||
'payment_failure_threshold' => $this->payment_failure_threshold(),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -28,13 +28,21 @@ class Payments {
|
|||
*/
|
||||
private $captures;
|
||||
|
||||
/**
|
||||
* The Refunds.
|
||||
*
|
||||
* @var Refund[]
|
||||
*/
|
||||
private $refunds;
|
||||
|
||||
/**
|
||||
* Payments constructor.
|
||||
*
|
||||
* @param array $authorizations The Authorizations.
|
||||
* @param array $captures The Captures.
|
||||
* @param array $refunds The Refunds.
|
||||
*/
|
||||
public function __construct( array $authorizations, array $captures ) {
|
||||
public function __construct( array $authorizations, array $captures, array $refunds = array() ) {
|
||||
foreach ( $authorizations as $key => $authorization ) {
|
||||
if ( is_a( $authorization, Authorization::class ) ) {
|
||||
continue;
|
||||
|
@ -47,8 +55,15 @@ class Payments {
|
|||
}
|
||||
unset( $captures[ $key ] );
|
||||
}
|
||||
foreach ( $refunds as $key => $refund ) {
|
||||
if ( is_a( $refund, Refund::class ) ) {
|
||||
continue;
|
||||
}
|
||||
unset( $refunds[ $key ] );
|
||||
}
|
||||
$this->authorizations = $authorizations;
|
||||
$this->captures = $captures;
|
||||
$this->refunds = $refunds;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,6 +85,12 @@ class Payments {
|
|||
},
|
||||
$this->captures()
|
||||
),
|
||||
'refunds' => array_map(
|
||||
static function ( Refund $refund ): array {
|
||||
return $refund->to_array();
|
||||
},
|
||||
$this->refunds()
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -90,4 +111,13 @@ class Payments {
|
|||
public function captures(): array {
|
||||
return $this->captures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Refunds.
|
||||
*
|
||||
* @return Refund[]
|
||||
**/
|
||||
public function refunds(): array {
|
||||
return $this->refunds;
|
||||
}
|
||||
}
|
||||
|
|
154
modules/ppcp-api-client/src/Entity/Plan.php
Normal file
154
modules/ppcp-api-client/src/Entity/Plan.php
Normal file
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
/**
|
||||
* The Plan object.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class Plan
|
||||
*/
|
||||
class Plan {
|
||||
|
||||
/**
|
||||
* Plan ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* Plan name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* Product ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $product_id;
|
||||
|
||||
/**
|
||||
* Billing cycles.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $billing_cycles;
|
||||
|
||||
/**
|
||||
* Payment preferences.
|
||||
*
|
||||
* @var PaymentPreferences
|
||||
*/
|
||||
private $payment_preferences;
|
||||
|
||||
/**
|
||||
* Plan status.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $status;
|
||||
|
||||
/**
|
||||
* Plan constructor.
|
||||
*
|
||||
* @param string $id Plan ID.
|
||||
* @param string $name Plan name.
|
||||
* @param string $product_id Product ID.
|
||||
* @param array $billing_cycles Billing cycles.
|
||||
* @param PaymentPreferences $payment_preferences Payment preferences.
|
||||
* @param string $status Plan status.
|
||||
*/
|
||||
public function __construct(
|
||||
string $id,
|
||||
string $name,
|
||||
string $product_id,
|
||||
array $billing_cycles,
|
||||
PaymentPreferences $payment_preferences,
|
||||
string $status = ''
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->product_id = $product_id;
|
||||
$this->billing_cycles = $billing_cycles;
|
||||
$this->payment_preferences = $payment_preferences;
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Plan ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function id(): string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Plan name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Product ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function product_id(): string {
|
||||
return $this->product_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Billing cycles.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function billing_cycles(): array {
|
||||
return $this->billing_cycles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Payment preferences.
|
||||
*
|
||||
* @return PaymentPreferences
|
||||
*/
|
||||
public function payment_preferences(): PaymentPreferences {
|
||||
return $this->payment_preferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Plan status.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function status(): string {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Plan as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array():array {
|
||||
return array(
|
||||
'id' => $this->id(),
|
||||
'name' => $this->name(),
|
||||
'product_id' => $this->product_id(),
|
||||
'billing_cycles' => $this->billing_cycles(),
|
||||
'payment_preferences' => $this->payment_preferences(),
|
||||
'status' => $this->status(),
|
||||
);
|
||||
}
|
||||
}
|
90
modules/ppcp-api-client/src/Entity/Product.php
Normal file
90
modules/ppcp-api-client/src/Entity/Product.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
/**
|
||||
* The Product object.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class Product
|
||||
*/
|
||||
class Product {
|
||||
|
||||
/**
|
||||
* Product ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* Product name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* Product description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* Product constructor.
|
||||
*
|
||||
* @param string $id Product ID.
|
||||
* @param string $name Product name.
|
||||
* @param string $description Product description.
|
||||
*/
|
||||
public function __construct( string $id, string $name, string $description = '' ) {
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function id(): string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product description.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function description(): string {
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() {
|
||||
return array(
|
||||
'id' => $this->id(),
|
||||
'name' => $this->name(),
|
||||
'description' => $this->description(),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\PurchaseUnitSanitizer;
|
||||
|
||||
/**
|
||||
* Class PurchaseUnit
|
||||
*/
|
||||
|
@ -49,13 +51,6 @@ class PurchaseUnit {
|
|||
*/
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* The Payee.
|
||||
*
|
||||
* @var Payee|null
|
||||
*/
|
||||
private $payee;
|
||||
|
||||
/**
|
||||
* The custom id.
|
||||
*
|
||||
|
@ -91,6 +86,13 @@ class PurchaseUnit {
|
|||
*/
|
||||
private $contains_physical_goods = false;
|
||||
|
||||
/**
|
||||
* The sanitizer for this purchase unit output.
|
||||
*
|
||||
* @var PurchaseUnitSanitizer|null
|
||||
*/
|
||||
private $sanitizer;
|
||||
|
||||
/**
|
||||
* PurchaseUnit constructor.
|
||||
*
|
||||
|
@ -99,7 +101,6 @@ class PurchaseUnit {
|
|||
* @param Shipping|null $shipping The Shipping.
|
||||
* @param string $reference_id The reference ID.
|
||||
* @param string $description The description.
|
||||
* @param Payee|null $payee The Payee.
|
||||
* @param string $custom_id The custom ID.
|
||||
* @param string $invoice_id The invoice ID.
|
||||
* @param string $soft_descriptor The soft descriptor.
|
||||
|
@ -111,7 +112,6 @@ class PurchaseUnit {
|
|||
Shipping $shipping = null,
|
||||
string $reference_id = 'default',
|
||||
string $description = '',
|
||||
Payee $payee = null,
|
||||
string $custom_id = '',
|
||||
string $invoice_id = '',
|
||||
string $soft_descriptor = '',
|
||||
|
@ -141,7 +141,6 @@ class PurchaseUnit {
|
|||
}
|
||||
)
|
||||
);
|
||||
$this->payee = $payee;
|
||||
$this->custom_id = $custom_id;
|
||||
$this->invoice_id = $invoice_id;
|
||||
$this->soft_descriptor = $soft_descriptor;
|
||||
|
@ -211,6 +210,25 @@ class PurchaseUnit {
|
|||
return $this->custom_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom ID.
|
||||
*
|
||||
* @param string $custom_id The value to set.
|
||||
*/
|
||||
public function set_custom_id( string $custom_id ): void {
|
||||
$this->custom_id = $custom_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sanitizer for this purchase unit output.
|
||||
*
|
||||
* @param PurchaseUnitSanitizer|null $sanitizer The sanitizer.
|
||||
* @return void
|
||||
*/
|
||||
public function set_sanitizer( ?PurchaseUnitSanitizer $sanitizer ) {
|
||||
$this->sanitizer = $sanitizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invoice id.
|
||||
*
|
||||
|
@ -229,15 +247,6 @@ class PurchaseUnit {
|
|||
return $this->soft_descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Payee.
|
||||
*
|
||||
* @return Payee|null
|
||||
*/
|
||||
public function payee() {
|
||||
return $this->payee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Payments.
|
||||
*
|
||||
|
@ -268,11 +277,12 @@ class PurchaseUnit {
|
|||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @param bool $ditch_items_when_mismatch Whether ditch items when mismatch or not.
|
||||
* @param bool $sanitize_output Whether output should be sanitized for PayPal consumption.
|
||||
* @param bool $allow_ditch_items Whether to allow items to be ditched.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array( bool $ditch_items_when_mismatch = true ): array {
|
||||
public function to_array( bool $sanitize_output = true, bool $allow_ditch_items = true ): array {
|
||||
$purchase_unit = array(
|
||||
'reference_id' => $this->reference_id(),
|
||||
'amount' => $this->amount()->to_array(),
|
||||
|
@ -284,14 +294,6 @@ class PurchaseUnit {
|
|||
$this->items()
|
||||
),
|
||||
);
|
||||
if ( $ditch_items_when_mismatch && $this->ditch_items_when_mismatch( $this->amount(), ...$this->items() ) ) {
|
||||
unset( $purchase_unit['items'] );
|
||||
unset( $purchase_unit['amount']['breakdown'] );
|
||||
}
|
||||
|
||||
if ( $this->payee() ) {
|
||||
$purchase_unit['payee'] = $this->payee()->to_array();
|
||||
}
|
||||
|
||||
if ( $this->payments() ) {
|
||||
$purchase_unit['payments'] = $this->payments()->to_array();
|
||||
|
@ -309,101 +311,45 @@ class PurchaseUnit {
|
|||
if ( $this->soft_descriptor() ) {
|
||||
$purchase_unit['soft_descriptor'] = $this->soft_descriptor();
|
||||
}
|
||||
return $purchase_unit;
|
||||
|
||||
$has_ditched_items_breakdown = false;
|
||||
|
||||
if ( $sanitize_output && isset( $this->sanitizer ) ) {
|
||||
$purchase_unit = ( $this->sanitizer->sanitize( $purchase_unit, $allow_ditch_items ) );
|
||||
$has_ditched_items_breakdown = $this->sanitizer->has_ditched_items_breakdown();
|
||||
}
|
||||
|
||||
return $this->apply_ditch_items_mismatch_filter(
|
||||
$has_ditched_items_breakdown,
|
||||
$purchase_unit
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* All money values send to PayPal can only have 2 decimal points. WooCommerce internally does
|
||||
* not have this restriction. Therefore the totals of the cart in WooCommerce and the totals
|
||||
* of the rounded money values of the items, we send to PayPal, can differ. In those cases,
|
||||
* we can not send the line items.
|
||||
* Applies the ppcp_ditch_items_breakdown filter.
|
||||
* If true purchase_unit items and breakdown are ditched from PayPal.
|
||||
*
|
||||
* @param Amount $amount The amount.
|
||||
* @param Item ...$items The items.
|
||||
* @return bool
|
||||
* @param bool $ditched_items_breakdown If the breakdown and items were already ditched.
|
||||
* @param array $purchase_unit The purchase_unit array.
|
||||
* @return array
|
||||
*/
|
||||
private function ditch_items_when_mismatch( Amount $amount, Item ...$items ): bool {
|
||||
$breakdown = $amount->breakdown();
|
||||
if ( ! $breakdown ) {
|
||||
return false;
|
||||
}
|
||||
public function apply_ditch_items_mismatch_filter( bool $ditched_items_breakdown, array $purchase_unit ): array {
|
||||
/**
|
||||
* The filter can be used to control when the items and totals breakdown are removed from PayPal order info.
|
||||
*/
|
||||
$ditch = apply_filters( 'ppcp_ditch_items_breakdown', $ditched_items_breakdown, $this );
|
||||
|
||||
$item_total = $breakdown->item_total();
|
||||
if ( $item_total ) {
|
||||
$remaining_item_total = array_reduce(
|
||||
$items,
|
||||
function ( float $total, Item $item ): float {
|
||||
return $total - (float) $item->unit_amount()->value_str() * (float) $item->quantity();
|
||||
},
|
||||
(float) $item_total->value_str()
|
||||
if ( $ditch ) {
|
||||
unset( $purchase_unit['items'] );
|
||||
unset( $purchase_unit['amount']['breakdown'] );
|
||||
|
||||
if ( isset( $this->sanitizer ) && ( $ditch !== $ditched_items_breakdown ) ) {
|
||||
$this->sanitizer->set_last_message(
|
||||
__( 'Ditch items breakdown filter. Items and breakdown ditched.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
|
||||
$remaining_item_total = round( $remaining_item_total, 2 );
|
||||
|
||||
if ( 0.0 !== $remaining_item_total ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$tax_total = $breakdown->tax_total();
|
||||
$items_with_tax = array_filter(
|
||||
$this->items,
|
||||
function ( Item $item ): bool {
|
||||
return null !== $item->tax();
|
||||
}
|
||||
);
|
||||
if ( $tax_total && ! empty( $items_with_tax ) ) {
|
||||
$remaining_tax_total = array_reduce(
|
||||
$items,
|
||||
function ( float $total, Item $item ): float {
|
||||
$tax = $item->tax();
|
||||
if ( $tax ) {
|
||||
$total -= (float) $tax->value_str() * (float) $item->quantity();
|
||||
}
|
||||
return $total;
|
||||
},
|
||||
(float) $tax_total->value_str()
|
||||
);
|
||||
|
||||
$remaining_tax_total = round( $remaining_tax_total, 2 );
|
||||
|
||||
if ( 0.0 !== $remaining_tax_total ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$shipping = $breakdown->shipping();
|
||||
$discount = $breakdown->discount();
|
||||
$shipping_discount = $breakdown->shipping_discount();
|
||||
$handling = $breakdown->handling();
|
||||
$insurance = $breakdown->insurance();
|
||||
|
||||
$amount_total = 0.0;
|
||||
if ( $shipping ) {
|
||||
$amount_total += (float) $shipping->value_str();
|
||||
}
|
||||
if ( $item_total ) {
|
||||
$amount_total += (float) $item_total->value_str();
|
||||
}
|
||||
if ( $discount ) {
|
||||
$amount_total -= (float) $discount->value_str();
|
||||
}
|
||||
if ( $tax_total ) {
|
||||
$amount_total += (float) $tax_total->value_str();
|
||||
}
|
||||
if ( $shipping_discount ) {
|
||||
$amount_total -= (float) $shipping_discount->value_str();
|
||||
}
|
||||
if ( $handling ) {
|
||||
$amount_total += (float) $handling->value_str();
|
||||
}
|
||||
if ( $insurance ) {
|
||||
$amount_total += (float) $insurance->value_str();
|
||||
}
|
||||
|
||||
$amount_str = $amount->value_str();
|
||||
$amount_total_str = ( new Money( $amount_total, $amount->currency_code() ) )->value_str();
|
||||
$needs_to_ditch = $amount_str !== $amount_total_str;
|
||||
return $needs_to_ditch;
|
||||
return $purchase_unit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
/**
|
||||
* The refund object.
|
||||
* The refund entity.
|
||||
*
|
||||
* @link https://developer.paypal.com/docs/api/orders/v2/#definition-refund
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
@ -15,11 +17,32 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
|||
class Refund {
|
||||
|
||||
/**
|
||||
* The Capture.
|
||||
* The ID.
|
||||
*
|
||||
* @var Capture
|
||||
* @var string
|
||||
*/
|
||||
private $capture;
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* The status.
|
||||
*
|
||||
* @var RefundStatus
|
||||
*/
|
||||
private $status;
|
||||
|
||||
/**
|
||||
* The amount.
|
||||
*
|
||||
* @var Amount
|
||||
*/
|
||||
private $amount;
|
||||
|
||||
/**
|
||||
* The detailed breakdown of the refund activity (fees, ...).
|
||||
*
|
||||
* @var SellerPayableBreakdown|null
|
||||
*/
|
||||
private $seller_payable_breakdown;
|
||||
|
||||
/**
|
||||
* The invoice id.
|
||||
|
@ -29,50 +52,97 @@ class Refund {
|
|||
private $invoice_id;
|
||||
|
||||
/**
|
||||
* The note to the payer.
|
||||
* The custom id.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $custom_id;
|
||||
|
||||
/**
|
||||
* The acquirer reference number.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $acquirer_reference_number;
|
||||
|
||||
/**
|
||||
* The acquirer reference number.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $note_to_payer;
|
||||
|
||||
/**
|
||||
* The Amount.
|
||||
* The payer of the refund.
|
||||
*
|
||||
* @var Amount|null
|
||||
* @var ?RefundPayer
|
||||
*/
|
||||
private $amount;
|
||||
private $payer;
|
||||
|
||||
/**
|
||||
* Refund constructor.
|
||||
*
|
||||
* @param Capture $capture The capture where the refund is supposed to be applied at.
|
||||
* @param string $id The ID.
|
||||
* @param RefundStatus $status The status.
|
||||
* @param Amount $amount The amount.
|
||||
* @param string $invoice_id The invoice id.
|
||||
* @param string $note_to_payer The note to the payer.
|
||||
* @param Amount|null $amount The Amount.
|
||||
* @param string $custom_id The custom id.
|
||||
* @param SellerPayableBreakdown|null $seller_payable_breakdown The detailed breakdown of the refund activity (fees, ...).
|
||||
* @param string $acquirer_reference_number The acquirer reference number.
|
||||
* @param string $note_to_payer The note to payer.
|
||||
* @param RefundPayer|null $payer The payer.
|
||||
*/
|
||||
public function __construct(
|
||||
Capture $capture,
|
||||
string $id,
|
||||
RefundStatus $status,
|
||||
Amount $amount,
|
||||
string $invoice_id,
|
||||
string $note_to_payer = '',
|
||||
Amount $amount = null
|
||||
string $custom_id,
|
||||
?SellerPayableBreakdown $seller_payable_breakdown,
|
||||
string $acquirer_reference_number,
|
||||
string $note_to_payer,
|
||||
?RefundPayer $payer
|
||||
) {
|
||||
$this->capture = $capture;
|
||||
$this->invoice_id = $invoice_id;
|
||||
$this->note_to_payer = $note_to_payer;
|
||||
$this->id = $id;
|
||||
$this->status = $status;
|
||||
$this->amount = $amount;
|
||||
$this->invoice_id = $invoice_id;
|
||||
$this->custom_id = $custom_id;
|
||||
$this->seller_payable_breakdown = $seller_payable_breakdown;
|
||||
$this->acquirer_reference_number = $acquirer_reference_number;
|
||||
$this->note_to_payer = $note_to_payer;
|
||||
$this->payer = $payer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the capture for the refund.
|
||||
* Returns the ID.
|
||||
*
|
||||
* @return Capture
|
||||
* @return string
|
||||
*/
|
||||
public function for_capture() : Capture {
|
||||
return $this->capture;
|
||||
public function id() : string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the invoice id.
|
||||
* Returns the status.
|
||||
*
|
||||
* @return RefundStatus
|
||||
*/
|
||||
public function status() : RefundStatus {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount.
|
||||
*
|
||||
* @return Amount
|
||||
*/
|
||||
public function amount() : Amount {
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invoice id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
@ -81,7 +151,34 @@ class Refund {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the note to the payer.
|
||||
* Returns the custom id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function custom_id() : string {
|
||||
return $this->custom_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the detailed breakdown of the refund activity (fees, ...).
|
||||
*
|
||||
* @return SellerPayableBreakdown|null
|
||||
*/
|
||||
public function seller_payable_breakdown() : ?SellerPayableBreakdown {
|
||||
return $this->seller_payable_breakdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* The acquirer reference number.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function acquirer_reference_number() : string {
|
||||
return $this->acquirer_reference_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* The note to payer.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
@ -90,28 +187,38 @@ class Refund {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the Amount.
|
||||
* Returns the refund payer.
|
||||
*
|
||||
* @return Amount|null
|
||||
* @return RefundPayer|null
|
||||
*/
|
||||
public function amount() {
|
||||
return $this->amount;
|
||||
public function payer() : ?RefundPayer {
|
||||
return $this->payer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
* Returns the entity as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() : array {
|
||||
$data = array(
|
||||
'id' => $this->id(),
|
||||
'status' => $this->status()->name(),
|
||||
'amount' => $this->amount()->to_array(),
|
||||
'invoice_id' => $this->invoice_id(),
|
||||
'custom_id' => $this->custom_id(),
|
||||
'acquirer_reference_number' => $this->acquirer_reference_number(),
|
||||
'note_to_payer' => (array) $this->note_to_payer(),
|
||||
);
|
||||
if ( $this->note_to_payer() ) {
|
||||
$data['note_to_payer'] = $this->note_to_payer();
|
||||
$details = $this->status()->details();
|
||||
if ( $details ) {
|
||||
$data['status_details'] = array( 'reason' => $details->reason() );
|
||||
}
|
||||
if ( $this->amount() ) {
|
||||
$data['amount'] = $this->amount()->to_array();
|
||||
if ( $this->seller_payable_breakdown ) {
|
||||
$data['seller_payable_breakdown'] = $this->seller_payable_breakdown->to_array();
|
||||
}
|
||||
if ( $this->payer ) {
|
||||
$data['payer'] = $this->payer->to_array();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
|
118
modules/ppcp-api-client/src/Entity/RefundCapture.php
Normal file
118
modules/ppcp-api-client/src/Entity/RefundCapture.php
Normal file
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
/**
|
||||
* The refund capture object.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class RefundCapture
|
||||
*/
|
||||
class RefundCapture {
|
||||
|
||||
/**
|
||||
* The Capture.
|
||||
*
|
||||
* @var Capture
|
||||
*/
|
||||
private $capture;
|
||||
|
||||
/**
|
||||
* The invoice id.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $invoice_id;
|
||||
|
||||
/**
|
||||
* The note to the payer.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $note_to_payer;
|
||||
|
||||
/**
|
||||
* The Amount.
|
||||
*
|
||||
* @var Amount|null
|
||||
*/
|
||||
private $amount;
|
||||
|
||||
/**
|
||||
* Refund constructor.
|
||||
*
|
||||
* @param Capture $capture The capture where the refund is supposed to be applied at.
|
||||
* @param string $invoice_id The invoice id.
|
||||
* @param string $note_to_payer The note to the payer.
|
||||
* @param Amount|null $amount The Amount.
|
||||
*/
|
||||
public function __construct(
|
||||
Capture $capture,
|
||||
string $invoice_id,
|
||||
string $note_to_payer = '',
|
||||
Amount $amount = null
|
||||
) {
|
||||
$this->capture = $capture;
|
||||
$this->invoice_id = $invoice_id;
|
||||
$this->note_to_payer = $note_to_payer;
|
||||
$this->amount = $amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the capture for the refund.
|
||||
*
|
||||
* @return Capture
|
||||
*/
|
||||
public function for_capture() : Capture {
|
||||
return $this->capture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the invoice id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function invoice_id() : string {
|
||||
return $this->invoice_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the note to the payer.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function note_to_payer() : string {
|
||||
return $this->note_to_payer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Amount.
|
||||
*
|
||||
* @return Amount|null
|
||||
*/
|
||||
public function amount() {
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() : array {
|
||||
$data = array(
|
||||
'invoice_id' => $this->invoice_id(),
|
||||
);
|
||||
if ( $this->note_to_payer() ) {
|
||||
$data['note_to_payer'] = $this->note_to_payer();
|
||||
}
|
||||
if ( $this->amount ) {
|
||||
$data['amount'] = $this->amount->to_array();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
79
modules/ppcp-api-client/src/Entity/RefundPayer.php
Normal file
79
modules/ppcp-api-client/src/Entity/RefundPayer.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
/**
|
||||
* The refund payer object.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class RefundPayer
|
||||
* The customer who sends the money.
|
||||
*/
|
||||
class RefundPayer {
|
||||
|
||||
/**
|
||||
* The email address.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $email_address;
|
||||
|
||||
/**
|
||||
* The merchant id.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $merchant_id;
|
||||
|
||||
/**
|
||||
* RefundPayer constructor.
|
||||
*
|
||||
* @param string $email_address The email.
|
||||
* @param string $merchant_id The merchant id.
|
||||
*/
|
||||
public function __construct(
|
||||
string $email_address,
|
||||
string $merchant_id
|
||||
) {
|
||||
|
||||
$this->email_address = $email_address;
|
||||
$this->merchant_id = $merchant_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the email address.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function email_address(): string {
|
||||
return $this->email_address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the merchant id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function merchant_id(): string {
|
||||
return $this->merchant_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() {
|
||||
$payer = array(
|
||||
'email_address' => $this->email_address(),
|
||||
);
|
||||
if ( $this->merchant_id ) {
|
||||
$payer['merchant_id'] = $this->merchant_id();
|
||||
}
|
||||
return $payer;
|
||||
}
|
||||
}
|
77
modules/ppcp-api-client/src/Entity/RefundStatus.php
Normal file
77
modules/ppcp-api-client/src/Entity/RefundStatus.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
/**
|
||||
* The RefundStatus object.
|
||||
*
|
||||
* @see https://developer.paypal.com/docs/api/orders/v2/#definition-refund_status
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class RefundStatus
|
||||
*/
|
||||
class RefundStatus {
|
||||
|
||||
const COMPLETED = 'COMPLETED';
|
||||
const CANCELLED = 'CANCELLED';
|
||||
const FAILED = 'FAILED';
|
||||
const PENDING = 'PENDING';
|
||||
|
||||
/**
|
||||
* The status.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $status;
|
||||
|
||||
/**
|
||||
* The details.
|
||||
*
|
||||
* @var RefundStatusDetails|null
|
||||
*/
|
||||
private $details;
|
||||
|
||||
/**
|
||||
* RefundStatus constructor.
|
||||
*
|
||||
* @param string $status The status.
|
||||
* @param RefundStatusDetails|null $details The details.
|
||||
*/
|
||||
public function __construct( string $status, ?RefundStatusDetails $details = null ) {
|
||||
$this->status = $status;
|
||||
$this->details = $details;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the current status with a given one.
|
||||
*
|
||||
* @param string $status The status to compare with.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is( string $status ): bool {
|
||||
return $this->status === $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name(): string {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the details.
|
||||
*
|
||||
* @return RefundStatusDetails|null
|
||||
*/
|
||||
public function details(): ?RefundStatusDetails {
|
||||
return $this->details;
|
||||
}
|
||||
}
|
71
modules/ppcp-api-client/src/Entity/RefundStatusDetails.php
Normal file
71
modules/ppcp-api-client/src/Entity/RefundStatusDetails.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
/**
|
||||
* The RefundStatusDetails object.
|
||||
*
|
||||
* @see https://developer.paypal.com/docs/api/payments/v2/#definition-refund_status_details
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class RefundStatusDetails
|
||||
*/
|
||||
class RefundStatusDetails {
|
||||
|
||||
const ECHECK = 'ECHECK';
|
||||
|
||||
/**
|
||||
* The reason.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $reason;
|
||||
|
||||
/**
|
||||
* RefundStatusDetails constructor.
|
||||
*
|
||||
* @param string $reason The reason explaining refund status.
|
||||
*/
|
||||
public function __construct( string $reason ) {
|
||||
$this->reason = $reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the current reason with a given one.
|
||||
*
|
||||
* @param string $reason The reason to compare with.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is( string $reason ): bool {
|
||||
return $this->reason === $reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reason explaining refund status.
|
||||
* One of RefundStatusDetails constants.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function reason(): string {
|
||||
return $this->reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the human-readable reason text explaining refund status.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function text(): string {
|
||||
switch ( $this->reason ) {
|
||||
case self::ECHECK:
|
||||
return __( 'The payer paid by an eCheck that has not yet cleared.', 'woocommerce-paypal-payments' );
|
||||
default:
|
||||
return $this->reason;
|
||||
}
|
||||
}
|
||||
}
|
202
modules/ppcp-api-client/src/Entity/SellerPayableBreakdown.php
Normal file
202
modules/ppcp-api-client/src/Entity/SellerPayableBreakdown.php
Normal file
|
@ -0,0 +1,202 @@
|
|||
<?php
|
||||
/**
|
||||
* The info about fees and amount that will be paid by the seller.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class SellerPayableBreakdown
|
||||
*/
|
||||
class SellerPayableBreakdown {
|
||||
|
||||
/**
|
||||
* The amount for this refunded payment in the currency of the transaction.
|
||||
*
|
||||
* @var Money|null
|
||||
*/
|
||||
private $gross_amount;
|
||||
|
||||
/**
|
||||
* The applicable fee for this refunded payment in the currency of the transaction.
|
||||
*
|
||||
* @var Money|null
|
||||
*/
|
||||
private $paypal_fee;
|
||||
|
||||
/**
|
||||
* The applicable fee for this captured payment in the receivable currency.
|
||||
*
|
||||
* Present only in cases the fee is charged in the receivable currency.
|
||||
*
|
||||
* @var Money|null
|
||||
*/
|
||||
private $paypal_fee_in_receivable_currency;
|
||||
|
||||
/**
|
||||
* The net amount that the payee receives for this refunded payment in their PayPal account.
|
||||
*
|
||||
* Computed as gross_amount minus the paypal_fee minus the platform_fees.
|
||||
*
|
||||
* @var Money|null
|
||||
*/
|
||||
private $net_amount;
|
||||
|
||||
/**
|
||||
* The net amount for this refunded payment in the receivable currency.
|
||||
*
|
||||
* @var Money|null
|
||||
*/
|
||||
private $net_amount_in_receivable_currency;
|
||||
|
||||
/**
|
||||
* The total amount for this refund.
|
||||
*
|
||||
* @var Money|null
|
||||
*/
|
||||
private $total_refunded_amount;
|
||||
|
||||
/**
|
||||
* An array of platform or partner fees, commissions, or brokerage fees that associated with the captured payment.
|
||||
*
|
||||
* @var PlatformFee[]
|
||||
*/
|
||||
private $platform_fees;
|
||||
|
||||
/**
|
||||
* SellerPayableBreakdown constructor.
|
||||
*
|
||||
* @param Money|null $gross_amount The amount for this refunded payment in the currency of the transaction.
|
||||
* @param Money|null $paypal_fee The applicable fee for this refunded payment in the currency of the transaction.
|
||||
* @param Money|null $paypal_fee_in_receivable_currency The applicable fee for this refunded payment in the receivable currency.
|
||||
* @param Money|null $net_amount The net amount that the payee receives for this refunded payment in their PayPal account.
|
||||
* @param Money|null $net_amount_in_receivable_currency The net amount for this refunded payment in the receivable currency.
|
||||
* @param Money|null $total_refunded_amount The total amount for this refund.
|
||||
* @param PlatformFee[] $platform_fees An array of platform or partner fees, commissions, or brokerage fees that associated with the captured payment.
|
||||
*/
|
||||
public function __construct(
|
||||
?Money $gross_amount,
|
||||
?Money $paypal_fee,
|
||||
?Money $paypal_fee_in_receivable_currency,
|
||||
?Money $net_amount,
|
||||
?Money $net_amount_in_receivable_currency,
|
||||
?Money $total_refunded_amount,
|
||||
array $platform_fees
|
||||
) {
|
||||
$this->gross_amount = $gross_amount;
|
||||
$this->paypal_fee = $paypal_fee;
|
||||
$this->paypal_fee_in_receivable_currency = $paypal_fee_in_receivable_currency;
|
||||
$this->net_amount = $net_amount;
|
||||
$this->net_amount_in_receivable_currency = $net_amount_in_receivable_currency;
|
||||
$this->total_refunded_amount = $total_refunded_amount;
|
||||
$this->platform_fees = $platform_fees;
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount for this refunded payment in the currency of the transaction.
|
||||
*
|
||||
* @return Money|null
|
||||
*/
|
||||
public function gross_amount(): ?Money {
|
||||
return $this->gross_amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* The applicable fee for this refunded payment in the currency of the transaction.
|
||||
*
|
||||
* @return Money|null
|
||||
*/
|
||||
public function paypal_fee(): ?Money {
|
||||
return $this->paypal_fee;
|
||||
}
|
||||
|
||||
/**
|
||||
* The applicable fee for this refunded payment in the receivable currency.
|
||||
*
|
||||
* Present only in cases the fee is charged in the receivable currency.
|
||||
*
|
||||
* @return Money|null
|
||||
*/
|
||||
public function paypal_fee_in_receivable_currency(): ?Money {
|
||||
return $this->paypal_fee_in_receivable_currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* The net amount that the payee receives for this refunded payment in their PayPal account.
|
||||
*
|
||||
* Computed as gross_amount minus the paypal_fee minus the platform_fees.
|
||||
*
|
||||
* @return Money|null
|
||||
*/
|
||||
public function net_amount(): ?Money {
|
||||
return $this->net_amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* The net amount for this refunded payment in the receivable currency.
|
||||
*
|
||||
* @return Money|null
|
||||
*/
|
||||
public function net_amount_in_receivable_currency(): ?Money {
|
||||
return $this->net_amount_in_receivable_currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total amount for this refund.
|
||||
*
|
||||
* @return Money|null
|
||||
*/
|
||||
public function total_refunded_amount(): ?Money {
|
||||
return $this->total_refunded_amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of platform or partner fees, commissions, or brokerage fees that associated with the refunded payment.
|
||||
*
|
||||
* @return PlatformFee[]
|
||||
*/
|
||||
public function platform_fees(): array {
|
||||
return $this->platform_fees;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
$data = array();
|
||||
if ( $this->gross_amount ) {
|
||||
$data['gross_amount'] = $this->gross_amount->to_array();
|
||||
}
|
||||
if ( $this->paypal_fee ) {
|
||||
$data['paypal_fee'] = $this->paypal_fee->to_array();
|
||||
}
|
||||
if ( $this->paypal_fee_in_receivable_currency ) {
|
||||
$data['paypal_fee_in_receivable_currency'] = $this->paypal_fee_in_receivable_currency->to_array();
|
||||
}
|
||||
if ( $this->net_amount ) {
|
||||
$data['net_amount'] = $this->net_amount->to_array();
|
||||
}
|
||||
if ( $this->net_amount_in_receivable_currency ) {
|
||||
$data['net_amount_in_receivable_currency'] = $this->net_amount_in_receivable_currency->to_array();
|
||||
}
|
||||
if ( $this->total_refunded_amount ) {
|
||||
$data['total_refunded_amount'] = $this->total_refunded_amount->to_array();
|
||||
}
|
||||
if ( $this->platform_fees ) {
|
||||
$data['platform_fees'] = array_map(
|
||||
function ( PlatformFee $fee ) {
|
||||
return $fee->to_array();
|
||||
},
|
||||
$this->platform_fees
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
|
@ -28,15 +28,24 @@ class Shipping {
|
|||
*/
|
||||
private $address;
|
||||
|
||||
/**
|
||||
* Shipping methods.
|
||||
*
|
||||
* @var ShippingOption[]
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Shipping constructor.
|
||||
*
|
||||
* @param string $name The name.
|
||||
* @param Address $address The address.
|
||||
* @param ShippingOption[] $options Shipping methods.
|
||||
*/
|
||||
public function __construct( string $name, Address $address ) {
|
||||
public function __construct( string $name, Address $address, array $options = array() ) {
|
||||
$this->name = $name;
|
||||
$this->address = $address;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,17 +66,35 @@ class Shipping {
|
|||
return $this->address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shipping methods.
|
||||
*
|
||||
* @return ShippingOption[]
|
||||
*/
|
||||
public function options(): array {
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
$result = array(
|
||||
'name' => array(
|
||||
'full_name' => $this->name(),
|
||||
),
|
||||
'address' => $this->address()->to_array(),
|
||||
);
|
||||
if ( $this->options ) {
|
||||
$result['options'] = array_map(
|
||||
function ( ShippingOption $opt ): array {
|
||||
return $opt->to_array();
|
||||
},
|
||||
$this->options
|
||||
);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
|
139
modules/ppcp-api-client/src/Entity/ShippingOption.php
Normal file
139
modules/ppcp-api-client/src/Entity/ShippingOption.php
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
/**
|
||||
* The ShippingOption object.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class ShippingOption
|
||||
*/
|
||||
class ShippingOption {
|
||||
const TYPE_SHIPPING = 'SHIPPING';
|
||||
const TYPE_PICKUP = 'PICKUP';
|
||||
|
||||
/**
|
||||
* The name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* The label.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $label;
|
||||
|
||||
/**
|
||||
* Whether the method is selected by default.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $selected;
|
||||
|
||||
/**
|
||||
* The price.
|
||||
*
|
||||
* @var Money
|
||||
*/
|
||||
private $amount;
|
||||
|
||||
/**
|
||||
* SHIPPING or PICKUP.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* ShippingOption constructor.
|
||||
*
|
||||
* @param string $id The name.
|
||||
* @param string $label The label.
|
||||
* @param bool $selected Whether the method is selected by default.
|
||||
* @param Money $amount The price.
|
||||
* @param string $type SHIPPING or PICKUP.
|
||||
*/
|
||||
public function __construct( string $id, string $label, bool $selected, Money $amount, string $type ) {
|
||||
$this->id = $id;
|
||||
$this->label = $label;
|
||||
$this->selected = $selected;
|
||||
$this->amount = $amount;
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function id(): string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* The label.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function label(): string {
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the method is selected by default.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function selected(): bool {
|
||||
return $this->selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the method is selected by default.
|
||||
*
|
||||
* @param bool $selected The value to be set.
|
||||
*/
|
||||
public function set_selected( bool $selected ): void {
|
||||
$this->selected = $selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* The price.
|
||||
*
|
||||
* @return Money
|
||||
*/
|
||||
public function amount(): Money {
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* SHIPPING or PICKUP.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function type(): string {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'id' => $this->id,
|
||||
'label' => $this->label,
|
||||
'selected' => $this->selected,
|
||||
'amount' => $this->amount->to_array(),
|
||||
'type' => $this->type,
|
||||
);
|
||||
}
|
||||
}
|
84
modules/ppcp-api-client/src/Factory/BillingCycleFactory.php
Normal file
84
modules/ppcp-api-client/src/Factory/BillingCycleFactory.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
/**
|
||||
* The Billing Cycle factory.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use stdClass;
|
||||
use WC_Product;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\BillingCycle;
|
||||
|
||||
/**
|
||||
* Class BillingCycleFactory
|
||||
*/
|
||||
class BillingCycleFactory {
|
||||
|
||||
/**
|
||||
* The currency.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $currency;
|
||||
|
||||
/**
|
||||
* BillingCycleFactory constructor.
|
||||
*
|
||||
* @param string $currency The currency.
|
||||
*/
|
||||
public function __construct( string $currency ) {
|
||||
$this->currency = $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BillingCycle object from the given WC product.
|
||||
*
|
||||
* @param WC_Product $product WC product.
|
||||
* @return BillingCycle
|
||||
*/
|
||||
public function from_wc_product( WC_Product $product ): BillingCycle {
|
||||
return new BillingCycle(
|
||||
array(
|
||||
'interval_unit' => $product->get_meta( '_subscription_period' ),
|
||||
'interval_count' => $product->get_meta( '_subscription_period_interval' ),
|
||||
),
|
||||
1,
|
||||
'REGULAR',
|
||||
array(
|
||||
'fixed_price' => array(
|
||||
'value' => $product->get_meta( '_subscription_price' ),
|
||||
'currency_code' => $this->currency,
|
||||
),
|
||||
),
|
||||
(int) $product->get_meta( '_subscription_length' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BillingCycle object based off a PayPal response.
|
||||
*
|
||||
* @param stdClass $data the data.
|
||||
* @return BillingCycle
|
||||
*/
|
||||
public function from_paypal_response( stdClass $data ): BillingCycle {
|
||||
return new BillingCycle(
|
||||
array(
|
||||
'interval_unit' => $data->frequency->interval_unit,
|
||||
'interval_count' => $data->frequency->interval_count,
|
||||
),
|
||||
$data->sequence,
|
||||
$data->tenure_type,
|
||||
array(
|
||||
'fixed_price' => array(
|
||||
'value' => $data->pricing_scheme->fixed_price->value,
|
||||
'currency_code' => $data->pricing_scheme->fixed_price->currency_code,
|
||||
),
|
||||
),
|
||||
$data->total_cycles
|
||||
);
|
||||
}
|
||||
}
|
|
@ -13,11 +13,15 @@ use WC_Product;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\ItemTrait;
|
||||
|
||||
/**
|
||||
* Class ItemFactory
|
||||
*/
|
||||
class ItemFactory {
|
||||
|
||||
use ItemTrait;
|
||||
|
||||
/**
|
||||
* 3-letter currency code of the shop.
|
||||
*
|
||||
|
@ -45,6 +49,7 @@ class ItemFactory {
|
|||
$items = array_map(
|
||||
function ( array $item ): Item {
|
||||
$product = $item['data'];
|
||||
$cart_item_key = $item['key'] ?? null;
|
||||
|
||||
/**
|
||||
* The WooCommerce product.
|
||||
|
@ -52,16 +57,21 @@ class ItemFactory {
|
|||
* @var \WC_Product $product
|
||||
*/
|
||||
$quantity = (int) $item['quantity'];
|
||||
$image = wp_get_attachment_image_src( (int) $product->get_image_id(), 'full' );
|
||||
|
||||
$price = (float) $item['line_subtotal'] / (float) $item['quantity'];
|
||||
return new Item(
|
||||
mb_substr( $product->get_name(), 0, 127 ),
|
||||
new Money( $price, $this->currency ),
|
||||
$quantity,
|
||||
substr( wp_strip_all_tags( $product->get_description() ), 0, 127 ) ?: '',
|
||||
$this->prepare_description( $product->get_description() ),
|
||||
null,
|
||||
$product->get_sku(),
|
||||
( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS
|
||||
( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS,
|
||||
$product->get_permalink(),
|
||||
$image[0] ?? '',
|
||||
0,
|
||||
$cart_item_key
|
||||
);
|
||||
},
|
||||
$cart->get_cart_contents()
|
||||
|
@ -125,15 +135,18 @@ class ItemFactory {
|
|||
$quantity = (int) $item->get_quantity();
|
||||
$price_without_tax = (float) $order->get_item_subtotal( $item, false );
|
||||
$price_without_tax_rounded = round( $price_without_tax, 2 );
|
||||
$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 ),
|
||||
new Money( $price_without_tax_rounded, $currency ),
|
||||
$quantity,
|
||||
substr( wp_strip_all_tags( $product instanceof WC_Product ? $product->get_description() : '' ), 0, 127 ) ?: '',
|
||||
$product instanceof WC_Product ? $this->prepare_description( $product->get_description() ) : '',
|
||||
null,
|
||||
$product instanceof WC_Product ? $product->get_sku() : '',
|
||||
( $product instanceof WC_Product && $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS
|
||||
( $product instanceof WC_Product && $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS,
|
||||
$product instanceof WC_Product ? $product->get_permalink() : '',
|
||||
$image[0] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -187,6 +200,8 @@ class ItemFactory {
|
|||
: null;
|
||||
$sku = ( isset( $data->sku ) ) ? $data->sku : '';
|
||||
$category = ( isset( $data->category ) ) ? $data->category : 'PHYSICAL_GOODS';
|
||||
$url = ( isset( $data->url ) ) ? $data->url : '';
|
||||
$image_url = ( isset( $data->image_url ) ) ? $data->image_url : '';
|
||||
|
||||
return new Item(
|
||||
$data->name,
|
||||
|
@ -195,7 +210,9 @@ class ItemFactory {
|
|||
$description,
|
||||
$tax,
|
||||
$sku,
|
||||
$category
|
||||
$category,
|
||||
$url,
|
||||
$image_url
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,14 @@ class PatchCollectionFactory {
|
|||
);
|
||||
$operation = $purchase_unit_from ? 'replace' : 'add';
|
||||
$value = $purchase_unit_to->to_array();
|
||||
|
||||
if ( ! isset( $value['shipping'] ) ) {
|
||||
$shipping = $purchase_unit_from && null !== $purchase_unit_from->shipping() ? $purchase_unit_from->shipping() : null;
|
||||
if ( $shipping ) {
|
||||
$value['shipping'] = $shipping->to_array();
|
||||
}
|
||||
}
|
||||
|
||||
$patches[] = new Patch(
|
||||
$operation,
|
||||
$path . "/@reference_id=='" . $purchase_unit_to->reference_id() . "'",
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
/**
|
||||
* The Payment Preferences factory.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use stdClass;
|
||||
use WC_Product;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentPreferences;
|
||||
|
||||
/**
|
||||
* Class PaymentPreferencesFactory
|
||||
*/
|
||||
class PaymentPreferencesFactory {
|
||||
|
||||
/**
|
||||
* The currency.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $currency;
|
||||
|
||||
/**
|
||||
* PaymentPreferencesFactory constructor.
|
||||
*
|
||||
* @param string $currency The currency.
|
||||
*/
|
||||
public function __construct( string $currency ) {
|
||||
$this->currency = $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PaymentPreferences object from the given WC product.
|
||||
*
|
||||
* @param WC_Product $product WC product.
|
||||
* @return PaymentPreferences
|
||||
*/
|
||||
public function from_wc_product( WC_Product $product ):PaymentPreferences {
|
||||
return new PaymentPreferences(
|
||||
array(
|
||||
'value' => $product->get_meta( '_subscription_sign_up_fee' ) ?: '0',
|
||||
'currency_code' => $this->currency,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PaymentPreferences object based off a PayPal response.
|
||||
*
|
||||
* @param stdClass $data The data.
|
||||
* @return PaymentPreferences
|
||||
*/
|
||||
public function from_paypal_response( stdClass $data ) {
|
||||
return new PaymentPreferences(
|
||||
array(
|
||||
'value' => $data->setup_fee->value,
|
||||
'currency_code' => $data->setup_fee->currency_code,
|
||||
),
|
||||
$data->auto_bill_outstanding,
|
||||
$data->setup_fee_failure_action,
|
||||
$data->payment_failure_threshold
|
||||
);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
|||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Refund;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payments;
|
||||
|
||||
/**
|
||||
|
@ -32,19 +33,29 @@ class PaymentsFactory {
|
|||
*/
|
||||
private $capture_factory;
|
||||
|
||||
/**
|
||||
* The Refund factory.
|
||||
*
|
||||
* @var RefundFactory
|
||||
*/
|
||||
private $refund_factory;
|
||||
|
||||
/**
|
||||
* PaymentsFactory constructor.
|
||||
*
|
||||
* @param AuthorizationFactory $authorization_factory The Authorization factory.
|
||||
* @param CaptureFactory $capture_factory The Capture factory.
|
||||
* @param RefundFactory $refund_factory The Refund factory.
|
||||
*/
|
||||
public function __construct(
|
||||
AuthorizationFactory $authorization_factory,
|
||||
CaptureFactory $capture_factory
|
||||
CaptureFactory $capture_factory,
|
||||
RefundFactory $refund_factory
|
||||
) {
|
||||
|
||||
$this->authorization_factory = $authorization_factory;
|
||||
$this->capture_factory = $capture_factory;
|
||||
$this->refund_factory = $refund_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,12 +73,18 @@ class PaymentsFactory {
|
|||
isset( $data->authorizations ) ? $data->authorizations : array()
|
||||
);
|
||||
$captures = array_map(
|
||||
function ( \stdClass $authorization ): Capture {
|
||||
return $this->capture_factory->from_paypal_response( $authorization );
|
||||
function ( \stdClass $capture ): Capture {
|
||||
return $this->capture_factory->from_paypal_response( $capture );
|
||||
},
|
||||
isset( $data->captures ) ? $data->captures : array()
|
||||
);
|
||||
$payments = new Payments( $authorizations, $captures );
|
||||
$refunds = array_map(
|
||||
function ( \stdClass $refund ): Refund {
|
||||
return $this->refund_factory->from_paypal_response( $refund );
|
||||
},
|
||||
isset( $data->refunds ) ? $data->refunds : array()
|
||||
);
|
||||
$payments = new Payments( $authorizations, $captures, $refunds );
|
||||
return $payments;
|
||||
}
|
||||
}
|
||||
|
|
96
modules/ppcp-api-client/src/Factory/PlanFactory.php
Normal file
96
modules/ppcp-api-client/src/Factory/PlanFactory.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
/**
|
||||
* Plan Factory.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Webhooks\Handler
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use stdClass;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Plan;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class PlanFactory
|
||||
*/
|
||||
class PlanFactory {
|
||||
|
||||
/**
|
||||
* Billing cycle factory.
|
||||
*
|
||||
* @var BillingCycleFactory
|
||||
*/
|
||||
private $billing_cycle_factory;
|
||||
|
||||
/**
|
||||
* Payment preferences factory.
|
||||
*
|
||||
* @var PaymentPreferencesFactory
|
||||
*/
|
||||
private $payment_preferences_factory;
|
||||
|
||||
/**
|
||||
* PlanFactory constructor.
|
||||
*
|
||||
* @param BillingCycleFactory $billing_cycle_factory Billing cycle factory.
|
||||
* @param PaymentPreferencesFactory $payment_preferences_factory Payment preferences factory.
|
||||
*/
|
||||
public function __construct(
|
||||
BillingCycleFactory $billing_cycle_factory,
|
||||
PaymentPreferencesFactory $payment_preferences_factory
|
||||
) {
|
||||
$this->billing_cycle_factory = $billing_cycle_factory;
|
||||
$this->payment_preferences_factory = $payment_preferences_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Plan from PayPal response.
|
||||
*
|
||||
* @param stdClass $data The data.
|
||||
*
|
||||
* @return Plan
|
||||
*
|
||||
* @throws RuntimeException If it could not create Plan.
|
||||
*/
|
||||
public function from_paypal_response( stdClass $data ): Plan {
|
||||
if ( ! isset( $data->id ) ) {
|
||||
throw new RuntimeException(
|
||||
__( 'No id for given plan', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
if ( ! isset( $data->name ) ) {
|
||||
throw new RuntimeException(
|
||||
__( 'No name for plan given', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
if ( ! isset( $data->product_id ) ) {
|
||||
throw new RuntimeException(
|
||||
__( 'No product id for given plan', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
if ( ! isset( $data->billing_cycles ) ) {
|
||||
throw new RuntimeException(
|
||||
__( 'No billing cycles for given plan', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
|
||||
$billing_cycles = array();
|
||||
foreach ( $data->billing_cycles as $billing_cycle ) {
|
||||
$billing_cycles[] = $this->billing_cycle_factory->from_paypal_response( $billing_cycle );
|
||||
}
|
||||
|
||||
$payment_preferences = $this->payment_preferences_factory->from_paypal_response( $data->payment_preferences );
|
||||
|
||||
return new Plan(
|
||||
$data->id,
|
||||
$data->name,
|
||||
$data->product_id,
|
||||
$billing_cycles,
|
||||
$payment_preferences,
|
||||
$data->status ?? ''
|
||||
);
|
||||
}
|
||||
}
|
47
modules/ppcp-api-client/src/Factory/ProductFactory.php
Normal file
47
modules/ppcp-api-client/src/Factory/ProductFactory.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
/**
|
||||
* The Product factory.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use stdClass;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Product;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class ProductFactory
|
||||
*/
|
||||
class ProductFactory {
|
||||
|
||||
/**
|
||||
* Creates a Product based off a PayPal response.
|
||||
*
|
||||
* @param stdClass $data The JSON object.
|
||||
*
|
||||
* @return Product
|
||||
* @throws RuntimeException When JSON object is malformed.
|
||||
*/
|
||||
public function from_paypal_response( stdClass $data ): Product {
|
||||
if ( ! isset( $data->id ) ) {
|
||||
throw new RuntimeException(
|
||||
__( 'No id for product given', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
if ( ! isset( $data->name ) ) {
|
||||
throw new RuntimeException(
|
||||
__( 'No name for product given', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
|
||||
return new Product(
|
||||
$data->id,
|
||||
$data->name,
|
||||
$data->description ?? ''
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,10 +9,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use WC_Session_Handler;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayeeRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\PurchaseUnitSanitizer;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\CustomIds;
|
||||
|
||||
/**
|
||||
* Class PurchaseUnitFactory
|
||||
|
@ -26,20 +28,6 @@ class PurchaseUnitFactory {
|
|||
*/
|
||||
private $amount_factory;
|
||||
|
||||
/**
|
||||
* The payee repository.
|
||||
*
|
||||
* @var PayeeRepository
|
||||
*/
|
||||
private $payee_repository;
|
||||
|
||||
/**
|
||||
* The payee factory.
|
||||
*
|
||||
* @var PayeeFactory
|
||||
*/
|
||||
private $payee_factory;
|
||||
|
||||
/**
|
||||
* The item factory.
|
||||
*
|
||||
|
@ -68,34 +56,48 @@ class PurchaseUnitFactory {
|
|||
*/
|
||||
private $prefix;
|
||||
|
||||
/**
|
||||
* The Soft Descriptor.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $soft_descriptor;
|
||||
|
||||
/**
|
||||
* The sanitizer for purchase unit output data.
|
||||
*
|
||||
* @var PurchaseUnitSanitizer|null
|
||||
*/
|
||||
private $sanitizer;
|
||||
|
||||
/**
|
||||
* PurchaseUnitFactory constructor.
|
||||
*
|
||||
* @param AmountFactory $amount_factory The amount factory.
|
||||
* @param PayeeRepository $payee_repository The Payee repository.
|
||||
* @param PayeeFactory $payee_factory The Payee factory.
|
||||
* @param ItemFactory $item_factory The item factory.
|
||||
* @param ShippingFactory $shipping_factory The shipping factory.
|
||||
* @param PaymentsFactory $payments_factory The payments factory.
|
||||
* @param string $prefix The prefix.
|
||||
* @param string $soft_descriptor The soft descriptor.
|
||||
* @param ?PurchaseUnitSanitizer $sanitizer The purchase unit to_array sanitizer.
|
||||
*/
|
||||
public function __construct(
|
||||
AmountFactory $amount_factory,
|
||||
PayeeRepository $payee_repository,
|
||||
PayeeFactory $payee_factory,
|
||||
ItemFactory $item_factory,
|
||||
ShippingFactory $shipping_factory,
|
||||
PaymentsFactory $payments_factory,
|
||||
string $prefix = 'WC-'
|
||||
string $prefix = 'WC-',
|
||||
string $soft_descriptor = '',
|
||||
PurchaseUnitSanitizer $sanitizer = null
|
||||
) {
|
||||
|
||||
$this->amount_factory = $amount_factory;
|
||||
$this->payee_repository = $payee_repository;
|
||||
$this->payee_factory = $payee_factory;
|
||||
$this->item_factory = $item_factory;
|
||||
$this->shipping_factory = $shipping_factory;
|
||||
$this->payments_factory = $payments_factory;
|
||||
$this->prefix = $prefix;
|
||||
$this->soft_descriptor = $soft_descriptor;
|
||||
$this->sanitizer = $sanitizer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,7 +112,7 @@ class PurchaseUnitFactory {
|
|||
$items = array_filter(
|
||||
$this->item_factory->from_wc_order( $order ),
|
||||
function ( Item $item ): bool {
|
||||
return $item->unit_amount()->value() > 0;
|
||||
return $item->unit_amount()->value() >= 0;
|
||||
}
|
||||
);
|
||||
$shipping = $this->shipping_factory->from_wc_order( $order );
|
||||
|
@ -123,10 +125,9 @@ class PurchaseUnitFactory {
|
|||
}
|
||||
$reference_id = 'default';
|
||||
$description = '';
|
||||
$payee = $this->payee_repository->payee();
|
||||
$custom_id = (string) $order->get_id();
|
||||
$invoice_id = $this->prefix . $order->get_order_number();
|
||||
$soft_descriptor = '';
|
||||
$soft_descriptor = $this->soft_descriptor;
|
||||
|
||||
$purchase_unit = new PurchaseUnit(
|
||||
$amount,
|
||||
|
@ -134,11 +135,13 @@ class PurchaseUnitFactory {
|
|||
$shipping,
|
||||
$reference_id,
|
||||
$description,
|
||||
$payee,
|
||||
$custom_id,
|
||||
$invoice_id,
|
||||
$soft_descriptor
|
||||
);
|
||||
|
||||
$this->init_purchase_unit( $purchase_unit );
|
||||
|
||||
/**
|
||||
* Returns PurchaseUnit for the WC order.
|
||||
*/
|
||||
|
@ -153,10 +156,11 @@ class PurchaseUnitFactory {
|
|||
* Creates a PurchaseUnit based off a WooCommerce cart.
|
||||
*
|
||||
* @param \WC_Cart|null $cart The cart.
|
||||
* @param bool $with_shipping_options Include WC shipping methods.
|
||||
*
|
||||
* @return PurchaseUnit
|
||||
*/
|
||||
public function from_wc_cart( ?\WC_Cart $cart = null ): PurchaseUnit {
|
||||
public function from_wc_cart( ?\WC_Cart $cart = null, bool $with_shipping_options = false ): PurchaseUnit {
|
||||
if ( ! $cart ) {
|
||||
$cart = WC()->cart ?? new \WC_Cart();
|
||||
}
|
||||
|
@ -165,14 +169,14 @@ class PurchaseUnitFactory {
|
|||
$items = array_filter(
|
||||
$this->item_factory->from_wc_cart( $cart ),
|
||||
function ( Item $item ): bool {
|
||||
return $item->unit_amount()->value() > 0;
|
||||
return $item->unit_amount()->value() >= 0;
|
||||
}
|
||||
);
|
||||
|
||||
$shipping = null;
|
||||
$customer = \WC()->customer;
|
||||
if ( $this->shipping_needed( ... array_values( $items ) ) && is_a( $customer, \WC_Customer::class ) ) {
|
||||
$shipping = $this->shipping_factory->from_wc_customer( \WC()->customer );
|
||||
$shipping = $this->shipping_factory->from_wc_customer( \WC()->customer, $with_shipping_options );
|
||||
if (
|
||||
2 !== strlen( $shipping->address()->country_code() ) ||
|
||||
( ! $shipping->address()->postal_code() && ! $this->country_without_postal_code( $shipping->address()->country_code() ) )
|
||||
|
@ -184,23 +188,29 @@ class PurchaseUnitFactory {
|
|||
$reference_id = 'default';
|
||||
$description = '';
|
||||
|
||||
$payee = $this->payee_repository->payee();
|
||||
|
||||
$custom_id = '';
|
||||
$session = WC()->session;
|
||||
if ( $session instanceof WC_Session_Handler ) {
|
||||
$session_id = $session->get_customer_unique_id();
|
||||
if ( $session_id ) {
|
||||
$custom_id = CustomIds::CUSTOMER_ID_PREFIX . $session_id;
|
||||
}
|
||||
}
|
||||
$invoice_id = '';
|
||||
$soft_descriptor = '';
|
||||
$soft_descriptor = $this->soft_descriptor;
|
||||
$purchase_unit = new PurchaseUnit(
|
||||
$amount,
|
||||
$items,
|
||||
$shipping,
|
||||
$reference_id,
|
||||
$description,
|
||||
$payee,
|
||||
$custom_id,
|
||||
$invoice_id,
|
||||
$soft_descriptor
|
||||
);
|
||||
|
||||
$this->init_purchase_unit( $purchase_unit );
|
||||
|
||||
return $purchase_unit;
|
||||
}
|
||||
|
||||
|
@ -223,7 +233,7 @@ class PurchaseUnitFactory {
|
|||
$description = ( isset( $data->description ) ) ? $data->description : '';
|
||||
$custom_id = ( isset( $data->custom_id ) ) ? $data->custom_id : '';
|
||||
$invoice_id = ( isset( $data->invoice_id ) ) ? $data->invoice_id : '';
|
||||
$soft_descriptor = ( isset( $data->soft_descriptor ) ) ? $data->soft_descriptor : '';
|
||||
$soft_descriptor = ( isset( $data->soft_descriptor ) ) ? $data->soft_descriptor : $this->soft_descriptor;
|
||||
$items = array();
|
||||
if ( isset( $data->items ) && is_array( $data->items ) ) {
|
||||
$items = array_map(
|
||||
|
@ -233,7 +243,6 @@ class PurchaseUnitFactory {
|
|||
$data->items
|
||||
);
|
||||
}
|
||||
$payee = isset( $data->payee ) ? $this->payee_factory->from_paypal_response( $data->payee ) : null;
|
||||
$shipping = null;
|
||||
try {
|
||||
if ( isset( $data->shipping ) ) {
|
||||
|
@ -257,12 +266,14 @@ class PurchaseUnitFactory {
|
|||
$shipping,
|
||||
$data->reference_id,
|
||||
$description,
|
||||
$payee,
|
||||
$custom_id,
|
||||
$invoice_id,
|
||||
$soft_descriptor,
|
||||
$payments
|
||||
);
|
||||
|
||||
$this->init_purchase_unit( $purchase_unit );
|
||||
|
||||
return $purchase_unit;
|
||||
}
|
||||
|
||||
|
@ -293,4 +304,16 @@ class PurchaseUnitFactory {
|
|||
$countries = array( 'AE', 'AF', 'AG', 'AI', 'AL', 'AN', 'AO', 'AW', 'BB', 'BF', 'BH', 'BI', 'BJ', 'BM', 'BO', 'BS', 'BT', 'BW', 'BZ', 'CD', 'CF', 'CG', 'CI', 'CK', 'CL', 'CM', 'CO', 'CR', 'CV', 'DJ', 'DM', 'DO', 'EC', 'EG', 'ER', 'ET', 'FJ', 'FK', 'GA', 'GD', 'GH', 'GI', 'GM', 'GN', 'GQ', 'GT', 'GW', 'GY', 'HK', 'HN', 'HT', 'IE', 'IQ', 'IR', 'JM', 'JO', 'KE', 'KH', 'KI', 'KM', 'KN', 'KP', 'KW', 'KY', 'LA', 'LB', 'LC', 'LK', 'LR', 'LS', 'LY', 'ML', 'MM', 'MO', 'MR', 'MS', 'MT', 'MU', 'MW', 'MZ', 'NA', 'NE', 'NG', 'NI', 'NP', 'NR', 'NU', 'OM', 'PA', 'PE', 'PF', 'PY', 'QA', 'RW', 'SA', 'SB', 'SC', 'SD', 'SL', 'SN', 'SO', 'SR', 'SS', 'ST', 'SV', 'SY', 'TC', 'TD', 'TG', 'TL', 'TO', 'TT', 'TV', 'TZ', 'UG', 'UY', 'VC', 'VE', 'VG', 'VN', 'VU', 'WS', 'XA', 'XB', 'XC', 'XE', 'XL', 'XM', 'XN', 'XS', 'YE', 'ZM', 'ZW' );
|
||||
return in_array( $country_code, $countries, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a purchase unit object.
|
||||
*
|
||||
* @param PurchaseUnit $purchase_unit The purchase unit.
|
||||
* @return void
|
||||
*/
|
||||
private function init_purchase_unit( PurchaseUnit $purchase_unit ): void {
|
||||
if ( $this->sanitizer instanceof PurchaseUnitSanitizer ) {
|
||||
$purchase_unit->set_sanitizer( $this->sanitizer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
91
modules/ppcp-api-client/src/Factory/RefundFactory.php
Normal file
91
modules/ppcp-api-client/src/Factory/RefundFactory.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
/**
|
||||
* The refund factory.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
|
||||
*/
|
||||
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Refund;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\RefundStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\RefundStatusDetails;
|
||||
|
||||
/**
|
||||
* Class RefundFactory
|
||||
*/
|
||||
class RefundFactory {
|
||||
|
||||
/**
|
||||
* The Amount factory.
|
||||
*
|
||||
* @var AmountFactory
|
||||
*/
|
||||
private $amount_factory;
|
||||
|
||||
/**
|
||||
* The SellerPayableBreakdownFactory factory.
|
||||
*
|
||||
* @var SellerPayableBreakdownFactory
|
||||
*/
|
||||
private $seller_payable_breakdown_factory;
|
||||
|
||||
/**
|
||||
* The RefundPayerFactory factory.
|
||||
*
|
||||
* @var RefundPayerFactory
|
||||
*/
|
||||
private $refund_payer_factory;
|
||||
|
||||
/**
|
||||
* RefundFactory constructor.
|
||||
*
|
||||
* @param AmountFactory $amount_factory The amount factory.
|
||||
* @param SellerPayableBreakdownFactory $seller_payable_breakdown_factory The payable breakdown factory.
|
||||
* @param RefundPayerFactory $refund_payer_factory The payer breakdown factory.
|
||||
*/
|
||||
public function __construct(
|
||||
AmountFactory $amount_factory,
|
||||
SellerPayableBreakdownFactory $seller_payable_breakdown_factory,
|
||||
RefundPayerFactory $refund_payer_factory
|
||||
) {
|
||||
$this->amount_factory = $amount_factory;
|
||||
$this->seller_payable_breakdown_factory = $seller_payable_breakdown_factory;
|
||||
$this->refund_payer_factory = $refund_payer_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the refund object based off the PayPal response.
|
||||
*
|
||||
* @param \stdClass $data The PayPal response.
|
||||
*
|
||||
* @return Refund
|
||||
*/
|
||||
public function from_paypal_response( \stdClass $data ) : Refund {
|
||||
$reason = $data->status_details->reason ?? null;
|
||||
$seller_payable_breakdown = isset( $data->seller_payable_breakdown ) ?
|
||||
$this->seller_payable_breakdown_factory->from_paypal_response( $data->seller_payable_breakdown )
|
||||
: null;
|
||||
|
||||
$payer = isset( $data->payer ) ?
|
||||
$this->refund_payer_factory->from_paypal_response( $data->payer )
|
||||
: null;
|
||||
|
||||
return new Refund(
|
||||
(string) $data->id,
|
||||
new RefundStatus(
|
||||
(string) $data->status,
|
||||
$reason ? new RefundStatusDetails( $reason ) : null
|
||||
),
|
||||
$this->amount_factory->from_paypal_response( $data->amount ),
|
||||
(string) ( $data->invoice_id ?? '' ),
|
||||
(string) ( $data->custom_id ?? '' ),
|
||||
$seller_payable_breakdown,
|
||||
(string) ( $data->acquirer_reference_number ?? '' ),
|
||||
(string) ( $data->note_to_payer ?? '' ),
|
||||
$payer
|
||||
);
|
||||
}
|
||||
}
|
39
modules/ppcp-api-client/src/Factory/RefundPayerFactory.php
Normal file
39
modules/ppcp-api-client/src/Factory/RefundPayerFactory.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* The RefundPayerFactory factory.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Address;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PayerName;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PayerTaxInfo;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Phone;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PhoneWithType;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\RefundPayer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class RefundPayerFactory
|
||||
*/
|
||||
class RefundPayerFactory {
|
||||
|
||||
/**
|
||||
* Returns a Refund Payer object based off a PayPal Response.
|
||||
*
|
||||
* @param \stdClass $data The JSON object.
|
||||
*
|
||||
* @return RefundPayer
|
||||
*/
|
||||
public function from_paypal_response( \stdClass $data ): RefundPayer {
|
||||
return new RefundPayer(
|
||||
isset( $data->email_address ) ? $data->email_address : '',
|
||||
isset( $data->merchant_id ) ? $data->merchant_id : ''
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
/**
|
||||
* The SellerPayableBreakdownFactory Factory.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use stdClass;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PlatformFee;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerPayableBreakdown;
|
||||
|
||||
/**
|
||||
* Class SellerPayableBreakdownFactory
|
||||
*/
|
||||
class SellerPayableBreakdownFactory {
|
||||
|
||||
/**
|
||||
* The Money factory.
|
||||
*
|
||||
* @var MoneyFactory
|
||||
*/
|
||||
private $money_factory;
|
||||
|
||||
/**
|
||||
* The PlatformFee factory.
|
||||
*
|
||||
* @var PlatformFeeFactory
|
||||
*/
|
||||
private $platform_fee_factory;
|
||||
|
||||
/**
|
||||
* SellerPayableBreakdownFactory constructor.
|
||||
*
|
||||
* @param MoneyFactory $money_factory The Money factory.
|
||||
* @param PlatformFeeFactory $platform_fee_factory The PlatformFee factory.
|
||||
*/
|
||||
public function __construct(
|
||||
MoneyFactory $money_factory,
|
||||
PlatformFeeFactory $platform_fee_factory
|
||||
) {
|
||||
$this->money_factory = $money_factory;
|
||||
$this->platform_fee_factory = $platform_fee_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SellerPayableBreakdownFactory object based off a PayPal Response.
|
||||
*
|
||||
* @param stdClass $data The JSON object.
|
||||
*
|
||||
* @return SellerPayableBreakdown
|
||||
*/
|
||||
public function from_paypal_response( stdClass $data ): SellerPayableBreakdown {
|
||||
|
||||
$gross_amount = ( isset( $data->gross_amount ) ) ? $this->money_factory->from_paypal_response( $data->gross_amount ) : null;
|
||||
$paypal_fee = ( isset( $data->paypal_fee ) ) ? $this->money_factory->from_paypal_response( $data->paypal_fee ) : null;
|
||||
$paypal_fee_in_receivable_currency = ( isset( $data->paypal_fee_in_receivable_currency ) ) ? $this->money_factory->from_paypal_response( $data->paypal_fee_in_receivable_currency ) : null;
|
||||
$net_amount = ( isset( $data->net_amount ) ) ? $this->money_factory->from_paypal_response( $data->net_amount ) : null;
|
||||
$net_amount_in_receivable_currency = ( isset( $data->net_amount_in_receivable_currency ) ) ? $this->money_factory->from_paypal_response( $data->net_amount_in_receivable_currency ) : null;
|
||||
$total_refunded_amount = ( isset( $data->total_refunded_amount ) ) ? $this->money_factory->from_paypal_response( $data->total_refunded_amount ) : null;
|
||||
$platform_fees = ( isset( $data->platform_fees ) ) ? array_map(
|
||||
function ( stdClass $fee_data ): PlatformFee {
|
||||
return $this->platform_fee_factory->from_paypal_response( $fee_data );
|
||||
},
|
||||
$data->platform_fees
|
||||
) : array();
|
||||
|
||||
return new SellerPayableBreakdown(
|
||||
$gross_amount,
|
||||
$paypal_fee,
|
||||
$paypal_fee_in_receivable_currency,
|
||||
$net_amount,
|
||||
$net_amount_in_receivable_currency,
|
||||
$total_refunded_amount,
|
||||
$platform_fees
|
||||
);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Shipping;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ShippingOption;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
|
@ -24,23 +25,33 @@ class ShippingFactory {
|
|||
*/
|
||||
private $address_factory;
|
||||
|
||||
/**
|
||||
* The shipping option factory.
|
||||
*
|
||||
* @var ShippingOptionFactory
|
||||
*/
|
||||
private $shipping_option_factory;
|
||||
|
||||
/**
|
||||
* ShippingFactory constructor.
|
||||
*
|
||||
* @param AddressFactory $address_factory The address factory.
|
||||
* @param ShippingOptionFactory $shipping_option_factory The shipping option factory.
|
||||
*/
|
||||
public function __construct( AddressFactory $address_factory ) {
|
||||
public function __construct( AddressFactory $address_factory, ShippingOptionFactory $shipping_option_factory ) {
|
||||
$this->address_factory = $address_factory;
|
||||
$this->shipping_option_factory = $shipping_option_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shipping object based off a WooCommerce customer.
|
||||
*
|
||||
* @param \WC_Customer $customer The WooCommerce customer.
|
||||
* @param bool $with_shipping_options Include WC shipping methods.
|
||||
*
|
||||
* @return Shipping
|
||||
*/
|
||||
public function from_wc_customer( \WC_Customer $customer ): Shipping {
|
||||
public function from_wc_customer( \WC_Customer $customer, bool $with_shipping_options = false ): Shipping {
|
||||
// Replicates the Behavior of \WC_Order::get_formatted_shipping_full_name().
|
||||
$full_name = sprintf(
|
||||
// translators: %1$s is the first name and %2$s is the second name. wc translation.
|
||||
|
@ -51,7 +62,8 @@ class ShippingFactory {
|
|||
$address = $this->address_factory->from_wc_customer( $customer );
|
||||
return new Shipping(
|
||||
$full_name,
|
||||
$address
|
||||
$address,
|
||||
$with_shipping_options ? $this->shipping_option_factory->from_wc_cart() : array()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -91,9 +103,14 @@ class ShippingFactory {
|
|||
);
|
||||
}
|
||||
$address = $this->address_factory->from_paypal_response( $data->address );
|
||||
$options = array_map(
|
||||
array( $this->shipping_option_factory, 'from_paypal_response' ),
|
||||
$data->options ?? array()
|
||||
);
|
||||
return new Shipping(
|
||||
$data->name->full_name,
|
||||
$address
|
||||
$address,
|
||||
$options
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
111
modules/ppcp-api-client/src/Factory/ShippingOptionFactory.php
Normal file
111
modules/ppcp-api-client/src/Factory/ShippingOptionFactory.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
/**
|
||||
* The shipping options factory.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use stdClass;
|
||||
use WC_Cart;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ShippingOption;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class ShippingOptionFactory
|
||||
*/
|
||||
class ShippingOptionFactory {
|
||||
|
||||
/**
|
||||
* The Money factory.
|
||||
*
|
||||
* @var MoneyFactory
|
||||
*/
|
||||
private $money_factory;
|
||||
|
||||
/**
|
||||
* ShippingOptionFactory constructor.
|
||||
*
|
||||
* @param MoneyFactory $money_factory The Money factory.
|
||||
*/
|
||||
public function __construct( MoneyFactory $money_factory ) {
|
||||
$this->money_factory = $money_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of ShippingOption objects for the shipping methods available in the cart.
|
||||
*
|
||||
* @param WC_Cart|null $cart The cart.
|
||||
* @return ShippingOption[]
|
||||
*/
|
||||
public function from_wc_cart( ?WC_Cart $cart = null ): array {
|
||||
if ( ! $cart ) {
|
||||
$cart = WC()->cart ?? new WC_Cart();
|
||||
}
|
||||
|
||||
$cart->calculate_shipping();
|
||||
|
||||
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods', array() );
|
||||
if ( ! is_array( $chosen_shipping_methods ) ) {
|
||||
$chosen_shipping_methods = array();
|
||||
}
|
||||
|
||||
$packages = WC()->shipping()->get_packages();
|
||||
$options = array();
|
||||
foreach ( $packages as $package ) {
|
||||
$rates = $package['rates'] ?? array();
|
||||
foreach ( $rates as $rate ) {
|
||||
if ( ! $rate instanceof \WC_Shipping_Rate ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$options[] = new ShippingOption(
|
||||
$rate->get_id(),
|
||||
$rate->get_label(),
|
||||
in_array( $rate->get_id(), $chosen_shipping_methods, true ),
|
||||
new Money(
|
||||
(float) $rate->get_cost(),
|
||||
get_woocommerce_currency()
|
||||
),
|
||||
ShippingOption::TYPE_SHIPPING
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $chosen_shipping_methods && $options ) {
|
||||
$options[0]->set_selected( true );
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ShippingOption object from the PayPal JSON object.
|
||||
*
|
||||
* @param stdClass $data The JSON object.
|
||||
*
|
||||
* @return ShippingOption
|
||||
* @throws RuntimeException When JSON object is malformed.
|
||||
*/
|
||||
public function from_paypal_response( stdClass $data ): ShippingOption {
|
||||
if ( ! isset( $data->id ) ) {
|
||||
throw new RuntimeException( 'No id was given for shipping option.' );
|
||||
}
|
||||
if ( ! isset( $data->amount ) ) {
|
||||
throw new RuntimeException( 'Shipping option amount not found' );
|
||||
}
|
||||
|
||||
$amount = $this->money_factory->from_paypal_response( $data->amount );
|
||||
return new ShippingOption(
|
||||
$data->id,
|
||||
$data->label ?? '',
|
||||
isset( $data->selected ) ? (bool) $data->selected : false,
|
||||
$amount,
|
||||
$data->type ?? ShippingOption::TYPE_SHIPPING
|
||||
);
|
||||
}
|
||||
}
|
94
modules/ppcp-api-client/src/Helper/FailureRegistry.php
Normal file
94
modules/ppcp-api-client/src/Helper/FailureRegistry.php
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
/**
|
||||
* Failure registry.
|
||||
*
|
||||
* This class is used to remember API failures.
|
||||
* Mostly to prevent multiple failed API requests.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Helper;
|
||||
|
||||
/**
|
||||
* Class FailureRegistry
|
||||
*/
|
||||
class FailureRegistry {
|
||||
const CACHE_KEY = 'failure_registry';
|
||||
const CACHE_TIMEOUT = 60 * 60 * 24; // DAY_IN_SECONDS, if necessary we can increase this.
|
||||
|
||||
const SELLER_STATUS_KEY = 'seller_status';
|
||||
|
||||
|
||||
/**
|
||||
* The Cache.
|
||||
*
|
||||
* @var Cache
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* FailureRegistry constructor.
|
||||
*
|
||||
* @param Cache $cache The Cache.
|
||||
*/
|
||||
public function __construct( Cache $cache ) {
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if there was a failure within a given timeframe.
|
||||
*
|
||||
* @param string $key The cache key.
|
||||
* @param int $seconds The timeframe in seconds.
|
||||
* @return bool
|
||||
*/
|
||||
public function has_failure_in_timeframe( string $key, int $seconds ): bool {
|
||||
$cache_key = $this->cache_key( $key );
|
||||
$failure_time = $this->cache->get( $cache_key );
|
||||
|
||||
if ( ! $failure_time ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$expiration = $failure_time + $seconds;
|
||||
return $expiration > time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a failure.
|
||||
*
|
||||
* @param string $key The cache key.
|
||||
* @return void
|
||||
*/
|
||||
public function add_failure( string $key ) {
|
||||
$cache_key = $this->cache_key( $key );
|
||||
$this->cache->set( $cache_key, time(), self::CACHE_TIMEOUT );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a given failure.
|
||||
*
|
||||
* @param string $key The cache key.
|
||||
* @return void
|
||||
*/
|
||||
public function clear_failures( string $key ) {
|
||||
$cache_key = $this->cache_key( $key );
|
||||
if ( $this->cache->has( $cache_key ) ) {
|
||||
$this->cache->delete( $cache_key );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build cache key.
|
||||
*
|
||||
* @param string $key The cache key.
|
||||
* @return string
|
||||
*/
|
||||
private function cache_key( string $key ): string {
|
||||
return implode( '_', array( self::CACHE_KEY, $key ) );
|
||||
}
|
||||
|
||||
}
|
24
modules/ppcp-api-client/src/Helper/ItemTrait.php
Normal file
24
modules/ppcp-api-client/src/Helper/ItemTrait.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* PayPal item helper.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Helper;
|
||||
|
||||
trait ItemTrait {
|
||||
|
||||
/**
|
||||
* 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 ) ?: '';
|
||||
}
|
||||
}
|
|
@ -33,4 +33,16 @@ class MoneyFormatter {
|
|||
? (string) round( $value, 0 )
|
||||
: number_format( $value, 2, '.', '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum amount a currency can be incremented or decremented.
|
||||
*
|
||||
* @param string $currency The 3-letter currency code.
|
||||
* @return float
|
||||
*/
|
||||
public function minimum_increment( string $currency ): float {
|
||||
return (float) in_array( $currency, $this->currencies_without_decimals, true )
|
||||
? 1.00
|
||||
: 0.01;
|
||||
}
|
||||
}
|
||||
|
|
160
modules/ppcp-api-client/src/Helper/OrderTransient.php
Normal file
160
modules/ppcp-api-client/src/Helper/OrderTransient.php
Normal file
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
/**
|
||||
* PayPal order transient helper.
|
||||
*
|
||||
* This class is used to pass transient data between the PayPal order and the WooCommerce order.
|
||||
* These two orders can be created on different requests and at different times so this transient
|
||||
* data must be persisted between requests.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Helper;
|
||||
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
|
||||
/**
|
||||
* Class OrderTransient
|
||||
*/
|
||||
class OrderTransient {
|
||||
const CACHE_KEY = 'order_transient';
|
||||
const CACHE_TIMEOUT = 60 * 60 * 24; // DAY_IN_SECONDS, if necessary we can increase this.
|
||||
|
||||
/**
|
||||
* The Cache.
|
||||
*
|
||||
* @var Cache
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* The purchase unit sanitizer.
|
||||
*
|
||||
* @var PurchaseUnitSanitizer
|
||||
*/
|
||||
private $purchase_unit_sanitizer;
|
||||
|
||||
/**
|
||||
* OrderTransient constructor.
|
||||
*
|
||||
* @param Cache $cache The Cache.
|
||||
* @param PurchaseUnitSanitizer $purchase_unit_sanitizer The purchase unit sanitizer.
|
||||
*/
|
||||
public function __construct( Cache $cache, PurchaseUnitSanitizer $purchase_unit_sanitizer ) {
|
||||
$this->cache = $cache;
|
||||
$this->purchase_unit_sanitizer = $purchase_unit_sanitizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the created PayPal order.
|
||||
*
|
||||
* @param Order $order The PayPal order.
|
||||
* @return void
|
||||
*/
|
||||
public function on_order_created( Order $order ): void {
|
||||
$message = $this->purchase_unit_sanitizer->get_last_message();
|
||||
$this->add_order_note( $order, $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the created WooCommerce order.
|
||||
*
|
||||
* @param WC_Order $wc_order The WooCommerce order.
|
||||
* @param Order $order The PayPal order.
|
||||
* @return void
|
||||
*/
|
||||
public function on_woocommerce_order_created( WC_Order $wc_order, Order $order ): void {
|
||||
$cache_key = $this->cache_key( $order );
|
||||
|
||||
if ( ! $cache_key ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->apply_order_notes( $order, $wc_order );
|
||||
$this->cache->delete( $cache_key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an order note associated with a PayPal order.
|
||||
* It can be added to a WooCommerce order associated with this PayPal order in the future.
|
||||
*
|
||||
* @param Order $order The PayPal order.
|
||||
* @param string $message The message to be added to order notes.
|
||||
* @return void
|
||||
*/
|
||||
private function add_order_note( Order $order, string $message ): void {
|
||||
if ( ! $message ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cache_key = $this->cache_key( $order );
|
||||
|
||||
if ( ! $cache_key ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transient = $this->cache->get( $cache_key );
|
||||
|
||||
if ( ! is_array( $transient ) ) {
|
||||
$transient = array();
|
||||
}
|
||||
|
||||
if ( ! is_array( $transient['notes'] ) ) {
|
||||
$transient['notes'] = array();
|
||||
}
|
||||
|
||||
$transient['notes'][] = $message;
|
||||
|
||||
$this->cache->set( $cache_key, $transient, self::CACHE_TIMEOUT );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an order note associated with a PayPal order.
|
||||
* It can be added to a WooCommerce order associated with this PayPal order in the future.
|
||||
*
|
||||
* @param Order $order The PayPal order.
|
||||
* @param WC_Order $wc_order The WooCommerce order.
|
||||
* @return void
|
||||
*/
|
||||
private function apply_order_notes( Order $order, WC_Order $wc_order ): void {
|
||||
$cache_key = $this->cache_key( $order );
|
||||
|
||||
if ( ! $cache_key ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transient = $this->cache->get( $cache_key );
|
||||
|
||||
if ( ! is_array( $transient ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! is_array( $transient['notes'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $transient['notes'] as $note ) {
|
||||
if ( ! is_string( $note ) ) {
|
||||
continue;
|
||||
}
|
||||
$wc_order->add_order_note( $note );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build cache key.
|
||||
*
|
||||
* @param Order $order The PayPal order.
|
||||
* @return string|null
|
||||
*/
|
||||
private function cache_key( Order $order ): ?string {
|
||||
if ( ! $order->id() ) {
|
||||
return null;
|
||||
}
|
||||
return implode( '_', array( self::CACHE_KEY . $order->id() ) );
|
||||
}
|
||||
|
||||
}
|
368
modules/ppcp-api-client/src/Helper/PurchaseUnitSanitizer.php
Normal file
368
modules/ppcp-api-client/src/Helper/PurchaseUnitSanitizer.php
Normal file
|
@ -0,0 +1,368 @@
|
|||
<?php
|
||||
/**
|
||||
* Class PurchaseUnitSanitizer.
|
||||
*
|
||||
* Sanitizes a purchase_unit array to be consumed by PayPal.
|
||||
*
|
||||
* All money values send to PayPal can only have 2 decimal points. WooCommerce internally does
|
||||
* not have this restriction. Therefore, the totals of the cart in WooCommerce and the totals
|
||||
* of the rounded money values of the items, we send to PayPal, can differ. In those case we either:
|
||||
* - Add an extra line with roundings.
|
||||
* - Don't send the line items.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Helper;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
|
||||
/**
|
||||
* Class PurchaseUnitSanitizer
|
||||
*/
|
||||
class PurchaseUnitSanitizer {
|
||||
const MODE_DITCH = 'ditch';
|
||||
const MODE_EXTRA_LINE = 'extra_line';
|
||||
const VALID_MODES = array(
|
||||
self::MODE_DITCH,
|
||||
self::MODE_EXTRA_LINE,
|
||||
);
|
||||
|
||||
const EXTRA_LINE_NAME = 'Subtotal mismatch';
|
||||
|
||||
/**
|
||||
* The purchase unit data
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $purchase_unit = array();
|
||||
|
||||
/**
|
||||
* Whether to allow items to be ditched.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $allow_ditch_items = true;
|
||||
|
||||
/**
|
||||
* The working mode
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $mode;
|
||||
|
||||
/**
|
||||
* The name for the extra line
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $extra_line_name;
|
||||
|
||||
/**
|
||||
* The last message. To be added to order notes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $last_message = '';
|
||||
|
||||
/**
|
||||
* If the items and breakdown has been ditched.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $has_ditched_items_breakdown = false;
|
||||
|
||||
/**
|
||||
* PurchaseUnitSanitizer constructor.
|
||||
*
|
||||
* @param string|null $mode The mismatch handling mode, ditch or extra_line.
|
||||
* @param string|null $extra_line_name The name of the extra line.
|
||||
*/
|
||||
public function __construct( string $mode = null, string $extra_line_name = null ) {
|
||||
|
||||
if ( ! in_array( $mode, self::VALID_MODES, true ) ) {
|
||||
$mode = self::MODE_DITCH;
|
||||
}
|
||||
|
||||
if ( ! $extra_line_name ) {
|
||||
$extra_line_name = self::EXTRA_LINE_NAME;
|
||||
}
|
||||
|
||||
$this->mode = $mode;
|
||||
$this->extra_line_name = $extra_line_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The purchase_unit amount.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function amount(): array {
|
||||
return $this->purchase_unit['amount'] ?? array();
|
||||
}
|
||||
|
||||
/**
|
||||
* The purchase_unit currency code.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function currency_code(): string {
|
||||
return (string) ( $this->amount()['currency_code'] ?? '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* The purchase_unit breakdown.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function breakdown(): array {
|
||||
return $this->amount()['breakdown'] ?? array();
|
||||
}
|
||||
|
||||
/**
|
||||
* The purchase_unit breakdown.
|
||||
*
|
||||
* @param string $key The breakdown element to get the value from.
|
||||
* @return float
|
||||
*/
|
||||
private function breakdown_value( string $key ): float {
|
||||
if ( ! isset( $this->breakdown()[ $key ] ) ) {
|
||||
return 0.0;
|
||||
}
|
||||
return (float) ( $this->breakdown()[ $key ]['value'] ?? 0.0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* The purchase_unit items array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function items(): array {
|
||||
return $this->purchase_unit['items'] ?? array();
|
||||
}
|
||||
|
||||
/**
|
||||
* The sanitizes the purchase_unit array.
|
||||
*
|
||||
* @param array $purchase_unit The purchase_unit array that should be sanitized.
|
||||
* @param bool $allow_ditch_items Whether to allow items to be ditched.
|
||||
* @return array
|
||||
*/
|
||||
public function sanitize( array $purchase_unit, bool $allow_ditch_items = true ): array {
|
||||
$this->purchase_unit = $purchase_unit;
|
||||
$this->allow_ditch_items = $allow_ditch_items;
|
||||
$this->has_ditched_items_breakdown = false;
|
||||
|
||||
$this->sanitize_item_amount_mismatch();
|
||||
$this->sanitize_item_tax_mismatch();
|
||||
$this->sanitize_breakdown_mismatch();
|
||||
return $this->purchase_unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* The sanitizes the purchase_unit items amount.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function sanitize_item_amount_mismatch(): void {
|
||||
$item_mismatch = $this->calculate_item_mismatch();
|
||||
|
||||
if ( $this->mode === self::MODE_EXTRA_LINE ) {
|
||||
if ( $item_mismatch < 0 ) {
|
||||
|
||||
// Do floors on item amounts so item_mismatch is a positive value.
|
||||
foreach ( $this->purchase_unit['items'] as $index => $item ) {
|
||||
// Get a more intelligent adjustment mechanism.
|
||||
$increment = ( new MoneyFormatter() )->minimum_increment( $item['unit_amount']['currency_code'] );
|
||||
|
||||
$this->purchase_unit['items'][ $index ]['unit_amount'] = ( new Money(
|
||||
( (float) $item['unit_amount']['value'] ) - $increment,
|
||||
$item['unit_amount']['currency_code']
|
||||
) )->to_array();
|
||||
}
|
||||
}
|
||||
|
||||
$item_mismatch = $this->calculate_item_mismatch();
|
||||
|
||||
if ( $item_mismatch > 0 ) {
|
||||
// Add extra line item with roundings.
|
||||
$line_name = $this->extra_line_name;
|
||||
$roundings_money = new Money( $item_mismatch, $this->currency_code() );
|
||||
$this->purchase_unit['items'][] = ( new Item( $line_name, $roundings_money, 1 ) )->to_array();
|
||||
|
||||
$this->set_last_message(
|
||||
__( 'Item amount mismatch. Extra line added.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
|
||||
$item_mismatch = $this->calculate_item_mismatch();
|
||||
}
|
||||
|
||||
if ( $item_mismatch !== 0.0 ) {
|
||||
// Ditch items.
|
||||
if ( $this->allow_ditch_items && isset( $this->purchase_unit['items'] ) ) {
|
||||
unset( $this->purchase_unit['items'] );
|
||||
$this->set_last_message(
|
||||
__( 'Item amount mismatch. Items ditched.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The sanitizes the purchase_unit items tax.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function sanitize_item_tax_mismatch(): void {
|
||||
$tax_mismatch = $this->calculate_tax_mismatch();
|
||||
|
||||
if ( $this->allow_ditch_items && $tax_mismatch !== 0.0 ) {
|
||||
// Unset tax in items.
|
||||
foreach ( $this->purchase_unit['items'] as $index => $item ) {
|
||||
if ( isset( $this->purchase_unit['items'][ $index ]['tax'] ) ) {
|
||||
unset( $this->purchase_unit['items'][ $index ]['tax'] );
|
||||
}
|
||||
if ( isset( $this->purchase_unit['items'][ $index ]['tax_rate'] ) ) {
|
||||
unset( $this->purchase_unit['items'][ $index ]['tax_rate'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The sanitizes the purchase_unit breakdown.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function sanitize_breakdown_mismatch(): void {
|
||||
$breakdown_mismatch = $this->calculate_breakdown_mismatch();
|
||||
|
||||
if ( $this->allow_ditch_items && $breakdown_mismatch !== 0.0 ) {
|
||||
// Ditch breakdowns and items.
|
||||
if ( isset( $this->purchase_unit['items'] ) ) {
|
||||
unset( $this->purchase_unit['items'] );
|
||||
}
|
||||
if ( isset( $this->purchase_unit['amount']['breakdown'] ) ) {
|
||||
unset( $this->purchase_unit['amount']['breakdown'] );
|
||||
}
|
||||
|
||||
$this->has_ditched_items_breakdown = true;
|
||||
$this->set_last_message(
|
||||
__( 'Breakdown mismatch. Items and breakdown ditched.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The calculates amount mismatch of items sums with breakdown.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function calculate_item_mismatch(): float {
|
||||
$item_total = $this->breakdown_value( 'item_total' );
|
||||
if ( ! $item_total ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$remaining_item_total = array_reduce(
|
||||
$this->items(),
|
||||
function ( float $total, array $item ): float {
|
||||
return $total - (float) $item['unit_amount']['value'] * (float) $item['quantity'];
|
||||
},
|
||||
$item_total
|
||||
);
|
||||
|
||||
return round( $remaining_item_total, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* The calculates tax mismatch of items sums with breakdown.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function calculate_tax_mismatch(): float {
|
||||
$tax_total = $this->breakdown_value( 'tax_total' );
|
||||
$items_with_tax = array_filter(
|
||||
$this->items(),
|
||||
function ( array $item ): bool {
|
||||
return isset( $item['tax'] );
|
||||
}
|
||||
);
|
||||
|
||||
if ( ! $tax_total || empty( $items_with_tax ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$remaining_tax_total = array_reduce(
|
||||
$this->items(),
|
||||
function ( float $total, array $item ): float {
|
||||
$tax = $item['tax'] ?? false;
|
||||
if ( $tax ) {
|
||||
$total -= (float) $tax['value'] * (float) $item['quantity'];
|
||||
}
|
||||
return $total;
|
||||
},
|
||||
$tax_total
|
||||
);
|
||||
|
||||
return round( $remaining_tax_total, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* The calculates mismatch of breakdown sums with total amount.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function calculate_breakdown_mismatch(): float {
|
||||
$breakdown = $this->breakdown();
|
||||
if ( ! $breakdown ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$amount_total = 0.0;
|
||||
$amount_total += $this->breakdown_value( 'item_total' );
|
||||
$amount_total += $this->breakdown_value( 'tax_total' );
|
||||
$amount_total += $this->breakdown_value( 'shipping' );
|
||||
$amount_total -= $this->breakdown_value( 'discount' );
|
||||
$amount_total -= $this->breakdown_value( 'shipping_discount' );
|
||||
$amount_total += $this->breakdown_value( 'handling' );
|
||||
$amount_total += $this->breakdown_value( 'insurance' );
|
||||
|
||||
$amount_str = $this->amount()['value'] ?? 0;
|
||||
$amount_total_str = ( new Money( $amount_total, $this->currency_code() ) )->value_str();
|
||||
|
||||
return $amount_str - $amount_total_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the items and breakdown were ditched.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_ditched_items_breakdown(): bool {
|
||||
return $this->has_ditched_items_breakdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last sanitization message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_last_message(): string {
|
||||
return $this->last_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last sanitization message.
|
||||
*
|
||||
* @param string $message The message.
|
||||
*/
|
||||
public function set_last_message( string $message ): void {
|
||||
$this->last_message = $message;
|
||||
}
|
||||
|
||||
}
|
|
@ -38,24 +38,30 @@ class ApplicationContextRepository {
|
|||
* Returns the current application context.
|
||||
*
|
||||
* @param string $shipping_preferences The shipping preferences.
|
||||
* @param string $user_action The user action.
|
||||
*
|
||||
* @return ApplicationContext
|
||||
*/
|
||||
public function current_context(
|
||||
string $shipping_preferences = ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING
|
||||
string $shipping_preferences = ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||
string $user_action = ApplicationContext::USER_ACTION_CONTINUE
|
||||
): ApplicationContext {
|
||||
|
||||
$brand_name = $this->settings->has( 'brand_name' ) ? $this->settings->get( 'brand_name' ) : '';
|
||||
$locale = $this->valid_bcp47_code();
|
||||
$landingpage = $this->settings->has( 'landing_page' ) ?
|
||||
$this->settings->get( 'landing_page' ) : ApplicationContext::LANDING_PAGE_NO_PREFERENCE;
|
||||
$payment_preference = $this->settings->has( 'payee_preferred' ) && $this->settings->get( 'payee_preferred' ) ?
|
||||
ApplicationContext::PAYMENT_METHOD_IMMEDIATE_PAYMENT_REQUIRED : ApplicationContext::PAYMENT_METHOD_UNRESTRICTED;
|
||||
$context = new ApplicationContext(
|
||||
network_home_url( \WC_AJAX::get_endpoint( ReturnUrlEndpoint::ENDPOINT ) ),
|
||||
(string) wc_get_checkout_url(),
|
||||
(string) $brand_name,
|
||||
$locale,
|
||||
(string) $landingpage,
|
||||
$shipping_preferences
|
||||
$shipping_preferences,
|
||||
$user_action,
|
||||
$payment_preference
|
||||
);
|
||||
return $context;
|
||||
}
|
||||
|
|
|
@ -127,4 +127,17 @@ class PartnerReferralsData {
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the validation token to the return_url
|
||||
*
|
||||
* @param array $data The referral data.
|
||||
* @param string $token The token to be appended.
|
||||
* @return array
|
||||
*/
|
||||
public function append_onboarding_token( array $data, string $token ): array {
|
||||
$data['partner_config_override']['return_url'] =
|
||||
add_query_arg( 'ppcpToken', $token, $data['partner_config_override']['return_url'] );
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* The repository for the request IDs.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Repository
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Repository;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
|
||||
/**
|
||||
* Class PayPalRequestIdRepository
|
||||
*/
|
||||
class PayPalRequestIdRepository {
|
||||
|
||||
const KEY = 'ppcp-request-ids';
|
||||
|
||||
/**
|
||||
* Returns a request ID based on the order ID.
|
||||
*
|
||||
* @param string $order_id The order ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_for_order_id( string $order_id ): string {
|
||||
return $this->get( $order_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request ID for an order.
|
||||
*
|
||||
* @param Order $order The order.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_for_order( Order $order ): string {
|
||||
return $this->get_for_order_id( $order->id() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a request ID for a specific order.
|
||||
*
|
||||
* @param Order $order The order.
|
||||
* @param string $request_id The ID.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function set_for_order( Order $order, string $request_id ): bool {
|
||||
$this->set( $order->id(), $request_id );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a request ID for the given key.
|
||||
*
|
||||
* @param string $key The key in the request ID storage.
|
||||
* @param string $request_id The ID.
|
||||
*/
|
||||
public function set( string $key, string $request_id ): void {
|
||||
$all = $this->all();
|
||||
$day_in_seconds = 86400;
|
||||
$all[ $key ] = array(
|
||||
'id' => $request_id,
|
||||
'expiration' => time() + 10 * $day_in_seconds,
|
||||
);
|
||||
$all = $this->cleanup( $all );
|
||||
update_option( self::KEY, $all );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a request ID.
|
||||
*
|
||||
* @param string $key The key in the request ID storage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get( string $key ): string {
|
||||
$all = $this->all();
|
||||
return isset( $all[ $key ] ) ? (string) $all[ $key ]['id'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all IDs.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function all(): array {
|
||||
|
||||
return (array) get_option( 'ppcp-request-ids', array() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up outdated request IDs.
|
||||
*
|
||||
* @param array $all All request IDs.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function cleanup( array $all ): array {
|
||||
|
||||
foreach ( $all as $order_id => $value ) {
|
||||
if ( time() < $value['expiration'] ) {
|
||||
continue;
|
||||
}
|
||||
unset( $all[ $order_id ] );
|
||||
}
|
||||
return $all;
|
||||
}
|
||||
}
|
14
modules/ppcp-applepay/.babelrc
Normal file
14
modules/ppcp-applepay/.babelrc
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"useBuiltIns": "usage",
|
||||
"corejs": "3.25.0"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@babel/preset-react"
|
||||
]
|
||||
]
|
||||
}
|
3
modules/ppcp-applepay/.gitignore
vendored
Normal file
3
modules/ppcp-applepay/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
node_modules
|
||||
assets/js
|
||||
assets/css
|
17
modules/ppcp-applepay/composer.json
Normal file
17
modules/ppcp-applepay/composer.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "woocommerce/ppcp-applepay",
|
||||
"type": "dhii-mod",
|
||||
"description": "Applepay 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\\Applepay\\": "src"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
156
modules/ppcp-applepay/composer.lock
generated
Normal file
156
modules/ppcp-applepay/composer.lock
generated
Normal file
|
@ -0,0 +1,156 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "30c5bd428bece98b555ddc0b2da044f3",
|
||||
"packages": [
|
||||
{
|
||||
"name": "container-interop/service-provider",
|
||||
"version": "v0.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/container-interop/service-provider.git",
|
||||
"reference": "4969b9e49460690b7430b3f1a87cab07be61418a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/container-interop/service-provider/zipball/4969b9e49460690b7430b3f1a87cab07be61418a",
|
||||
"reference": "4969b9e49460690b7430b3f1a87cab07be61418a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"psr/container": "^1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Interop\\Container\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Promoting container interoperability through standard service providers",
|
||||
"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"
|
||||
},
|
||||
"time": "2017-09-20T14:13:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dhii/module-interface",
|
||||
"version": "v0.3.0-alpha2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Dhii/module-interface.git",
|
||||
"reference": "0e39f167d7ed8990c82f5d2e6084159d1a502a5b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Dhii/module-interface/zipball/0e39f167d7ed8990c82f5d2e6084159d1a502a5b",
|
||||
"reference": "0e39f167d7ed8990c82f5d2e6084159d1a502a5b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"container-interop/service-provider": "^0.4",
|
||||
"php": "^7.1 | ^8.0",
|
||||
"psr/container": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7.0 | ^8.0 | ^9.0",
|
||||
"slevomat/coding-standard": "^6.0",
|
||||
"vimeo/psalm": "^3.11.7 | ^4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-develop": "0.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Dhii\\Modular\\Module\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Dhii Team",
|
||||
"email": "development@dhii.co"
|
||||
}
|
||||
],
|
||||
"description": "Interfaces for modules",
|
||||
"support": {
|
||||
"issues": "https://github.com/Dhii/module-interface/issues",
|
||||
"source": "https://github.com/Dhii/module-interface/tree/v0.3.0-alpha2"
|
||||
},
|
||||
"time": "2021-08-23T08:23:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
"version": "1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/container.git",
|
||||
"reference": "8622567409010282b7aeebe4bb841fe98b58dcaf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf",
|
||||
"reference": "8622567409010282b7aeebe4bb841fe98b58dcaf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Container\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common Container Interface (PHP FIG PSR-11)",
|
||||
"homepage": "https://github.com/php-fig/container",
|
||||
"keywords": [
|
||||
"PSR-11",
|
||||
"container",
|
||||
"container-interface",
|
||||
"container-interop",
|
||||
"psr"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-fig/container/issues",
|
||||
"source": "https://github.com/php-fig/container/tree/1.1.1"
|
||||
},
|
||||
"time": "2021-03-05T17:36:06+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^7.2 | ^8.0"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
185
modules/ppcp-applepay/extensions.php
Normal file
185
modules/ppcp-applepay/extensions.php
Normal file
|
@ -0,0 +1,185 @@
|
|||
<?php
|
||||
/**
|
||||
* The Applepay module extensions.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Applepay
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Applepay;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Applepay\Assets\PropertiesDictionary;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
|
||||
return array(
|
||||
'wcgateway.settings.fields' => function ( ContainerInterface $container, array $fields ): array {
|
||||
|
||||
// Eligibility check.
|
||||
if ( ! $container->has( 'applepay.eligible' ) || ! $container->get( 'applepay.eligible' ) ) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$is_available = $container->get( 'applepay.available' );
|
||||
$is_referral = $container->get( 'applepay.is_referral' );
|
||||
|
||||
$insert_after = function ( array $array, string $key, array $new ): array {
|
||||
$keys = array_keys( $array );
|
||||
$index = array_search( $key, $keys, true );
|
||||
$pos = false === $index ? count( $array ) : $index + 1;
|
||||
|
||||
return array_merge( array_slice( $array, 0, $pos ), $new, array_slice( $array, $pos ) );
|
||||
};
|
||||
$display_manager = $container->get( 'wcgateway.display-manager' );
|
||||
assert( $display_manager instanceof DisplayManager );
|
||||
|
||||
// Connection tab fields.
|
||||
$fields = $insert_after(
|
||||
$fields,
|
||||
'ppcp_dcc_status',
|
||||
array(
|
||||
'applepay_status' => array(
|
||||
'title' => __( 'Apple Pay Payments', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'ppcp-text',
|
||||
'text' => $container->get( 'applepay.settings.connection.status-text' ),
|
||||
'screens' => array(
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! $is_available && $is_referral ) {
|
||||
$connection_url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=ppcp-connection#field-credentials_feature_onboarding_heading' );
|
||||
$connection_link = '<a href="' . $connection_url . '" style="pointer-events: auto">';
|
||||
return $insert_after(
|
||||
$fields,
|
||||
'allow_card_button_gateway',
|
||||
array(
|
||||
'applepay_button_enabled' => array(
|
||||
'title' => __( 'Apple Pay Button', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'class' => array( 'ppcp-grayed-out-text' ),
|
||||
'input_class' => array( 'ppcp-disabled-checkbox' ),
|
||||
'label' => __( 'Enable Apple Pay button', 'woocommerce-paypal-payments' )
|
||||
. '<p class="description">'
|
||||
. sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__( 'Your PayPal account %1$srequires additional permissions%2$s to enable Apple Pay.', 'woocommerce-paypal-payments' ),
|
||||
$connection_link,
|
||||
'</a>'
|
||||
)
|
||||
. '</p>',
|
||||
'default' => 'yes',
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
'custom_attributes' => array(
|
||||
'data-ppcp-display' => wp_json_encode(
|
||||
array(
|
||||
$display_manager
|
||||
->rule()
|
||||
->condition_is_true( false )
|
||||
->action_enable( 'applepay_button_enabled' )
|
||||
->to_array(),
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $insert_after(
|
||||
$fields,
|
||||
'allow_card_button_gateway',
|
||||
array(
|
||||
'applepay_button_enabled' => array(
|
||||
'title' => __( 'Apple Pay Button', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Enable Apple Pay button', 'woocommerce-paypal-payments' )
|
||||
. '<p class="description">'
|
||||
. sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__( 'Buyers can use %1$sApple Pay%2$s to make payments on the web using the Safari web browser or an iOS device.', 'woocommerce-paypal-payments' ),
|
||||
'<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#apple-pay" target="_blank">',
|
||||
'</a>'
|
||||
)
|
||||
. '</p>',
|
||||
'default' => 'yes',
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
'custom_attributes' => array(
|
||||
'data-ppcp-display' => wp_json_encode(
|
||||
array(
|
||||
$display_manager
|
||||
->rule()
|
||||
->condition_element( 'applepay_button_enabled', '1' )
|
||||
->action_visible( 'applepay_button_color' )
|
||||
->action_visible( 'applepay_button_type' )
|
||||
->action_visible( 'applepay_button_language' )
|
||||
->to_array(),
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
'applepay_button_type' => array(
|
||||
'title' => str_repeat( ' ', 6 ) . __( 'Button Label', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'desc_tip' => true,
|
||||
'description' => __(
|
||||
'This controls the label of the Apple Pay button.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'pay',
|
||||
'options' => PropertiesDictionary::button_types(),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
),
|
||||
'applepay_button_color' => array(
|
||||
'title' => str_repeat( ' ', 6 ) . __( 'Button Color', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'desc_tip' => true,
|
||||
'description' => __(
|
||||
'The Apple Pay Button may appear as a black button with white lettering, white button with black lettering, or a white button with black lettering and a black outline.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'label' => '',
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'class' => array(),
|
||||
'default' => 'black',
|
||||
'options' => PropertiesDictionary::button_colors(),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
),
|
||||
'applepay_button_language' => array(
|
||||
'title' => str_repeat( ' ', 6 ) . __( 'Button Language', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'desc_tip' => true,
|
||||
'description' => __(
|
||||
'The language and region used for the displayed Apple Pay button. The default value is the current language and region setting in a browser.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'en',
|
||||
'options' => PropertiesDictionary::button_languages(),
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
),
|
||||
)
|
||||
);
|
||||
},
|
||||
);
|
16
modules/ppcp-applepay/module.php
Normal file
16
modules/ppcp-applepay/module.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* The Applepay module.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Applepay
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Applepay;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
|
||||
return static function (): ModuleInterface {
|
||||
return new ApplepayModule();
|
||||
};
|
34
modules/ppcp-applepay/package.json
Normal file
34
modules/ppcp-applepay/package.json
Normal file
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "ppcp-applepay",
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"browserslist": [
|
||||
"> 0.5%",
|
||||
"Safari >= 8",
|
||||
"Chrome >= 41",
|
||||
"Firefox >= 43",
|
||||
"Edge >= 14"
|
||||
],
|
||||
"dependencies": {
|
||||
"@paypal/paypal-js": "^6.0.0",
|
||||
"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"
|
||||
}
|
||||
}
|
56
modules/ppcp-applepay/resources/css/styles.scss
Normal file
56
modules/ppcp-applepay/resources/css/styles.scss
Normal file
|
@ -0,0 +1,56 @@
|
|||
#applepay-container {
|
||||
--apple-pay-button-height: 45px;
|
||||
--apple-pay-button-min-height: 40px;
|
||||
--apple-pay-button-width: 100%;
|
||||
--apple-pay-button-max-width: 750px;
|
||||
--apple-pay-button-border-radius: 4px;
|
||||
--apple-pay-button-overflow: hidden;
|
||||
--apple-pay-button-margin:7px 0;
|
||||
&.ppcp-button-pill {
|
||||
--apple-pay-button-border-radius: 50px;
|
||||
}
|
||||
|
||||
&.ppcp-button-minicart {
|
||||
--apple-pay-button-display: block;
|
||||
--apple-pay-button-height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-checkout {
|
||||
#applepay-container {
|
||||
margin-top: 0.5em;
|
||||
--apple-pay-button-border-radius: 4px;
|
||||
--apple-pay-button-height: 45px;
|
||||
&.ppcp-button-pill {
|
||||
--apple-pay-button-border-radius: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ppcp-has-applepay-block {
|
||||
|
||||
.wp-block-woocommerce-checkout {
|
||||
#applepay-container {
|
||||
--apple-pay-button-margin: 0;
|
||||
--apple-pay-button-height: 40px;
|
||||
&.ppcp-button-pill {
|
||||
--apple-pay-button-border-radius: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wp-block-woocommerce-cart {
|
||||
#applepay-container {
|
||||
--apple-pay-button-margin: 0;
|
||||
--apple-pay-button-height: 40px;
|
||||
}
|
||||
/* Workaround for blocks grid */
|
||||
.wc-block-components-express-payment__event-buttons {
|
||||
--apple-pay-button-display: block;
|
||||
li[id*="express-payment-method-ppcp-"] {
|
||||
--apple-pay-button-padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
588
modules/ppcp-applepay/resources/js/ApplepayButton.js
Normal file
588
modules/ppcp-applepay/resources/js/ApplepayButton.js
Normal file
|
@ -0,0 +1,588 @@
|
|||
import ContextHandlerFactory from "./Context/ContextHandlerFactory";
|
||||
import {createAppleErrors} from "./Helper/applePayError";
|
||||
import {setVisible} from '../../../ppcp-button/resources/js/modules/Helper/Hiding';
|
||||
import {setEnabled} from '../../../ppcp-button/resources/js/modules/Helper/ButtonDisabler';
|
||||
import FormValidator from "../../../ppcp-button/resources/js/modules/Helper/FormValidator";
|
||||
import ErrorHandler from '../../../ppcp-button/resources/js/modules/ErrorHandler';
|
||||
|
||||
class ApplepayButton {
|
||||
|
||||
constructor(context, externalHandler, buttonConfig, ppcpConfig) {
|
||||
this.isInitialized = false;
|
||||
|
||||
this.context = context;
|
||||
this.externalHandler = externalHandler;
|
||||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
this.paymentsClient = null;
|
||||
this.form_saved = false;
|
||||
|
||||
this.contextHandler = ContextHandlerFactory.create(
|
||||
this.context,
|
||||
this.buttonConfig,
|
||||
this.ppcpConfig
|
||||
);
|
||||
|
||||
this.updated_contact_info = []
|
||||
this.selectedShippingMethod = []
|
||||
this.nonce = document.getElementById('woocommerce-process-checkout-nonce')?.value
|
||||
|
||||
this.log = function() {
|
||||
if ( this.buttonConfig.is_debug ) {
|
||||
console.log('[ApplePayButton]', ...arguments);
|
||||
}
|
||||
}
|
||||
|
||||
this.refreshContextData();
|
||||
}
|
||||
|
||||
init(config) {
|
||||
if (this.isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.log('Init', this.context);
|
||||
this.initEventHandlers();
|
||||
this.isInitialized = true;
|
||||
this.applePayConfig = config;
|
||||
const isEligible = this.applePayConfig.isEligible;
|
||||
if (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;
|
||||
|
||||
if (this.context === 'mini-cart') {
|
||||
document.querySelector(id_minicart)?.addEventListener('click', (evt) => {
|
||||
evt.preventDefault();
|
||||
this.onButtonClick();
|
||||
});
|
||||
} else {
|
||||
document.querySelector(id)?.addEventListener('click', (evt) => {
|
||||
evt.preventDefault();
|
||||
this.onButtonClick();
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for changes on any input within the WooCommerce checkout form
|
||||
jQuery('form.checkout').on('change', 'input, select, textarea', () => {
|
||||
this.fetchTransactionInfo();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
reinit() {
|
||||
if (!this.applePayConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isInitialized = false;
|
||||
this.init(this.applePayConfig);
|
||||
}
|
||||
|
||||
async fetchTransactionInfo() {
|
||||
this.transactionInfo = await this.contextHandler.transactionInfo();
|
||||
}
|
||||
/**
|
||||
* Returns configurations relative to this button context.
|
||||
*/
|
||||
contextConfig() {
|
||||
let config = {
|
||||
wrapper: this.buttonConfig.button.wrapper,
|
||||
ppcpStyle: this.ppcpConfig.button.style,
|
||||
//buttonStyle: this.buttonConfig.button.style,
|
||||
ppcpButtonWrapper: this.ppcpConfig.button.wrapper
|
||||
}
|
||||
|
||||
if (this.context === 'mini-cart') {
|
||||
config.wrapper = this.buttonConfig.button.mini_cart_wrapper;
|
||||
config.ppcpStyle = this.ppcpConfig.button.mini_cart_style;
|
||||
config.buttonStyle = this.buttonConfig.button.mini_cart_style;
|
||||
config.ppcpButtonWrapper = this.ppcpConfig.button.mini_cart_wrapper;
|
||||
}
|
||||
|
||||
if (['cart-block', 'checkout-block'].indexOf(this.context) !== -1) {
|
||||
config.ppcpButtonWrapper = '#express-payment-method-ppcp-gateway';
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
initEventHandlers() {
|
||||
const { wrapper, ppcpButtonWrapper } = this.contextConfig();
|
||||
const wrapper_id = '#' + wrapper;
|
||||
|
||||
const syncButtonVisibility = () => {
|
||||
const $ppcpButtonWrapper = jQuery(ppcpButtonWrapper);
|
||||
setVisible(wrapper_id, $ppcpButtonWrapper.is(':visible'));
|
||||
setEnabled(wrapper_id, !$ppcpButtonWrapper.hasClass('ppcp-disabled'));
|
||||
}
|
||||
|
||||
jQuery(document).on('ppcp-shown ppcp-hidden ppcp-enabled ppcp-disabled', (ev, data) => {
|
||||
if (jQuery(data.selector).is(ppcpButtonWrapper)) {
|
||||
syncButtonVisibility();
|
||||
}
|
||||
});
|
||||
|
||||
syncButtonVisibility();
|
||||
}
|
||||
|
||||
applePaySession(paymentRequest) {
|
||||
this.log('applePaySession', paymentRequest);
|
||||
const session = new ApplePaySession(4, paymentRequest)
|
||||
session.begin()
|
||||
|
||||
if (this.buttonConfig.product.needShipping) {
|
||||
session.onshippingmethodselected = this.onshippingmethodselected(session)
|
||||
session.onshippingcontactselected = this.onshippingcontactselected(session)
|
||||
}
|
||||
session.onvalidatemerchant = this.onvalidatemerchant(session);
|
||||
session.onpaymentauthorized = this.onpaymentauthorized(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add a Apple Pay purchase button
|
||||
*/
|
||||
addButton() {
|
||||
const wrapper =
|
||||
(this.context === 'mini-cart')
|
||||
? this.buttonConfig.button.mini_cart_wrapper
|
||||
: this.buttonConfig.button.wrapper;
|
||||
const shape =
|
||||
(this.context === 'mini-cart')
|
||||
? this.ppcpConfig.button.mini_cart_style.shape
|
||||
: this.ppcpConfig.button.style.shape;
|
||||
const appleContainer = this.context === 'mini-cart' ? document.getElementById("applepay-container-minicart") : document.getElementById("applepay-container");
|
||||
const type = this.buttonConfig.button.type;
|
||||
const language = this.buttonConfig.button.lang;
|
||||
const color = this.buttonConfig.button.color;
|
||||
const id = "apple-" + wrapper;
|
||||
|
||||
if (appleContainer) {
|
||||
appleContainer.innerHTML = `<apple-pay-button id="${id}" buttonstyle="${color}" type="${type}" locale="${language}">`;
|
||||
}
|
||||
|
||||
jQuery('#' + wrapper).addClass('ppcp-button-' + shape);
|
||||
jQuery(wrapper).append(appleContainer);
|
||||
}
|
||||
|
||||
//------------------------
|
||||
// Button click
|
||||
//------------------------
|
||||
|
||||
/**
|
||||
* Show Apple Pay payment sheet when Apple Pay payment button is clicked
|
||||
*/
|
||||
async onButtonClick() {
|
||||
this.log('onButtonClick', this.context);
|
||||
|
||||
const paymentDataRequest = this.paymentDataRequest();
|
||||
// trigger woocommerce validation if we are in the checkout page
|
||||
if (this.context === 'checkout') {
|
||||
const checkoutFormSelector = 'form.woocommerce-checkout';
|
||||
const errorHandler = new ErrorHandler(
|
||||
PayPalCommerceGateway.labels.error.generic,
|
||||
document.querySelector('.woocommerce-notices-wrapper')
|
||||
);
|
||||
try {
|
||||
const formData = new FormData(document.querySelector(checkoutFormSelector));
|
||||
this.form_saved = Object.fromEntries(formData.entries());
|
||||
// This line should be reviewed, the paypal.Applepay().confirmOrder fails if we add it.
|
||||
//this.update_request_data_with_form(paymentDataRequest);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
const session = this.applePaySession(paymentDataRequest)
|
||||
const formValidator = PayPalCommerceGateway.early_checkout_validation_enabled ?
|
||||
new FormValidator(
|
||||
PayPalCommerceGateway.ajax.validate_checkout.endpoint,
|
||||
PayPalCommerceGateway.ajax.validate_checkout.nonce,
|
||||
) : null;
|
||||
if (formValidator) {
|
||||
try {
|
||||
const errors = await formValidator.validate(document.querySelector(checkoutFormSelector));
|
||||
if (errors.length > 0) {
|
||||
errorHandler.messages(errors);
|
||||
jQuery( document.body ).trigger( 'checkout_error' , [ errorHandler.currentHtml() ] );
|
||||
session.abort();
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.applePaySession(paymentDataRequest)
|
||||
}
|
||||
|
||||
update_request_data_with_form(paymentDataRequest) {
|
||||
paymentDataRequest.billingContact = this.fill_billing_contact(this.form_saved);
|
||||
paymentDataRequest.applicationData = this.fill_application_data(this.form_saved);
|
||||
if (!this.buttonConfig.product.needShipping) {
|
||||
return;
|
||||
}
|
||||
paymentDataRequest.shippingContact = this.fill_shipping_contact(this.form_saved);
|
||||
}
|
||||
|
||||
paymentDataRequest() {
|
||||
const applepayConfig = this.applePayConfig
|
||||
const buttonConfig = this.buttonConfig
|
||||
let baseRequest = {
|
||||
countryCode: applepayConfig.countryCode,
|
||||
merchantCapabilities: applepayConfig.merchantCapabilities,
|
||||
supportedNetworks: applepayConfig.supportedNetworks,
|
||||
requiredShippingContactFields: ["postalAddress", "email", "phone"],
|
||||
requiredBillingContactFields: ["postalAddress", "email", "phone"],
|
||||
}
|
||||
const paymentDataRequest = Object.assign({}, baseRequest);
|
||||
paymentDataRequest.currencyCode = buttonConfig.shop.currencyCode;
|
||||
paymentDataRequest.total = {
|
||||
label: buttonConfig.shop.totalLabel,
|
||||
type: "final",
|
||||
amount: this.transactionInfo.totalPrice,
|
||||
}
|
||||
|
||||
return paymentDataRequest
|
||||
}
|
||||
|
||||
refreshContextData() {
|
||||
switch (this.context) {
|
||||
case 'product':
|
||||
// Refresh product data that makes the price change.
|
||||
this.productQuantity = document.querySelector('input.qty').value;
|
||||
this.products = this.contextHandler.products();
|
||||
this.log('Products updated', this.products);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------
|
||||
// Payment process
|
||||
//------------------------
|
||||
|
||||
onvalidatemerchant(session) {
|
||||
this.log('onvalidatemerchant', this.buttonConfig.ajax_url);
|
||||
return (applePayValidateMerchantEvent) => {
|
||||
this.log('onvalidatemerchant call');
|
||||
|
||||
paypal.Applepay().validateMerchant({
|
||||
validationUrl: applePayValidateMerchantEvent.validationURL
|
||||
})
|
||||
.then(validateResult => {
|
||||
this.log('onvalidatemerchant ok');
|
||||
session.completeMerchantValidation(validateResult.merchantSession);
|
||||
//call backend to update validation to true
|
||||
jQuery.ajax({
|
||||
url: this.buttonConfig.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'ppcp_validate',
|
||||
validation: true,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(validateError => {
|
||||
this.log('onvalidatemerchant error', validateError);
|
||||
console.error(validateError);
|
||||
//call backend to update validation to false
|
||||
jQuery.ajax({
|
||||
url: this.buttonConfig.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'ppcp_validate',
|
||||
validation: false,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
}
|
||||
})
|
||||
this.log('onvalidatemerchant session abort');
|
||||
session.abort();
|
||||
});
|
||||
};
|
||||
}
|
||||
onshippingmethodselected(session) {
|
||||
this.log('onshippingmethodselected', this.buttonConfig.ajax_url);
|
||||
const ajax_url = this.buttonConfig.ajax_url
|
||||
return (event) => {
|
||||
this.log('onshippingmethodselected call');
|
||||
|
||||
const data = this.getShippingMethodData(event);
|
||||
jQuery.ajax({
|
||||
url: ajax_url,
|
||||
method: 'POST',
|
||||
data: data,
|
||||
success: (applePayShippingMethodUpdate, textStatus, jqXHR) => {
|
||||
this.log('onshippingmethodselected ok');
|
||||
let response = applePayShippingMethodUpdate.data
|
||||
if (applePayShippingMethodUpdate.success === false) {
|
||||
response.errors = createAppleErrors(response.errors)
|
||||
}
|
||||
this.selectedShippingMethod = event.shippingMethod
|
||||
//order the response shipping methods, so that the selected shipping method is the first one
|
||||
let orderedShippingMethods = response.newShippingMethods.sort((a, b) => {
|
||||
if (a.label === this.selectedShippingMethod.label) {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
})
|
||||
//update the response.newShippingMethods with the ordered shipping methods
|
||||
response.newShippingMethods = orderedShippingMethods
|
||||
if (applePayShippingMethodUpdate.success === false) {
|
||||
response.errors = createAppleErrors(response.errors)
|
||||
}
|
||||
session.completeShippingMethodSelection(response)
|
||||
},
|
||||
error: (jqXHR, textStatus, errorThrown) => {
|
||||
this.log('onshippingmethodselected error', textStatus);
|
||||
console.warn(textStatus, errorThrown)
|
||||
session.abort()
|
||||
},
|
||||
})
|
||||
};
|
||||
}
|
||||
onshippingcontactselected(session) {
|
||||
this.log('onshippingcontactselected', this.buttonConfig.ajax_url);
|
||||
const ajax_url = this.buttonConfig.ajax_url
|
||||
return (event) => {
|
||||
this.log('onshippingcontactselected call');
|
||||
|
||||
const data = this.getShippingContactData(event);
|
||||
jQuery.ajax({
|
||||
url: ajax_url,
|
||||
method: 'POST',
|
||||
data: data,
|
||||
success: (applePayShippingContactUpdate, textStatus, jqXHR) => {
|
||||
this.log('onshippingcontactselected ok');
|
||||
let response = applePayShippingContactUpdate.data
|
||||
this.updated_contact_info = event.shippingContact
|
||||
if (applePayShippingContactUpdate.success === false) {
|
||||
response.errors = createAppleErrors(response.errors)
|
||||
}
|
||||
if (response.newShippingMethods) {
|
||||
this.selectedShippingMethod = response.newShippingMethods[0]
|
||||
}
|
||||
session.completeShippingContactSelection(response)
|
||||
},
|
||||
error: (jqXHR, textStatus, errorThrown) => {
|
||||
this.log('onshippingcontactselected error', textStatus);
|
||||
console.warn(textStatus, errorThrown)
|
||||
session.abort()
|
||||
},
|
||||
})
|
||||
};
|
||||
}
|
||||
getShippingContactData(event) {
|
||||
const product_id = this.buttonConfig.product.id;
|
||||
|
||||
this.refreshContextData();
|
||||
|
||||
switch (this.context) {
|
||||
case 'product':
|
||||
return {
|
||||
action: 'ppcp_update_shipping_contact',
|
||||
product_id: product_id,
|
||||
products: JSON.stringify(this.products),
|
||||
caller_page: 'productDetail',
|
||||
product_quantity: this.productQuantity,
|
||||
simplified_contact: event.shippingContact,
|
||||
need_shipping: this.buttonConfig.product.needShipping,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
};
|
||||
case 'cart':
|
||||
case 'checkout':
|
||||
case 'cart-block':
|
||||
case 'checkout-block':
|
||||
case 'mini-cart':
|
||||
return {
|
||||
action: 'ppcp_update_shipping_contact',
|
||||
simplified_contact: event.shippingContact,
|
||||
caller_page: 'cart',
|
||||
need_shipping: this.buttonConfig.product.needShipping,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
};
|
||||
}
|
||||
}
|
||||
getShippingMethodData(event) {
|
||||
const product_id = this.buttonConfig.product.id;
|
||||
|
||||
this.refreshContextData();
|
||||
|
||||
switch (this.context) {
|
||||
case 'product': return {
|
||||
action: 'ppcp_update_shipping_method',
|
||||
shipping_method: event.shippingMethod,
|
||||
product_id: product_id,
|
||||
products: JSON.stringify(this.products),
|
||||
caller_page: 'productDetail',
|
||||
product_quantity: this.productQuantity,
|
||||
simplified_contact: this.updated_contact_info,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
}
|
||||
case 'cart':
|
||||
case 'checkout':
|
||||
case 'cart-block':
|
||||
case 'checkout-block':
|
||||
case 'mini-cart':
|
||||
return {
|
||||
action: 'ppcp_update_shipping_method',
|
||||
shipping_method: event.shippingMethod,
|
||||
caller_page: 'cart',
|
||||
simplified_contact: this.updated_contact_info,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onpaymentauthorized(session) {
|
||||
this.log('onpaymentauthorized');
|
||||
return async (event) => {
|
||||
this.log('onpaymentauthorized call');
|
||||
|
||||
function form() {
|
||||
return document.querySelector('form.cart');
|
||||
}
|
||||
const processInWooAndCapture = async (data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const billingContact = data.billing_contact
|
||||
const shippingContact = data.shipping_contact
|
||||
let request_data = {
|
||||
action: 'ppcp_create_order',
|
||||
'caller_page': this.context,
|
||||
'product_id': this.buttonConfig.product.id ?? null,
|
||||
'products': JSON.stringify(this.products),
|
||||
'product_quantity': this.productQuantity ?? null,
|
||||
'shipping_contact': shippingContact,
|
||||
'billing_contact': billingContact,
|
||||
'token': event.payment.token,
|
||||
'shipping_method': this.selectedShippingMethod,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
'funding_source': 'applepay',
|
||||
'_wp_http_referer': '/?wc-ajax=update_order_review',
|
||||
'paypal_order_id': data.paypal_order_id,
|
||||
};
|
||||
|
||||
this.log('onpaymentauthorized request', this.buttonConfig.ajax_url, data);
|
||||
|
||||
jQuery.ajax({
|
||||
url: this.buttonConfig.ajax_url,
|
||||
method: 'POST',
|
||||
data: request_data,
|
||||
complete: (jqXHR, textStatus) => {
|
||||
this.log('onpaymentauthorized complete');
|
||||
},
|
||||
success: (authorizationResult, textStatus, jqXHR) => {
|
||||
this.log('onpaymentauthorized ok');
|
||||
resolve(authorizationResult)
|
||||
},
|
||||
error: (jqXHR, textStatus, errorThrown) => {
|
||||
this.log('onpaymentauthorized error', textStatus);
|
||||
reject(new Error(errorThrown));
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
this.log('onpaymentauthorized catch', error);
|
||||
console.log(error) // handle error
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let id = await this.contextHandler.createOrder();
|
||||
|
||||
this.log('onpaymentauthorized paypal order ID', id, event.payment.token, event.payment.billingContact);
|
||||
|
||||
try {
|
||||
const confirmOrderResponse = await paypal.Applepay().confirmOrder({
|
||||
orderId: id,
|
||||
token: event.payment.token,
|
||||
billingContact: event.payment.billingContact,
|
||||
});
|
||||
|
||||
this.log('onpaymentauthorized confirmOrderResponse', confirmOrderResponse);
|
||||
|
||||
if (confirmOrderResponse && confirmOrderResponse.approveApplePayPayment) {
|
||||
if (confirmOrderResponse.approveApplePayPayment.status === "APPROVED") {
|
||||
try {
|
||||
let data = {
|
||||
billing_contact: event.payment.billingContact,
|
||||
shipping_contact: event.payment.shippingContact,
|
||||
paypal_order_id: id,
|
||||
};
|
||||
let authorizationResult = await processInWooAndCapture(data);
|
||||
if (authorizationResult.result === "success") {
|
||||
session.completePayment(ApplePaySession.STATUS_SUCCESS)
|
||||
window.location.href = authorizationResult.redirect
|
||||
} else {
|
||||
session.completePayment(ApplePaySession.STATUS_FAILURE)
|
||||
}
|
||||
} catch (error) {
|
||||
session.completePayment(ApplePaySession.STATUS_FAILURE);
|
||||
session.abort()
|
||||
console.error(error);
|
||||
}
|
||||
} else {
|
||||
console.error('Error status is not APPROVED');
|
||||
session.completePayment(ApplePaySession.STATUS_FAILURE);
|
||||
}
|
||||
} else {
|
||||
console.error('Invalid confirmOrderResponse');
|
||||
session.completePayment(ApplePaySession.STATUS_FAILURE);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error confirming order with applepay token', error);
|
||||
session.completePayment(ApplePaySession.STATUS_FAILURE);
|
||||
session.abort()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fill_billing_contact(form_saved) {
|
||||
return {
|
||||
givenName: form_saved.billing_first_name ?? '',
|
||||
familyName: form_saved.billing_last_name ?? '',
|
||||
emailAddress: form_saved.billing_email ?? '',
|
||||
phoneNumber: form_saved.billing_phone ?? '',
|
||||
addressLines: [form_saved.billing_address_1, form_saved.billing_address_2],
|
||||
locality: form_saved.billing_city ?? '',
|
||||
postalCode: form_saved.billing_postcode ?? '',
|
||||
countryCode: form_saved.billing_country ?? '',
|
||||
administrativeArea: form_saved.billing_state ?? '',
|
||||
}
|
||||
}
|
||||
fill_shipping_contact(form_saved) {
|
||||
if (form_saved.shipping_first_name === "") {
|
||||
return this.fill_billing_contact(form_saved)
|
||||
}
|
||||
return {
|
||||
givenName: (form_saved?.shipping_first_name && form_saved.shipping_first_name !== "") ? form_saved.shipping_first_name : form_saved?.billing_first_name,
|
||||
familyName: (form_saved?.shipping_last_name && form_saved.shipping_last_name !== "") ? form_saved.shipping_last_name : form_saved?.billing_last_name,
|
||||
emailAddress: (form_saved?.shipping_email && form_saved.shipping_email !== "") ? form_saved.shipping_email : form_saved?.billing_email,
|
||||
phoneNumber: (form_saved?.shipping_phone && form_saved.shipping_phone !== "") ? form_saved.shipping_phone : form_saved?.billing_phone,
|
||||
addressLines: [form_saved.shipping_address_1 ?? '', form_saved.shipping_address_2 ?? ''],
|
||||
locality: (form_saved?.shipping_city && form_saved.shipping_city !== "") ? form_saved.shipping_city : form_saved?.billing_city,
|
||||
postalCode: (form_saved?.shipping_postcode && form_saved.shipping_postcode !== "") ? form_saved.shipping_postcode : form_saved?.billing_postcode,
|
||||
countryCode: (form_saved?.shipping_country && form_saved.shipping_country !== "") ? form_saved.shipping_country : form_saved?.billing_country,
|
||||
administrativeArea: (form_saved?.shipping_state && form_saved.shipping_state !== "") ? form_saved.shipping_state : form_saved?.billing_state,
|
||||
}
|
||||
}
|
||||
|
||||
fill_application_data(form_saved) {
|
||||
const jsonString = JSON.stringify(form_saved);
|
||||
let utf8Str = encodeURIComponent(jsonString).replace(/%([0-9A-F]{2})/g, (match, p1) => {
|
||||
return String.fromCharCode('0x' + p1);
|
||||
});
|
||||
|
||||
return btoa(utf8Str);
|
||||
}
|
||||
}
|
||||
|
||||
export default ApplepayButton;
|
55
modules/ppcp-applepay/resources/js/ApplepayManager.js
Normal file
55
modules/ppcp-applepay/resources/js/ApplepayManager.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
import buttonModuleWatcher from "../../../ppcp-button/resources/js/modules/ButtonModuleWatcher";
|
||||
import ApplepayButton from "./ApplepayButton";
|
||||
|
||||
class ApplepayManager {
|
||||
|
||||
constructor(buttonConfig, ppcpConfig) {
|
||||
|
||||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
this.ApplePayConfig = null;
|
||||
this.buttons = [];
|
||||
|
||||
buttonModuleWatcher.watchContextBootstrap((bootstrap) => {
|
||||
const button = new ApplepayButton(
|
||||
bootstrap.context,
|
||||
bootstrap.handler,
|
||||
buttonConfig,
|
||||
ppcpConfig,
|
||||
);
|
||||
|
||||
this.buttons.push(button);
|
||||
|
||||
if (this.ApplePayConfig) {
|
||||
button.init(this.ApplePayConfig);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
init() {
|
||||
(async () => {
|
||||
await this.config();
|
||||
for (const button of this.buttons) {
|
||||
button.init(this.ApplePayConfig);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
reinit() {
|
||||
for (const button of this.buttons) {
|
||||
button.reinit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ApplePay configuration of the PayPal merchant.
|
||||
* @returns {Promise<null>}
|
||||
*/
|
||||
async config() {
|
||||
this.ApplePayConfig = await paypal.Applepay().config();
|
||||
return this.ApplePayConfig;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ApplepayManager;
|
73
modules/ppcp-applepay/resources/js/Context/BaseHandler.js
Normal file
73
modules/ppcp-applepay/resources/js/Context/BaseHandler.js
Normal file
|
@ -0,0 +1,73 @@
|
|||
import ErrorHandler from "../../../../ppcp-button/resources/js/modules/ErrorHandler";
|
||||
import CartActionHandler
|
||||
from "../../../../ppcp-button/resources/js/modules/ActionHandler/CartActionHandler";
|
||||
import onApprove
|
||||
from "../../../../ppcp-button/resources/js/modules/OnApproveHandler/onApproveForContinue";
|
||||
|
||||
class BaseHandler {
|
||||
|
||||
constructor(buttonConfig, ppcpConfig) {
|
||||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
}
|
||||
|
||||
transactionInfo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
fetch(
|
||||
this.ppcpConfig.ajax.cart_script_params.endpoint,
|
||||
{
|
||||
method: 'GET',
|
||||
credentials: 'same-origin',
|
||||
}
|
||||
)
|
||||
.then(result => result.json())
|
||||
.then(result => {
|
||||
if (! result.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
// handle script reload
|
||||
const data = result.data;
|
||||
|
||||
resolve({
|
||||
countryCode: data.country_code,
|
||||
currencyCode: data.currency_code,
|
||||
totalPriceStatus: 'FINAL',
|
||||
totalPrice: data.total_str
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
createOrder() {
|
||||
const errorHandler = new ErrorHandler(
|
||||
this.ppcpConfig.labels.error.generic,
|
||||
document.querySelector('.woocommerce-notices-wrapper')
|
||||
);
|
||||
|
||||
const actionHandler = new CartActionHandler(
|
||||
this.ppcpConfig,
|
||||
errorHandler,
|
||||
);
|
||||
|
||||
return actionHandler.configuration().createOrder(null, null);
|
||||
}
|
||||
|
||||
approveOrderForContinue(data, actions) {
|
||||
const errorHandler = new ErrorHandler(
|
||||
this.ppcpConfig.labels.error.generic,
|
||||
document.querySelector('.woocommerce-notices-wrapper')
|
||||
);
|
||||
|
||||
let onApproveHandler = onApprove({
|
||||
config: this.ppcpConfig
|
||||
}, errorHandler);
|
||||
|
||||
return onApproveHandler(data, actions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BaseHandler;
|
|
@ -0,0 +1,7 @@
|
|||
import BaseHandler from "./BaseHandler";
|
||||
|
||||
class CartBlockHandler extends BaseHandler {
|
||||
|
||||
}
|
||||
|
||||
export default CartBlockHandler;
|
|
@ -0,0 +1,7 @@
|
|||
import BaseHandler from "./BaseHandler";
|
||||
|
||||
class CartHandler extends BaseHandler {
|
||||
|
||||
}
|
||||
|
||||
export default CartHandler;
|
|
@ -0,0 +1,7 @@
|
|||
import BaseHandler from "./BaseHandler";
|
||||
|
||||
class CheckoutBlockHandler extends BaseHandler{
|
||||
|
||||
}
|
||||
|
||||
export default CheckoutBlockHandler;
|
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