woocommerce-paypal-payments/modules/ppcp-api-client/src/Factory/class-amountfactory.php
2020-10-09 19:00:00 -03:00

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 );
}
}