mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 12:25:15 +08:00
Add PurchaseUnitSanitizer tests
Add subtotal mismatch admin options
This commit is contained in:
parent
c15b8ee463
commit
837bdb0392
6 changed files with 314 additions and 50 deletions
|
@ -17,6 +17,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentPreferencesFactory;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PlanFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ProductFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingOptionFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\PurchaseUnitSanitizer;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
|
@ -299,6 +300,7 @@ return array(
|
|||
$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,
|
||||
|
@ -308,7 +310,8 @@ return array(
|
|||
$shipping_factory,
|
||||
$payments_factory,
|
||||
$prefix,
|
||||
$soft_descriptor
|
||||
$soft_descriptor,
|
||||
$sanitizer
|
||||
);
|
||||
},
|
||||
'api.factory.patch-collection-factory' => static function ( ContainerInterface $container ): PatchCollectionFactory {
|
||||
|
@ -814,4 +817,12 @@ return array(
|
|||
'api.order-helper' => static function( ContainerInterface $container ): OrderHelper {
|
||||
return new OrderHelper();
|
||||
},
|
||||
'api.helper.purchase-unit-sanitizer' => 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 );
|
||||
},
|
||||
);
|
||||
|
|
|
@ -93,6 +93,13 @@ class PurchaseUnit {
|
|||
*/
|
||||
private $contains_physical_goods = false;
|
||||
|
||||
/**
|
||||
* The sanitizer for this purchase unit output.
|
||||
*
|
||||
* @var PurchaseUnitSanitizer|null
|
||||
*/
|
||||
private $sanitizer;
|
||||
|
||||
/**
|
||||
* PurchaseUnit constructor.
|
||||
*
|
||||
|
@ -222,6 +229,16 @@ class PurchaseUnit {
|
|||
$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.
|
||||
*
|
||||
|
@ -317,8 +334,8 @@ class PurchaseUnit {
|
|||
$purchase_unit['soft_descriptor'] = $this->soft_descriptor();
|
||||
}
|
||||
|
||||
if ( $sanitize_output ) {
|
||||
$purchase_unit = ( new PurchaseUnitSanitizer( $purchase_unit, $this->items() ) )->sanitize();
|
||||
if ( $sanitize_output && isset( $this->sanitizer ) ) {
|
||||
$purchase_unit = ( $this->sanitizer->sanitize( $purchase_unit, $this->items() ) );
|
||||
}
|
||||
|
||||
return $purchase_unit;
|
||||
|
|
|
@ -13,6 +13,7 @@ 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\Helper\PurchaseUnitSanitizer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayeeRepository;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\CustomIds;
|
||||
|
||||
|
@ -77,17 +78,25 @@ class PurchaseUnitFactory {
|
|||
*/
|
||||
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 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,
|
||||
|
@ -97,7 +106,8 @@ class PurchaseUnitFactory {
|
|||
ShippingFactory $shipping_factory,
|
||||
PaymentsFactory $payments_factory,
|
||||
string $prefix = 'WC-',
|
||||
string $soft_descriptor = ''
|
||||
string $soft_descriptor = '',
|
||||
PurchaseUnitSanitizer $sanitizer = null
|
||||
) {
|
||||
|
||||
$this->amount_factory = $amount_factory;
|
||||
|
@ -108,6 +118,7 @@ class PurchaseUnitFactory {
|
|||
$this->payments_factory = $payments_factory;
|
||||
$this->prefix = $prefix;
|
||||
$this->soft_descriptor = $soft_descriptor;
|
||||
$this->sanitizer = $sanitizer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,6 +162,9 @@ class PurchaseUnitFactory {
|
|||
$invoice_id,
|
||||
$soft_descriptor
|
||||
);
|
||||
|
||||
$this->init_purchase_unit( $purchase_unit );
|
||||
|
||||
/**
|
||||
* Returns PurchaseUnit for the WC order.
|
||||
*/
|
||||
|
@ -221,6 +235,8 @@ class PurchaseUnitFactory {
|
|||
$soft_descriptor
|
||||
);
|
||||
|
||||
$this->init_purchase_unit( $purchase_unit );
|
||||
|
||||
return $purchase_unit;
|
||||
}
|
||||
|
||||
|
@ -283,6 +299,9 @@ class PurchaseUnitFactory {
|
|||
$soft_descriptor,
|
||||
$payments
|
||||
);
|
||||
|
||||
$this->init_purchase_unit( $purchase_unit );
|
||||
|
||||
return $purchase_unit;
|
||||
}
|
||||
|
||||
|
@ -313,4 +332,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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,31 +24,80 @@ 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;
|
||||
private $purchase_unit = array();
|
||||
|
||||
/**
|
||||
* The purchase unit Item objects
|
||||
*
|
||||
* @var array|Item[]
|
||||
*/
|
||||
private $item_objects;
|
||||
private $item_objects = array();
|
||||
|
||||
/**
|
||||
* The working mode
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $mode;
|
||||
|
||||
/**
|
||||
* The name for the extra line
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $extra_line_name;
|
||||
|
||||
|
||||
/**
|
||||
* PurchaseUnitSanitizer constructor.
|
||||
*
|
||||
* @param array $purchase_unit The purchase_unit array that should be sanitized.
|
||||
* @param array|Item[] $item_objects The purchase unit Item objects used for recalculations.
|
||||
* @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( array $purchase_unit, array $item_objects ) {
|
||||
$this->purchase_unit = $purchase_unit;
|
||||
$this->item_objects = $item_objects;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if mode is ditch.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_mode_ditch(): bool {
|
||||
return $this->mode === self::MODE_DITCH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if mode is adding extra line.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_mode_extra_line(): bool {
|
||||
return $this->mode === self::MODE_EXTRA_LINE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,9 +152,14 @@ class PurchaseUnitSanitizer {
|
|||
/**
|
||||
* The sanitizes the purchase_unit array.
|
||||
*
|
||||
* @param array $purchase_unit The purchase_unit array that should be sanitized.
|
||||
* @param array|Item[] $item_objects The purchase unit Item objects used for recalculations.
|
||||
* @return array
|
||||
*/
|
||||
public function sanitize(): array {
|
||||
public function sanitize( array $purchase_unit, array $item_objects ): array {
|
||||
$this->purchase_unit = $purchase_unit;
|
||||
$this->item_objects = $item_objects;
|
||||
|
||||
$this->sanitize_item_amount_mismatch();
|
||||
$this->sanitize_item_tax_mismatch();
|
||||
$this->sanitize_breakdown_mismatch();
|
||||
|
@ -120,25 +174,28 @@ class PurchaseUnitSanitizer {
|
|||
private function sanitize_item_amount_mismatch(): void {
|
||||
$item_mismatch = $this->calculate_item_mismatch();
|
||||
|
||||
if ( $item_mismatch < 0 ) {
|
||||
// Do floors on item amounts so item_mismatch is a positive value.
|
||||
foreach ( $this->item_objects as $index => $item ) {
|
||||
$this->purchase_unit['items'][ $index ] = $item->to_array(
|
||||
$item->unit_amount()->is_rounding_up()
|
||||
);
|
||||
if ( $this->is_mode_extra_line() ) {
|
||||
if ( $item_mismatch < 0 ) {
|
||||
// Do floors on item amounts so item_mismatch is a positive value.
|
||||
foreach ( $this->item_objects as $index => $item ) {
|
||||
$this->purchase_unit['items'][ $index ] = $item->to_array(
|
||||
$item->unit_amount()->is_rounding_up()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$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();
|
||||
}
|
||||
|
||||
$item_mismatch = $this->calculate_item_mismatch();
|
||||
}
|
||||
|
||||
$item_mismatch = $this->calculate_item_mismatch();
|
||||
|
||||
if ( $item_mismatch > 0 ) {
|
||||
// Add extra line item with roundings.
|
||||
$roundings_money = new Money( $item_mismatch, $this->currency_code() );
|
||||
$this->purchase_unit['items'][] = ( new Item( 'Roundings', $roundings_money, 1 ) )->to_array();
|
||||
}
|
||||
|
||||
$item_mismatch = $this->calculate_item_mismatch();
|
||||
|
||||
if ( $item_mismatch !== 0.0 ) {
|
||||
// Ditch items.
|
||||
if ( isset( $this->purchase_unit['items'] ) ) {
|
||||
|
@ -257,8 +314,8 @@ class PurchaseUnitSanitizer {
|
|||
$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( 'discount' );
|
||||
$amount_total -= $this->breakdown_value( 'shipping_discount' );
|
||||
$amount_total += $this->breakdown_value( 'handling' );
|
||||
$amount_total += $this->breakdown_value( 'insurance' );
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue