mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-04 08:47:23 +08:00
222 lines
5.3 KiB
PHP
222 lines
5.3 KiB
PHP
<?php
|
|
/**
|
|
* The Amount factory.
|
|
*
|
|
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
|
|
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Amount;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\AmountBreakdown;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
|
|
|
/**
|
|
* Class AmountFactory
|
|
*/
|
|
class AmountFactory {
|
|
|
|
|
|
/**
|
|
* The item factory.
|
|
*
|
|
* @var ItemFactory
|
|
*/
|
|
private $item_factory;
|
|
|
|
/**
|
|
* AmountFactory constructor.
|
|
*
|
|
* @param ItemFactory $item_factory The Item factory.
|
|
*/
|
|
public function __construct( ItemFactory $item_factory ) {
|
|
$this->item_factory = $item_factory;
|
|
}
|
|
|
|
/**
|
|
* Returns an Amount object based off a WooCommerce cart.
|
|
*
|
|
* @param \WC_Cart $cart The cart.
|
|
*
|
|
* @return Amount
|
|
*/
|
|
public function from_wc_cart( \WC_Cart $cart ): Amount {
|
|
$currency = get_woocommerce_currency();
|
|
$total = new Money( (float) $cart->get_total( 'numeric' ), $currency );
|
|
$item_total = $cart->get_cart_contents_total() + $cart->get_discount_total();
|
|
$item_total = new Money( (float) $item_total, $currency );
|
|
$shipping = new Money(
|
|
(float) $cart->get_shipping_total() + $cart->get_shipping_tax(),
|
|
$currency
|
|
);
|
|
|
|
$taxes = new Money(
|
|
(float) $cart->get_cart_contents_tax() + (float) $cart->get_discount_tax(),
|
|
$currency
|
|
);
|
|
|
|
$discount = null;
|
|
if ( $cart->get_discount_total() ) {
|
|
$discount = new Money(
|
|
(float) $cart->get_discount_total() + $cart->get_discount_tax(),
|
|
$currency
|
|
);
|
|
}
|
|
|
|
$breakdown = new AmountBreakdown(
|
|
$item_total,
|
|
$shipping,
|
|
$taxes,
|
|
null, // insurance?
|
|
null, // handling?
|
|
null, // shipping discounts?
|
|
$discount
|
|
);
|
|
$amount = new Amount(
|
|
$total,
|
|
$breakdown
|
|
);
|
|
return $amount;
|
|
}
|
|
|
|
/**
|
|
* Returns an Amount object based off a WooCommerce order.
|
|
*
|
|
* @param \WC_Order $order The order.
|
|
*
|
|
* @return Amount
|
|
*/
|
|
public function from_wc_order( \WC_Order $order ): Amount {
|
|
$currency = $order->get_currency();
|
|
$items = $this->item_factory->from_wc_order( $order );
|
|
$total = new Money( (float) $order->get_total(), $currency );
|
|
$item_total = new Money(
|
|
(float) array_reduce(
|
|
$items,
|
|
static function ( float $total, Item $item ): float {
|
|
return $total + $item->quantity() * $item->unit_amount()->value();
|
|
},
|
|
0
|
|
),
|
|
$currency
|
|
);
|
|
$shipping = new Money(
|
|
(float) $order->get_shipping_total() + (float) $order->get_shipping_tax(),
|
|
$currency
|
|
);
|
|
$taxes = new Money(
|
|
(float) array_reduce(
|
|
$items,
|
|
static function ( float $total, Item $item ): float {
|
|
return $total + $item->quantity() * $item->tax()->value();
|
|
},
|
|
0
|
|
),
|
|
$currency
|
|
);
|
|
|
|
$discount = null;
|
|
if ( (float) $order->get_total_discount( false ) ) {
|
|
$discount = new Money(
|
|
(float) $order->get_total_discount( false ),
|
|
$currency
|
|
);
|
|
}
|
|
|
|
$breakdown = new AmountBreakdown(
|
|
$item_total,
|
|
$shipping,
|
|
$taxes,
|
|
null, // insurance?
|
|
null, // handling?
|
|
null, // shipping discounts?
|
|
$discount
|
|
);
|
|
$amount = new Amount(
|
|
$total,
|
|
$breakdown
|
|
);
|
|
return $amount;
|
|
}
|
|
|
|
/**
|
|
* Returns an Amount object based off a PayPal Response.
|
|
*
|
|
* @param \stdClass $data The JSON object.
|
|
*
|
|
* @return Amount
|
|
* @throws RuntimeException When JSON object is malformed.
|
|
*/
|
|
public function from_paypal_response( \stdClass $data ): Amount {
|
|
if ( ! isset( $data->value ) || ! is_numeric( $data->value ) ) {
|
|
throw new RuntimeException( __( 'No value given', 'woocommerce-paypal-payments' ) );
|
|
}
|
|
if ( ! isset( $data->currency_code ) ) {
|
|
throw new RuntimeException(
|
|
__( 'No currency given', 'woocommerce-paypal-payments' )
|
|
);
|
|
}
|
|
|
|
$money = new Money( (float) $data->value, $data->currency_code );
|
|
$breakdown = ( isset( $data->breakdown ) ) ? $this->break_down( $data->breakdown ) : null;
|
|
return new Amount( $money, $breakdown );
|
|
}
|
|
|
|
/**
|
|
* Returns a AmountBreakdown object based off a PayPal response.
|
|
*
|
|
* @param \stdClass $data The JSON object.
|
|
*
|
|
* @return AmountBreakdown
|
|
* @throws RuntimeException When JSON object is malformed.
|
|
*/
|
|
private function break_down( \stdClass $data ): AmountBreakdown {
|
|
/**
|
|
* The order of the keys equals the necessary order of the constructor arguments.
|
|
*/
|
|
$ordered_constructor_keys = array(
|
|
'item_total',
|
|
'shipping',
|
|
'tax_total',
|
|
'handling',
|
|
'insurance',
|
|
'shipping_discount',
|
|
'discount',
|
|
);
|
|
|
|
$money = array();
|
|
foreach ( $ordered_constructor_keys as $key ) {
|
|
if ( ! isset( $data->{$key} ) ) {
|
|
$money[] = null;
|
|
continue;
|
|
}
|
|
$item = $data->{$key};
|
|
|
|
if ( ! isset( $item->value ) || ! is_numeric( $item->value ) ) {
|
|
throw new RuntimeException(
|
|
sprintf(
|
|
// translators: %s is the current breakdown key.
|
|
__( 'No value given for breakdown %s', 'woocommerce-paypal-payments' ),
|
|
$key
|
|
)
|
|
);
|
|
}
|
|
if ( ! isset( $item->currency_code ) ) {
|
|
throw new RuntimeException(
|
|
sprintf(
|
|
// translators: %s is the current breakdown key.
|
|
__( 'No currency given for breakdown %s', 'woocommerce-paypal-payments' ),
|
|
$key
|
|
)
|
|
);
|
|
}
|
|
$money[] = new Money( (float) $item->value, $item->currency_code );
|
|
}
|
|
|
|
return new AmountBreakdown( ...$money );
|
|
}
|
|
}
|