installed plugin Easy Digital Downloads
version 3.1.0.3
This commit is contained in:
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/**
|
||||
* Orders API - Address Object.
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Customers
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Orders;
|
||||
|
||||
use EDD\Base_Object;
|
||||
|
||||
// Exit if accessed directly
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Order Address Class.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $order_id
|
||||
* @property string $first_name
|
||||
* @property string $last_name
|
||||
* @property string $address
|
||||
* @property string $address2
|
||||
* @property string $city
|
||||
* @property string $region
|
||||
* @property string $postal_code
|
||||
* @property string $country
|
||||
* @property string $date_created
|
||||
* @property string $date_modified
|
||||
*/
|
||||
class Order_Address extends Base_Object {
|
||||
|
||||
/**
|
||||
* Order address ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var int
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Order ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var int
|
||||
*/
|
||||
protected $order_id;
|
||||
|
||||
/**
|
||||
* First name.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var string
|
||||
*/
|
||||
protected $first_name;
|
||||
|
||||
/**
|
||||
* Last name.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var string
|
||||
*/
|
||||
protected $last_name;
|
||||
|
||||
/**
|
||||
* Address.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var string
|
||||
*/
|
||||
protected $address;
|
||||
|
||||
/**
|
||||
* Address line 2.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var string
|
||||
*/
|
||||
protected $address2;
|
||||
|
||||
/**
|
||||
* City.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var string
|
||||
*/
|
||||
protected $city;
|
||||
|
||||
/**
|
||||
* Region.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var string
|
||||
*/
|
||||
protected $region;
|
||||
|
||||
/**
|
||||
* Postal code.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var string
|
||||
*/
|
||||
protected $postal_code;
|
||||
|
||||
/**
|
||||
* Country.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var string
|
||||
*/
|
||||
protected $country;
|
||||
|
||||
|
||||
/**
|
||||
* Date created.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var string
|
||||
*/
|
||||
protected $date_created;
|
||||
|
||||
/**
|
||||
* Date modified.
|
||||
*
|
||||
* @since 3.0
|
||||
* @access protected
|
||||
* @var string
|
||||
*/
|
||||
protected $date_modified;
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/**
|
||||
* Order Adjustment Object.
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Orders
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Orders;
|
||||
|
||||
use EDD\Refundable_Item;
|
||||
|
||||
// Exit if accessed directly
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Order_Adjustment Class.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $parent
|
||||
* @property int $object_id
|
||||
* @property string $object_type
|
||||
* @property int|null $type_id
|
||||
* @property string $type
|
||||
* @property string $description
|
||||
* @property float $subtotal
|
||||
* @property float $tax
|
||||
* @property float $total
|
||||
* @property string $date_completed
|
||||
* @property string $date_modified
|
||||
*/
|
||||
class Order_Adjustment extends \EDD\Database\Rows\Order_Adjustment {
|
||||
|
||||
use Refundable_Item;
|
||||
|
||||
/**
|
||||
* Order Discount ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Parent ID. This is only used for order adjustments attached to refunds. The ID references the
|
||||
* original adjustment that was refunded.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Object ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $object_id;
|
||||
|
||||
/**
|
||||
* Object type.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $object_type;
|
||||
|
||||
/**
|
||||
* Type ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int|null
|
||||
*/
|
||||
protected $type_id;
|
||||
|
||||
/**
|
||||
* Type.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* Description.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* Subtotal.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $subtotal;
|
||||
|
||||
/**
|
||||
* Tax.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $tax;
|
||||
|
||||
/**
|
||||
* Total.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $total;
|
||||
|
||||
/**
|
||||
* Date created.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $date_created;
|
||||
|
||||
/**
|
||||
* Date modified.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $date_modified;
|
||||
|
||||
/**
|
||||
* Magic __toString method.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public function __toString() {
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves order adjustment records that were refunded from this original adjustment.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return Order_Adjustment[]|false
|
||||
*/
|
||||
public function get_refunded_items() {
|
||||
if ( null !== $this->refunded_items ) {
|
||||
return $this->refunded_items;
|
||||
}
|
||||
|
||||
// Only fees and credits are supported.
|
||||
if ( ! in_array( $this->type, array( 'fee', 'credit' ) ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return edd_get_order_adjustments( array(
|
||||
'parent' => $this->id
|
||||
) );
|
||||
}
|
||||
}
|
@ -0,0 +1,274 @@
|
||||
<?php
|
||||
/**
|
||||
* Order Item Object.
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Orders
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Orders;
|
||||
|
||||
use EDD\Refundable_Item;
|
||||
|
||||
// Exit if accessed directly
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Order_Item Class.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $parent
|
||||
* @property int $order_id
|
||||
* @property int $product_id
|
||||
* @property string $product_name
|
||||
* @property int|null $price_id
|
||||
* @property int $cart_index
|
||||
* @property string $type
|
||||
* @property string $status
|
||||
* @property int $quantity
|
||||
* @property int $amount
|
||||
* @property float $subtotal
|
||||
* @property float $tax
|
||||
* @property float $discount
|
||||
* @property float $total
|
||||
* @property float $rate
|
||||
* @property string $date_created
|
||||
* @property string $date_modified
|
||||
* @property Order_Adjustment[] $adjustments
|
||||
*/
|
||||
class Order_Item extends \EDD\Database\Rows\Order_Item {
|
||||
|
||||
use Refundable_Item;
|
||||
|
||||
/**
|
||||
* Order Item ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Parent ID. This is only used for order items attached to refunds. The ID references the
|
||||
* original order item that was refunded.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Order ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $order_id;
|
||||
|
||||
/**
|
||||
* Product ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $product_id;
|
||||
|
||||
/**
|
||||
* Product Name.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $product_name;
|
||||
|
||||
/**
|
||||
* Price ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int|null
|
||||
*/
|
||||
protected $price_id;
|
||||
|
||||
/**
|
||||
* Cart index.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $cart_index;
|
||||
|
||||
/**
|
||||
* Item type.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* Item status.
|
||||
*/
|
||||
protected $status;
|
||||
|
||||
/**
|
||||
* Item quantity.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $quantity;
|
||||
|
||||
/**
|
||||
* Item amount.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $amount;
|
||||
|
||||
/**
|
||||
* Item subtotal.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $subtotal;
|
||||
|
||||
/**
|
||||
* Item tax.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $tax;
|
||||
|
||||
/**
|
||||
* Item discount.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $discount;
|
||||
|
||||
/**
|
||||
* Item total.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $total;
|
||||
|
||||
/**
|
||||
* Date created.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $date_created;
|
||||
|
||||
/**
|
||||
* Date modified.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $date_modified;
|
||||
|
||||
/**
|
||||
* Order item adjustments.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var \EDD\Orders\Order_Adjustment[]
|
||||
*/
|
||||
protected $adjustments = null;
|
||||
|
||||
/**
|
||||
* Magic getter for immutability.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get( $key = '' ) {
|
||||
if ( 'adjustments' === $key && null === $this->adjustments ) {
|
||||
$this->adjustments = edd_get_order_adjustments( array(
|
||||
'object_id' => $this->id,
|
||||
'object_type' => 'order_item',
|
||||
'no_found_rows' => true,
|
||||
'order' => 'ASC',
|
||||
) );
|
||||
}
|
||||
|
||||
return parent::__get( $key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve fees applied to this order item.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return array $fees Fees applied to this item.
|
||||
*/
|
||||
public function get_fees() {
|
||||
return edd_get_order_adjustments( array(
|
||||
'object_id' => $this->id,
|
||||
'object_type' => 'order_item',
|
||||
'type' => 'fee',
|
||||
'order' => 'ASC',
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an order item name, including any price ID name appended to the end.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return string The product name including any price ID name.
|
||||
*/
|
||||
public function get_order_item_name() {
|
||||
if ( is_admin() && ( function_exists( 'edd_doing_ajax' ) && ! edd_doing_ajax() ) ) {
|
||||
/**
|
||||
* Allow the product name to be filtered within the admin.
|
||||
* @since 3.0
|
||||
* @param string $product_name The order item name.
|
||||
* @param EDD\Orders\Order_Item The order item object.
|
||||
*/
|
||||
return apply_filters( 'edd_order_details_item_name', $this->product_name, $this );
|
||||
}
|
||||
|
||||
return $this->product_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves order item records that were refunded from this original order item.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return Order_Item[]|false
|
||||
*/
|
||||
public function get_refunded_items() {
|
||||
if ( null !== $this->refunded_items ) {
|
||||
return $this->refunded_items;
|
||||
}
|
||||
|
||||
return edd_get_order_items( array(
|
||||
'parent' => $this->id
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the order item status to determine whether assets can be delivered.
|
||||
*
|
||||
* @since 3.0
|
||||
* @return bool
|
||||
*/
|
||||
public function is_deliverable() {
|
||||
return in_array( $this->status, edd_get_deliverable_order_item_statuses(), true );
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
* Order Transaction Object.
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Orders
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Orders;
|
||||
|
||||
use EDD\Database\Rows as Rows;
|
||||
|
||||
// Exit if accessed directly
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Order Transaction Class.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $object_id
|
||||
* @property string $object_type
|
||||
* @property string $transaction_id
|
||||
* @property string $gateway
|
||||
* @property string $status
|
||||
* @property float $total
|
||||
* @property string $date_created
|
||||
* @property string $date_modified
|
||||
*/
|
||||
class Order_Transaction extends Rows\Order_Transaction {
|
||||
|
||||
/**
|
||||
* Order Transaction ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Object ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $object_id;
|
||||
|
||||
/**
|
||||
* Object type
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $object_type;
|
||||
|
||||
/**
|
||||
* Transaction ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $transaction_id;
|
||||
|
||||
/**
|
||||
* Gateway.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $gateway;
|
||||
|
||||
/**
|
||||
* Status.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $status;
|
||||
|
||||
/**
|
||||
* Total amount.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $total;
|
||||
|
||||
/**
|
||||
* Date created.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $date_created;
|
||||
|
||||
/**
|
||||
* Date modified.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $date_modified;
|
||||
|
||||
/**
|
||||
* Check if a transaction is complete.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return bool True if the transaction is complete, false otherwise.
|
||||
*/
|
||||
public function is_complete() {
|
||||
return ( 'complete' === $this->status );
|
||||
}
|
||||
}
|
@ -0,0 +1,699 @@
|
||||
<?php
|
||||
/**
|
||||
* Order Object.
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Orders
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Orders;
|
||||
|
||||
use EDD\Database\Rows as Rows;
|
||||
use EDD\Database\Rows\Adjustment;
|
||||
|
||||
// Exit if accessed directly
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Order Class.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $parent
|
||||
* @property string $order_number
|
||||
* @property string $type
|
||||
* @property string $status
|
||||
* @property string $date_created
|
||||
* @property string $date_modified
|
||||
* @property string|null $date_completed
|
||||
* @property string|null $date_refundable
|
||||
* @property int $user_id
|
||||
* @property int $customer_id
|
||||
* @property string $email
|
||||
* @property string $ip
|
||||
* @property string $gateway
|
||||
* @property string $mode
|
||||
* @property string $currency
|
||||
* @property string $payment_key
|
||||
* @property int|null $tax_rate_id
|
||||
* @property float $subtotal
|
||||
* @property float $tax
|
||||
* @property float $discount
|
||||
* @property float $total
|
||||
* @property float $rate
|
||||
* @property Order_Item[] $items
|
||||
* @property Order_Adjustment[] $adjustments
|
||||
* @property Order_Address $address
|
||||
*/
|
||||
class Order extends Rows\Order {
|
||||
|
||||
/**
|
||||
* Order ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Parent order.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Order number.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $order_number;
|
||||
|
||||
/**
|
||||
* Order status.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $status;
|
||||
|
||||
/**
|
||||
* Order type.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* Date created.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $date_created;
|
||||
|
||||
/**
|
||||
* Date modified.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $date_modified;
|
||||
|
||||
/**
|
||||
* Date completed.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string|null
|
||||
*/
|
||||
protected $date_completed;
|
||||
|
||||
/**
|
||||
* Date refundable.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string|null
|
||||
*/
|
||||
protected $date_refundable;
|
||||
|
||||
/**
|
||||
* User ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $user_id;
|
||||
|
||||
/**
|
||||
* Customer ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int
|
||||
*/
|
||||
protected $customer_id;
|
||||
|
||||
/**
|
||||
* Email.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $email;
|
||||
|
||||
/**
|
||||
* IP.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $ip;
|
||||
|
||||
/**
|
||||
* Order gateway.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $gateway;
|
||||
|
||||
/**
|
||||
* Order mode.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $mode;
|
||||
|
||||
/**
|
||||
* Order currency.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $currency;
|
||||
|
||||
/**
|
||||
* Payment key.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $payment_key;
|
||||
|
||||
/**
|
||||
* Tax rate ID.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var int|null
|
||||
*/
|
||||
protected $tax_rate_id;
|
||||
|
||||
/**
|
||||
* Tax rate Adjustment object.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var Adjustment|null
|
||||
*/
|
||||
protected $tax_rate = null;
|
||||
|
||||
/**
|
||||
* Subtotal.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $subtotal;
|
||||
|
||||
/**
|
||||
* Tax.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $tax;
|
||||
|
||||
/**
|
||||
* Order discount.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $discount;
|
||||
|
||||
/**
|
||||
* Order total.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var float
|
||||
*/
|
||||
protected $total;
|
||||
|
||||
/**
|
||||
* Order items.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var \EDD\Orders\Order_Item[]
|
||||
*/
|
||||
protected $items = null;
|
||||
|
||||
/**
|
||||
* Order adjustments.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var \EDD\Orders\Order_Adjustment[]
|
||||
*/
|
||||
protected $adjustments = null;
|
||||
|
||||
/**
|
||||
* Order address.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var \EDD\Orders\Order_Address
|
||||
*/
|
||||
protected $address = null;
|
||||
|
||||
/**
|
||||
* Magic getter for immutability.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get( $key = '' ) {
|
||||
if ( 'adjustments' === $key && null === $this->adjustments ) {
|
||||
$this->adjustments = edd_get_order_adjustments( array(
|
||||
'object_id' => $this->id,
|
||||
'object_type' => 'order',
|
||||
'no_found_rows' => true,
|
||||
'order' => 'ASC',
|
||||
) );
|
||||
} elseif ( 'items' === $key ) {
|
||||
$this->get_items();
|
||||
}
|
||||
|
||||
return parent::__get( $key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve order number.
|
||||
*
|
||||
* An order number is only retrieved if sequential order numbers are enabled,
|
||||
* otherwise the order ID is returned.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_number() {
|
||||
|
||||
if ( $this->order_number && edd_get_option( 'enable_sequential' ) ) {
|
||||
$number = $this->order_number;
|
||||
} else {
|
||||
$number = $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* The edd_payment_number filter allows the order_number value to be changed.
|
||||
*
|
||||
* This filter used to run in the EDD_Payment class's get_number method upon its setup.
|
||||
* It now exists only here in EDD_Order since EDD 3.0. EDD Payment gets its order_number
|
||||
* value from EDD_Order (this class), so it gets run for both EDD_Payment and EDD_Order this way.
|
||||
*
|
||||
* @since 2.5
|
||||
* @since 3.0 Updated the 3rd paramater from an EDD_Payment object to an EDD_Order object.
|
||||
*
|
||||
* @param string The unique value to represent this order. This is a string because pre-fixes and post-fixes can be appended via the filter.
|
||||
* @param int The row ID of the Payment/Order.
|
||||
* @param Order Prior to EDD 3.0, this was an EDD_Payment object. Now it is an EDD_Order object.
|
||||
*/
|
||||
$number = apply_filters( 'edd_payment_number', $number, $this->ID, $this );
|
||||
|
||||
/**
|
||||
* This filter is exactly the same as edd_payment_number, and exists purely so that
|
||||
* the "order" terminology has a filter as well.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string The unique value to represent this order. This is a string because pre-fixes and post-fixes can be appended via the filter.
|
||||
* @param int The row ID of the Payment/Order.
|
||||
* @param Order The EDD_Order object.
|
||||
*/
|
||||
$number = apply_filters( 'edd_order_number', $number, $this->ID, $this );
|
||||
|
||||
return $number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all the items in the order.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return Order_Item[] Order items.
|
||||
*/
|
||||
public function get_items() {
|
||||
if ( null === $this->items ) {
|
||||
$this->items = edd_get_order_items( array(
|
||||
'order_id' => $this->id,
|
||||
'orderby' => 'cart_index',
|
||||
'order' => 'ASC',
|
||||
'no_found_rows' => true,
|
||||
'number' => 200,
|
||||
) );
|
||||
}
|
||||
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve all the items in the order and transform bundle products into regular items.
|
||||
*
|
||||
* @since 3.0.2
|
||||
*
|
||||
* @return Order_Item[] Order items.
|
||||
*/
|
||||
public function get_items_with_bundles() {
|
||||
$items = $this->get_items();
|
||||
foreach ( $items as $index => $item ) {
|
||||
if ( edd_is_bundled_product( $item->product_id ) ) {
|
||||
$new_items = array();
|
||||
$bundled_products = edd_get_bundled_products( $item->product_id, $item->price_id );
|
||||
foreach ( $bundled_products as $bundle_item ) {
|
||||
$order_item_args = array(
|
||||
'order_id' => $this->ID,
|
||||
'status' => $item->status,
|
||||
'product_id' => edd_get_bundle_item_id( $bundle_item ),
|
||||
'product_name' => edd_get_bundle_item_title( $bundle_item ),
|
||||
'price_id' => edd_get_bundle_item_price_id( $bundle_item ),
|
||||
);
|
||||
$new_items[] = new \EDD\Orders\Order_Item( $order_item_args );
|
||||
}
|
||||
if ( ! empty( $new_items ) ) {
|
||||
// The parent item should be replaced at its original position with its bundle items.
|
||||
array_splice( $items, $index, 1, $new_items );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve all the adjustments applied to the order.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return array Order adjustments.
|
||||
*/
|
||||
public function get_adjustments() {
|
||||
if ( null === $this->adjustments ) {
|
||||
$this->adjustments = edd_get_order_adjustments( array(
|
||||
'object_id' => $this->id,
|
||||
'object_type' => 'order',
|
||||
'no_found_rows' => true,
|
||||
'order' => 'ASC',
|
||||
) );
|
||||
}
|
||||
|
||||
return $this->adjustments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the discounts applied to the order.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return Order_Adjustment[] Order discounts.
|
||||
*/
|
||||
public function get_discounts() {
|
||||
$discounts = array();
|
||||
|
||||
foreach ( $this->get_adjustments() as $adjustment ) {
|
||||
/** @var Order_Adjustment $adjustment */
|
||||
|
||||
if ( 'discount' === $adjustment->type ) {
|
||||
$discounts[] = $adjustment;
|
||||
}
|
||||
}
|
||||
|
||||
return $discounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the fees applied to the order. This retrieves the fees applied to the entire order and to individual items.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return Order_Adjustment[] Order fees.
|
||||
*/
|
||||
public function get_fees() {
|
||||
|
||||
// Default values
|
||||
$fees = array();
|
||||
|
||||
// Fetch the fees that applied to the entire order.
|
||||
foreach ( $this->get_adjustments() as $adjustment ) {
|
||||
/** @var Order_Adjustment $adjustment */
|
||||
|
||||
if ( 'fee' === $adjustment->type ) {
|
||||
$fees[] = $adjustment;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure items exist.
|
||||
if ( null === $this->items ) {
|
||||
$this->items = $this->get_items();
|
||||
}
|
||||
|
||||
// Fetch the fees that applied to specific items in the order.
|
||||
foreach ( $this->items as $item ) {
|
||||
/** @var Order_Item $item */
|
||||
|
||||
foreach ( $item->get_fees() as $fee ) {
|
||||
/** @var Order_Adjustment $fee */
|
||||
|
||||
$fees[] = $fee;
|
||||
}
|
||||
}
|
||||
|
||||
return $fees;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the credits applied to the order.
|
||||
* These exist only for manually added orders.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
*@return Order_Adjustment[] Order credits.
|
||||
*/
|
||||
public function get_credits() {
|
||||
// Default values
|
||||
$credits = array();
|
||||
|
||||
// Fetch the fees that applied to the entire order.
|
||||
foreach ( $this->get_adjustments() as $adjustment ) {
|
||||
/** @var Order_Adjustment $adjustment */
|
||||
|
||||
if ( 'credit' === $adjustment->type ) {
|
||||
$credits[] = $adjustment;
|
||||
}
|
||||
}
|
||||
|
||||
return $credits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the transaction ID associated with the order.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $type Transaction type. Default `primary`.
|
||||
* @return string|array $retval Transaction ID(s).
|
||||
*/
|
||||
public function get_transaction_id( $type = 'primary' ) {
|
||||
$retval = '';
|
||||
|
||||
// Retrieve first transaction ID only.
|
||||
if ( 'primary' === $type ) {
|
||||
$transactions = array_values( edd_get_order_transactions( array(
|
||||
'object_id' => $this->id,
|
||||
'object_type' => 'order',
|
||||
'orderby' => 'date_created',
|
||||
'order' => 'ASC',
|
||||
'fields' => 'transaction_id',
|
||||
'number' => 1,
|
||||
) ) );
|
||||
|
||||
if ( $transactions ) {
|
||||
$retval = esc_attr( $transactions[0] );
|
||||
}
|
||||
|
||||
// Retrieve all transaction IDs.
|
||||
} else {
|
||||
$retval = edd_get_order_transactions( array(
|
||||
'object_id' => $this->id,
|
||||
'object_type' => 'order',
|
||||
'orderby' => 'date_created',
|
||||
'order' => 'ASC',
|
||||
'fields' => 'transaction_id',
|
||||
) );
|
||||
}
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the tax rate Adjustment object associated with the order.
|
||||
*
|
||||
* @since 3.0
|
||||
* @return Adjustment|false|null
|
||||
*/
|
||||
public function get_tax_rate_object() {
|
||||
if ( $this->tax_rate_id && null === $this->tax_rate ) {
|
||||
$this->tax_rate = edd_get_adjustment( $this->tax_rate_id );
|
||||
}
|
||||
|
||||
return $this->tax_rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the tax rate associated with the order.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return float Tax rate percentage (0 - 100).
|
||||
*/
|
||||
public function get_tax_rate() {
|
||||
|
||||
// Default rate
|
||||
$rate = 0;
|
||||
|
||||
// Get rates from adjustments
|
||||
$tax_rate_object = $this->get_tax_rate_object();
|
||||
if ( is_object( $tax_rate_object ) && isset( $tax_rate_object->amount ) ) {
|
||||
$rate = $tax_rate_object->amount;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a tax_amount, but no rate, check in order meta. This is where legacy rates are stored
|
||||
* if they cannot be resolved to an actual adjustment object.
|
||||
*/
|
||||
if ( empty( $rate ) && abs( $this->tax ) > 0 ) {
|
||||
$rate = edd_get_order_meta( $this->id, 'tax_rate', true );
|
||||
}
|
||||
|
||||
return floatval( $rate );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the address associated with the order.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return \EDD\Orders\Order_Address|false Object if successful, false otherwise.
|
||||
*/
|
||||
public function get_address() {
|
||||
|
||||
// Attempt to get the order address.
|
||||
$address = edd_get_order_address_by( 'order_id', $this->id );
|
||||
|
||||
// Fallback object if not found.
|
||||
if ( empty( $address ) ) {
|
||||
$address = (object) array(
|
||||
'id' => 0,
|
||||
'order_id' => 0,
|
||||
'first_name' => '',
|
||||
'last_name' => '',
|
||||
'address' => '',
|
||||
'address2' => '',
|
||||
'city' => '',
|
||||
'region' => '',
|
||||
'postal_code' => '',
|
||||
'country' => '',
|
||||
);
|
||||
}
|
||||
|
||||
// Return address (from DB or fallback).
|
||||
return $address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve whether or not unlimited downloads have been enabled on this order.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return bool True if unlimited downloads are enabled, false otherwise.
|
||||
*/
|
||||
public function has_unlimited_downloads() {
|
||||
return (bool) edd_get_order_meta( $this->id, 'unlimited_downloads', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all the notes for this order.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return array Notes associated with this order.
|
||||
*/
|
||||
public function get_notes() {
|
||||
return edd_get_notes( array(
|
||||
'object_id' => $this->id,
|
||||
'object_type' => 'order',
|
||||
'order' => 'ASC',
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an order is complete.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return bool True if the order is complete, false otherwise.
|
||||
*/
|
||||
public function is_complete() {
|
||||
return ( 'complete' === $this->status );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this order is able to be resumed by the user.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_recoverable() {
|
||||
$recoverable_statuses = edd_recoverable_order_statuses();
|
||||
if ( in_array( $this->status, $recoverable_statuses, true ) && empty( $this->get_transaction_id() ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL that a customer can use to resume an order, or false if it's not recoverable.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function get_recovery_url() {
|
||||
if ( ! $this->is_recoverable() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$recovery_url = add_query_arg(
|
||||
array(
|
||||
'edd_action' => 'recover_payment',
|
||||
'payment_id' => urlencode( $this->id ),
|
||||
),
|
||||
edd_get_checkout_uri()
|
||||
);
|
||||
|
||||
/**
|
||||
* Legacy recovery URL filter.
|
||||
*
|
||||
* @param \EDD_Payment $payment The EDD payment object.
|
||||
*/
|
||||
if ( has_filter( 'edd_payment_recovery_url' ) ) {
|
||||
$recovery_url = apply_filters( 'edd_payment_recovery_url', $recovery_url, edd_get_payment( $this->id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* The order recovery URL.
|
||||
*
|
||||
* @since 3.0
|
||||
* @param string $recovery_url The order recovery URL.
|
||||
* @param \EDD\Orders\Order $this The order object.
|
||||
*/
|
||||
return apply_filters( 'edd_order_recovery_url', $recovery_url, $this );
|
||||
}
|
||||
}
|
@ -0,0 +1,511 @@
|
||||
<?php
|
||||
/**
|
||||
* Refund Validator
|
||||
*
|
||||
* @package easy-digital-downloads
|
||||
* @copyright Copyright (c) 2021, Sandhills Development, LLC
|
||||
* @license GPL2+
|
||||
* @since 3.0
|
||||
*/
|
||||
|
||||
namespace EDD\Orders;
|
||||
|
||||
use EDD\Utils\Exception;
|
||||
use EDD\Utils\Exceptions\Invalid_Argument;
|
||||
|
||||
class Refund_Validator {
|
||||
|
||||
/**
|
||||
* Original order being refunded.
|
||||
*
|
||||
* @var Order
|
||||
*/
|
||||
protected $order;
|
||||
|
||||
/**
|
||||
* All fees and credits associated with the original order. Includes both order-level and order-item-level.
|
||||
*
|
||||
* @var Order_Adjustment[]
|
||||
*/
|
||||
protected $order_adjustments;
|
||||
|
||||
/**
|
||||
* Array of order item IDs and amounts to refund. If empty, then all items will be refunded.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $order_items_to_refund;
|
||||
|
||||
/**
|
||||
* Array of adjustment IDs and amounts to refund. If empty, then no adjustments are refunded.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $adjustments_to_refund;
|
||||
|
||||
/**
|
||||
* Final subtotal for the refund. Includes all selected order items and adjustments.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $subtotal = 0.00;
|
||||
|
||||
/**
|
||||
* Final tax amount to refund. Includes all selected order items and adjustments.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $tax = 0.00;
|
||||
|
||||
/**
|
||||
* Final total for the refund (subtotal + tax). Includes all selected order items and adjustments.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $total = 0.00;
|
||||
|
||||
/**
|
||||
* Refund_Validator constructor.
|
||||
*
|
||||
* @param Order $order
|
||||
* @param array|string $order_items
|
||||
* @param array|string $adjustments
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct( Order $order, $order_items = 'all', $adjustments = 'all' ) {
|
||||
$this->order = $order;
|
||||
$this->order_adjustments = $this->get_order_adjustments();
|
||||
$this->order_items_to_refund = $this->validate_and_format_order_items( $order_items );
|
||||
$this->adjustments_to_refund = $this->validate_and_format_adjustments( $adjustments );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all refund-eligible adjustments associated with the order.
|
||||
* Note that this doesn't exclude items that have already reached their refund max; it just
|
||||
* returns all objects that could possibly be refunded. (Essentially `discount` adjustments
|
||||
* are excluded.)
|
||||
*
|
||||
* @since 3.0
|
||||
* @return Order_Adjustment[]
|
||||
*/
|
||||
private function get_order_adjustments() {
|
||||
$fees = $this->order->get_fees();
|
||||
$credits = edd_get_order_adjustments( array(
|
||||
'object_id' => $this->order->id,
|
||||
'object_type' => 'order',
|
||||
'type' => 'credit'
|
||||
) );
|
||||
|
||||
return array_merge( $fees, $credits );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the supplied order items and does a little formatting.
|
||||
* If `all` is supplied, then all items eligible for refund are included.
|
||||
*
|
||||
* @param array|string $order_items
|
||||
*
|
||||
* @return array
|
||||
* @throws Invalid_Argument
|
||||
*/
|
||||
private function validate_and_format_order_items( $order_items ) {
|
||||
$keyed_order_items = array();
|
||||
|
||||
if ( 'all' === $order_items ) {
|
||||
$order_items = $this->get_all_refundable_order_items();
|
||||
}
|
||||
|
||||
if ( ! empty( $order_items ) && is_array( $order_items ) ) {
|
||||
$order_item_ids = wp_list_pluck( $this->order->items, 'id' );
|
||||
|
||||
foreach ( $order_items as $order_item_data ) {
|
||||
// order_item_id must be supplied and in the list attached to the original order.
|
||||
if ( empty( $order_item_data['order_item_id'] ) || ! in_array( $order_item_data['order_item_id'], $order_item_ids ) ) {
|
||||
throw Invalid_Argument::from( 'order_item_id', __METHOD__ );
|
||||
}
|
||||
|
||||
$this->validate_required_fields( $order_item_data, __METHOD__ );
|
||||
|
||||
if ( ! isset( $order_item_data['total'] ) ) {
|
||||
$order_item_data['total'] = $order_item_data['subtotal'] + $order_item_data['tax'];
|
||||
}
|
||||
|
||||
// Set the array key to be the order item ID for easier lookups as we go.
|
||||
$keyed_order_items[ intval( $order_item_data['order_item_id'] ) ] = $order_item_data;
|
||||
}
|
||||
}
|
||||
|
||||
return $keyed_order_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all order items that can be refunded.
|
||||
* This is used if `all` is supplied for order items.
|
||||
*
|
||||
* @since 3.0
|
||||
* @return array
|
||||
*/
|
||||
private function get_all_refundable_order_items() {
|
||||
$order_items_to_refund = array();
|
||||
|
||||
foreach ( $this->order->items as $item ) {
|
||||
if ( 'refunded' !== $item->status ) {
|
||||
$order_items_to_refund[] = array_merge( array(
|
||||
'order_item_id' => $item->id,
|
||||
'quantity' => $item->quantity,
|
||||
), $item->get_refundable_amounts() );
|
||||
}
|
||||
}
|
||||
|
||||
return $order_items_to_refund;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the supplied adjustments and does a little formatting.
|
||||
* If `all` is supplied, then all adjustments eligible for refund are included.
|
||||
*
|
||||
* @param array|string $adjustments
|
||||
*
|
||||
* @return array
|
||||
* @throws Invalid_Argument
|
||||
*/
|
||||
private function validate_and_format_adjustments( $adjustments ) {
|
||||
$keyed_adjustments = array();
|
||||
|
||||
if ( 'all' === $adjustments ) {
|
||||
$adjustments = $this->get_all_refundable_adjustments();
|
||||
}
|
||||
|
||||
if ( ! empty( $adjustments ) && is_array( $adjustments ) ) {
|
||||
$adjustment_ids = wp_list_pluck( $this->order_adjustments, 'id' );
|
||||
|
||||
foreach ( $adjustments as $adjustment_data ) {
|
||||
// adjustment_id must be supplied and in the list attached to the original order/items.
|
||||
if ( empty( $adjustment_data['adjustment_id'] ) || ! in_array( $adjustment_data['adjustment_id'], $adjustment_ids ) ) {
|
||||
throw Invalid_Argument::from( 'adjustment_id', __METHOD__ );
|
||||
}
|
||||
|
||||
$this->validate_required_fields( $adjustment_data, __METHOD__ );
|
||||
|
||||
if ( ! isset( $adjustment_data['total'] ) ) {
|
||||
$adjustment_data['total'] = $adjustment_data['subtotal'] + $adjustment_data['tax'];
|
||||
}
|
||||
|
||||
// Set the array key to be the adjustment ID for easier lookups as we go.
|
||||
$keyed_adjustments[ intval( $adjustment_data['adjustment_id'] ) ] = $adjustment_data;
|
||||
}
|
||||
}
|
||||
|
||||
return $keyed_adjustments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all adjustments that can be refunded.
|
||||
* This is used if `all` is supplied for adjustments.
|
||||
*
|
||||
* @since 3.0
|
||||
* @return array
|
||||
*/
|
||||
private function get_all_refundable_adjustments() {
|
||||
$adjustments_to_refund = array();
|
||||
|
||||
foreach ( $this->order_adjustments as $adjustment ) {
|
||||
if ( 'refunded' !== $adjustment->status ) {
|
||||
$adjustments_to_refund[] = array_merge( array(
|
||||
'adjustment_id' => $adjustment->id
|
||||
), $adjustment->get_refundable_amounts() );
|
||||
}
|
||||
}
|
||||
|
||||
return $adjustments_to_refund;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates required fields for both order items and taxes.
|
||||
*
|
||||
* @param array $input Input to be validated.
|
||||
* @param string $context Context, for error message.
|
||||
*
|
||||
* @since 3.0
|
||||
* @throws Invalid_Argument
|
||||
*/
|
||||
private function validate_required_fields( $input, $context ) {
|
||||
// subtotal and total are both required.
|
||||
$required_fields = array( 'subtotal' );
|
||||
if ( edd_use_taxes() ) {
|
||||
$required_fields[] = 'tax';
|
||||
}
|
||||
|
||||
foreach ( $required_fields as $required_field ) {
|
||||
if ( ! isset( $input[ $required_field ] ) ) {
|
||||
throw Invalid_Argument::from( $required_field, $context );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates final amounts and calculates refund total.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function validate_and_calculate_totals() {
|
||||
$this->validate_order_item_amounts();
|
||||
$this->validate_adjustment_amounts();
|
||||
|
||||
// Some items or adjustments have to be selected to refund.
|
||||
if ( empty( $this->order_items_to_refund ) && empty( $this->adjustments_to_refund ) ) {
|
||||
throw new Exception(
|
||||
__( 'No items have been selected to refund.', 'easy-digital-downloads' )
|
||||
);
|
||||
}
|
||||
|
||||
// Refund amount cannot be 0
|
||||
if ( $this->total <= 0 ) {
|
||||
throw new Exception( sprintf(
|
||||
/* Translators: %s - 0.00 formatted in store currency */
|
||||
__( 'The refund amount must be greater than %s.', 'easy-digital-downloads' ),
|
||||
edd_currency_filter( edd_format_amount( 0.00 ) )
|
||||
) );
|
||||
}
|
||||
|
||||
// Overall refund total cannot be over total refundable amount.
|
||||
$order_total = edd_get_order_total( $this->order->id );
|
||||
if ( $this->is_over_refund_amount( $this->total, $order_total ) ) {
|
||||
throw new Exception( sprintf(
|
||||
/* Translators: %s - maximum refund amount as formatted currency */
|
||||
__( 'The maximum refund amount is %s.', 'easy-digital-downloads' ),
|
||||
edd_currency_filter( edd_format_amount( $order_total ) )
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the order item amounts.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function validate_order_item_amounts() {
|
||||
foreach ( $this->order->items as $item ) {
|
||||
if ( ! array_key_exists( $item->id, $this->order_items_to_refund ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$amount_to_refund = wp_parse_args( $this->order_items_to_refund[ $item->id ], array(
|
||||
'subtotal' => $item->subtotal,
|
||||
'tax' => $item->tax,
|
||||
'total' => $item->total
|
||||
) );
|
||||
|
||||
$this->order_items_to_refund[ $item->id ]['original_item_status'] = $this->validate_item_and_add_totals( $item, $amount_to_refund );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the adjustment amounts.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function validate_adjustment_amounts() {
|
||||
foreach ( $this->order_adjustments as $adjustment ) {
|
||||
if ( ! array_key_exists( $adjustment->id, $this->adjustments_to_refund ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$amount_to_refund = wp_parse_args( $this->adjustments_to_refund[ $adjustment->id ], array(
|
||||
'subtotal' => $adjustment->subtotal,
|
||||
'tax' => $adjustment->tax,
|
||||
'total' => $adjustment->total
|
||||
) );
|
||||
|
||||
$this->adjustments_to_refund[ $adjustment->id ]['original_item_status'] = $this->validate_item_and_add_totals( $adjustment, $amount_to_refund );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the amount attempting to be refunded against the total that can be refunded.
|
||||
*
|
||||
* The refund amount for each item cannot exceed the original amount minus what's already been refunded.
|
||||
* Note: quantity is not checked because you might process multiple partial refunds for the same order item.
|
||||
*
|
||||
* @param Order_Item|Order_Adjustment $original_item Original item being refunded.
|
||||
* @param array $amounts_to_refund Amounts *attempting* to be refunded. These will be
|
||||
* matched against the maximums.
|
||||
*
|
||||
* @return string Either `refunded` if this is a complete refund, or `partially_refunded` if it's a partial.
|
||||
* This should be the new status for the original item.
|
||||
* @throws Exception
|
||||
*/
|
||||
private function validate_item_and_add_totals( $original_item, $amounts_to_refund ) {
|
||||
$item_status = 'refunded';
|
||||
|
||||
$maximum_refundable_amounts = $original_item->get_refundable_amounts();
|
||||
|
||||
foreach ( array( 'subtotal', 'tax', 'total' ) as $column_name ) {
|
||||
// Hopefully this should never happen, but just in case!
|
||||
if ( ! array_key_exists( $column_name, $maximum_refundable_amounts ) ) {
|
||||
throw new Exception( sprintf(
|
||||
/* Translators: %s is the type of amount being refunded (e.g. "subtotal" or "tax"). Not translatable at this time. */
|
||||
__( 'An unexpected error occurred while validating the maximum %s amount.', 'easy-digital-downloads' ),
|
||||
$column_name
|
||||
) );
|
||||
}
|
||||
|
||||
// This is our fallback.
|
||||
$attempted_amount = isset( $original_item->{$column_name} ) ? $original_item->{$column_name} : 0.00;
|
||||
$maximum_amount = $maximum_refundable_amounts[ $column_name ];
|
||||
|
||||
// Only order items are included in the subtotal.
|
||||
if ( ! $original_item instanceof Order_Item && 'subtotal' === $column_name ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// But grab from specified amounts if available. It should always be available.
|
||||
if ( isset( $amounts_to_refund[ $column_name ] ) ) {
|
||||
$attempted_amount = $amounts_to_refund[ $column_name ];
|
||||
}
|
||||
|
||||
if ( $this->is_over_refund_amount( $attempted_amount, $maximum_amount ) ) {
|
||||
if ( $original_item instanceof Order_Item ) {
|
||||
$error_message = sprintf(
|
||||
/*
|
||||
* Translators:
|
||||
* %1$s - type of amount being refunded (subtotal, tax, or total);
|
||||
* %1$s - product name;
|
||||
* %3$s - maximum amount allowed for refund
|
||||
*/
|
||||
__( 'The maximum refund %1$s for the product "%2$s" is %3$s.', 'easy-digital-downloads' ),
|
||||
$column_name,
|
||||
$original_item->product_name,
|
||||
edd_currency_filter( $maximum_refundable_amounts[ $column_name ] )
|
||||
);
|
||||
} else {
|
||||
$error_message = sprintf(
|
||||
/*
|
||||
* Translators:
|
||||
* %1$s - type of amount being refunded (subtotal, tax, or total);
|
||||
* %1$s - adjustment description;
|
||||
* %3$s - maximum amount allowed for refund
|
||||
*/
|
||||
__( 'The maximum refund %s for the adjustment "%s" is %s.', 'easy-digital-downloads' ),
|
||||
$column_name,
|
||||
$original_item->description,
|
||||
edd_currency_filter( $maximum_refundable_amounts[ $column_name ] )
|
||||
);
|
||||
}
|
||||
|
||||
throw new Exception( $error_message );
|
||||
}
|
||||
|
||||
if ( 'total' === $column_name && $attempted_amount < $maximum_refundable_amounts['total'] ) {
|
||||
$item_status = 'partially_refunded';
|
||||
}
|
||||
|
||||
// If this is an adjustment, and it's _credit_, negate the amount because credit _reduces_ the total.
|
||||
if ( $original_item instanceof Order_Adjustment && 'credit' === $original_item->type ) {
|
||||
$attempted_amount = edd_negate_amount( $attempted_amount );
|
||||
}
|
||||
|
||||
$this->{$column_name} += $attempted_amount;
|
||||
}
|
||||
|
||||
return $item_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of order items to refund.
|
||||
*
|
||||
* @since 3.0
|
||||
* @return array
|
||||
*/
|
||||
public function get_refunded_order_items() {
|
||||
$order_items = array();
|
||||
|
||||
foreach ( $this->order->items as $item ) {
|
||||
if ( array_key_exists( $item->id, $this->order_items_to_refund ) ) {
|
||||
$defaults = $allowed_keys = $item->to_array();
|
||||
|
||||
if ( array_key_exists( 'original_item_status', $this->order_items_to_refund[ $item->id ] ) ) {
|
||||
$allowed_keys['original_item_status'] = $this->order_items_to_refund[ $item->id ]['original_item_status'];
|
||||
}
|
||||
|
||||
$args = array_intersect_key( $this->order_items_to_refund[ $item->id ], $allowed_keys );
|
||||
$order_items[] = $this->set_common_item_args( wp_parse_args( $args, $defaults ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $order_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all adjustments to refund.
|
||||
*
|
||||
* @since 3.0
|
||||
* @return array
|
||||
*/
|
||||
public function get_refunded_adjustments() {
|
||||
$order_item_adjustments = array();
|
||||
|
||||
foreach ( $this->order_adjustments as $adjustment ) {
|
||||
if ( array_key_exists( $adjustment->id, $this->adjustments_to_refund ) ) {
|
||||
$defaults = $allowed_keys = $adjustment->to_array();
|
||||
|
||||
if ( array_key_exists( 'original_item_status', $this->adjustments_to_refund[ $adjustment->id ] ) ) {
|
||||
$allowed_keys['original_item_status'] = $this->adjustments_to_refund[ $adjustment->id ]['original_item_status'];
|
||||
}
|
||||
|
||||
$args = array_intersect_key( $this->adjustments_to_refund[ $adjustment->id ], $defaults );
|
||||
$order_item_adjustments[] = $this->set_common_item_args( wp_parse_args( $args, $defaults ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $order_item_adjustments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets common arguments for refunded order items and adjustments.
|
||||
*
|
||||
* @param array $new_args
|
||||
*
|
||||
* @since 3.0
|
||||
* @return array
|
||||
*/
|
||||
private function set_common_item_args( $new_args ) {
|
||||
// Set the `parent` to the original item ID.
|
||||
if ( isset( $new_args['id'] ) ) {
|
||||
$new_args['parent'] = $new_args['id'];
|
||||
}
|
||||
|
||||
// Negate amounts.
|
||||
if ( array_key_exists( 'quantity', $new_args ) ) {
|
||||
$new_args['quantity'] = edd_negate_int( $new_args['quantity'] );
|
||||
}
|
||||
foreach ( array( 'subtotal', 'tax', 'total' ) as $field_to_negate ) {
|
||||
if ( array_key_exists( $field_to_negate, $new_args ) ) {
|
||||
$new_args[ $field_to_negate ] = edd_negate_amount( $new_args[ $field_to_negate ] );
|
||||
}
|
||||
}
|
||||
|
||||
// Strip out the keys we don't want.
|
||||
$keys_to_remove = array( 'id', 'order_id', 'discount', 'date_created', 'date_modified', 'uuid' );
|
||||
$new_args = array_diff_key( $new_args, array_flip( $keys_to_remove ) );
|
||||
|
||||
// Status is always `complete`.
|
||||
$new_args['status'] = 'complete';
|
||||
|
||||
return $new_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the attempted refund amount is over the maximum allowed refund amount.
|
||||
*
|
||||
* @since 3.0
|
||||
* @param float $attempted_amount The amount to refund.
|
||||
* @param float $maximum_amount The maximum amount which can be refunded.
|
||||
* @return boolean
|
||||
*/
|
||||
private function is_over_refund_amount( $attempted_amount, $maximum_amount ) {
|
||||
return edd_sanitize_amount( $attempted_amount ) > edd_sanitize_amount( $maximum_amount );
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user