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