Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 47 additions & 6 deletions includes/data/mutation/class-checkout-mutation.php
Original file line number Diff line number Diff line change
Expand Up @@ -463,11 +463,14 @@ protected function process_order_payment( $order_id, $payment_method ) {
* Process an order that doesn't require payment.
*
* @since 3.0.0
* @param int $order_id Order ID.
* @param int $order_id Order ID.
* @param string $transaction_id Payment transaction ID.
*
* @return array
*/
protected function process_order_without_payment( $order_id ) {
protected function process_order_without_payment( $order_id, $transaction_id = '' ) {
$order = wc_get_order( $order_id );
$order->payment_complete();
$order->payment_complete( $transaction_id );
wc_empty_cart();

return array(
Expand All @@ -480,13 +483,14 @@ protected function process_order_without_payment( $order_id ) {
* Process the checkout.
*
* @param array $data Order data.
* @param array $input Input data describing order.
* @param AppContext $context AppContext instance.
* @param ResolveInfo $info ResolveInfo instance.
* @param array $results Order status.
*
* @throws UserError When validation fails.
*/
public static function process_checkout( $data, $context, $info, &$results = null ) {
public static function process_checkout( $data, $input, $context, $info, &$results = null ) {
wc_maybe_define_constant( 'WOOCOMMERCE_CHECKOUT', true );
wc_set_time_limit( 0 );

Expand Down Expand Up @@ -518,10 +522,47 @@ public static function process_checkout( $data, $context, $info, &$results = nul

do_action( 'woocommerce_checkout_order_processed', $order_id, $data, $order );

if ( WC()->cart->needs_payment() ) {
if ( WC()->cart->needs_payment() && ( empty( $input['isPaid'] ) || false === $input['isPaid'] ) ) {
$results = self::process_order_payment( $order_id, $data['payment_method'] );
} else {
$results = self::process_order_without_payment( $order_id );
$transaction_id = ! empty( $input['transactionId'] ) ? $input['transactionId'] : '';

/**
* Use this to do some last minute transaction ID validation.
*
* @param bool $is_valid Is transaction ID valid.
* @param WC_Order $order Order being processed.
* @param String|null $transaction_id Order payment transaction ID.
* @param array $data Order data.
* @param array $input Order raw input data.
* @param AppContext $context Request's AppContext instance.
* @param ResolveInfo $info Request's ResolveInfo instance.
*/
$valid = apply_filters(
'graphql_checkout_prepaid_order_validation',
true,
$order,
$transaction_id,
$data,
$input,
$context,
$info
);

if ( $valid ) {
$results = self::process_order_without_payment( $order_id, $transaction_id );
} else {
$results = array(
'result' => 'failed',
'redirect' => apply_filters(
'graphql_woocommerce_checkout_payment_failed_redirect',
$order->get_checkout_payment_url(),
$order,
$order_id,
$transaction_id
),
);
}
}

return $order_id;
Expand Down
1 change: 1 addition & 0 deletions includes/model/class-order.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function __construct( $id ) {
'id',
'orderId',
'orderNumber',
'status',
'date',
'modified',
'datePaid',
Expand Down
14 changes: 9 additions & 5 deletions includes/mutation/class-checkout.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@ public static function get_input_fields() {
'type' => 'Boolean',
'description' => __( 'Ship to a separate address', 'wp-graphql-woocommerce' ),
),
'paymentMethodTitle' => array(
'type' => 'String',
'description' => __( 'Payment method title.', 'woocommerce' ),
),
'billing' => array(
'type' => 'CustomerAddressInput',
'description' => __( 'Order billing address', 'wp-graphql-woocommerce' ),
Expand All @@ -71,6 +67,14 @@ public static function get_input_fields() {
'type' => 'CreateAccountInput',
'description' => __( 'Create new customer account', 'wp-graphql-woocommerce' ),
),
'transactionId' => array(
'type' => 'String',
'description' => __( 'Order transaction ID', 'wp-graphql-woocommerce' ),
),
'isPaid' => array(
'type' => 'Boolean',
'description' => __( 'Define if the order is paid. It will set the status to processing and reduce stock items.', 'wp-graphql-woocommerce' ),
),
'metaData' => array(
'type' => array( 'list_of' => 'MetaDataInput' ),
'description' => __( 'Order meta data', 'wp-graphql-woocommerce' ),
Expand Down Expand Up @@ -134,7 +138,7 @@ public static function mutate_and_get_payload() {
*/
do_action( 'woocommerce_graphql_before_checkout', $args, $input, $context, $info );

$order_id = Checkout_Mutation::process_checkout( $args, $context, $info, $results );
$order_id = Checkout_Mutation::process_checkout( $args, $input, $context, $info, $results );

if ( is_wp_error( $order_id ) ) {
throw new UserError( $order_id->get_error_message( 'checkout-error' ) );
Expand Down
4 changes: 2 additions & 2 deletions tests/_support/Helper/crud-helpers/order.php
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,8 @@ public function print_restricted_query( $id ) {
'orderVersion' => null,
'date' => $data->get_date_created()->__toString(),
'modified' => $data->get_date_modified()->__toString(),
'status' => null,
'discountTotal' => \wc_graphql_price( $data->get_discount_total(), array( 'currency' => $data->get_currency() ) ),
'status' => WPEnumType::get_safe_name( $data->get_status() ),
'discountTotal' => \wc_graphql_price( $data->get_discount_total(), array( 'currency' => $data->get_currency() ) ),
'discountTax' => \wc_graphql_price( $data->get_discount_tax(), array( 'currency' => $data->get_currency() ) ),
'shippingTotal' => \wc_graphql_price( $data->get_shipping_total(), array( 'currency' => $data->get_currency() ) ),
'shippingTax' => \wc_graphql_price( $data->get_shipping_tax(), array( 'currency' => $data->get_currency() ) ),
Expand Down
22 changes: 13 additions & 9 deletions tests/_support/Helper/crud-helpers/product.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,17 +140,21 @@ public function create_grouped( $args = array() ) {

public function create_variable( $args = array() ) {
$product = new WC_Product_Variable();
$product->set_props(
array_merge(
array(
'name' => $this->dummy->product(),
'slug' => $this->next_slug(),
'sku' => 'DUMMY VARIABLE SKU ' . $this->index,
),
$args
)
$props = array_merge(
array(
'name' => $this->dummy->product(),
'slug' => $this->next_slug(),
'sku' => 'DUMMY VARIABLE SKU ' . $this->index,
),
$args
);

foreach ( $props as $key => $value ) {
if ( is_callable( array( $product, "set_{$key}" ) ) ) {
$product->{"set_{$key}"}( $value );
}
}

if ( ! empty( $args['meta_data'] ) ) {
$product->set_meta_data( $args['meta_data'] );
}
Expand Down
182 changes: 182 additions & 0 deletions tests/wpunit/CheckoutMutationsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -851,4 +851,186 @@ function( $item ) {

$this->assertEquals( $expected, $actual );
}

public function testCheckoutOrderMutationWithPrepaidOrder() {
update_option( 'woocommerce_enable_guest_checkout', 'yes' );
$product_ids = array(
$this->product->create_simple(
array(
'virtual' => true,
'downloadable' => true,
)
),
$this->product->create_simple(
array(
'virtual' => true,
'downloadable' => true,
)
),
);
$coupon = new WC_Coupon(
$this->coupon->create( array( 'product_ids' => $product_ids ) )
);
WC()->cart->add_to_cart( $product_ids[0], 3 );
WC()->cart->add_to_cart( $product_ids[1], 6 );
WC()->cart->apply_coupon( $coupon->get_code() );

$input = array(
'clientMutationId' => 'someId',
'paymentMethod' => 'bacs',
'isPaid' => true,
'transactionId' => 'transaction_id',
'shippingMethod' => 'flat rate',
'billing' => array(
'firstName' => 'May',
'lastName' => 'Parker',
'address1' => '20 Ingram St',
'city' => 'New York City',
'state' => 'NY',
'postcode' => '12345',
'country' => 'US',
'email' => 'superfreak500@gmail.com',
'phone' => '555-555-1234',
),
'shipping' => array(
'firstName' => 'May',
'lastName' => 'Parker',
'address1' => '20 Ingram St',
'city' => 'New York City',
'state' => 'NY',
'postcode' => '12345',
'country' => 'US',
),
);

/**
* Assertion One
*
* Test mutation and input.
*/
$actual = $this->checkout( $input );

// use --debug flag to view.
codecept_debug( $actual );

$this->assertArrayHasKey('data', $actual );
$this->assertArrayHasKey('checkout', $actual['data'] );
$this->assertArrayHasKey('order', $actual['data']['checkout'] );
$this->assertArrayHasKey('id', $actual['data']['checkout']['order'] );
$this->assertEquals('COMPLETED', $actual['data']['checkout']['order']['status'] );
$order = \WC_Order_Factory::get_order( $actual['data']['checkout']['order']['orderId'] );

// Get Available payment gateways.
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();

$expected = array(
'data' => array(
'checkout' => array(
'clientMutationId' => 'someId',
'order' => array_merge(
$this->order->print_restricted_query( $order->get_id() ),
array(
'metaData' => array(
array(
'key' => 'is_vat_exempt',
'value' => 'no',
),
),
'couponLines' => array(
'nodes' => array_reverse(
array_map(
function( $item ) {
return array(
'itemId' => $item->get_id(),
'orderId' => $item->get_order_id(),
'code' => $item->get_code(),
'discount' => ! empty( $item->get_discount() ) ? $item->get_discount() : null,
'discountTax' => ! empty( $item->get_discount_tax() ) ? $item->get_discount_tax() : null,
'coupon' => null,
);
},
$order->get_items( 'coupon' )
)
),
),
'feeLines' => array(
'nodes' => array_reverse(
array_map(
function( $item ) {
return array(
'itemId' => $item->get_id(),
'orderId' => $item->get_order_id(),
'amount' => $item->get_amount(),
'name' => $item->get_name(),
'taxStatus' => strtoupper( $item->get_tax_status() ),
'total' => $item->get_total(),
'totalTax' => ! empty( $item->get_total_tax() ) ? $item->get_total_tax() : null,
'taxClass' => ! empty( $item->get_tax_class() )
? WPEnumType::get_safe_name( $item->get_tax_class() )
: 'STANDARD',
);
},
$order->get_items( 'fee' )
)
),
),
'shippingLines' => null,
'taxLines' => array(
'nodes' => array_reverse(
array_map(
function( $item ) {
return array(
'rateCode' => $item->get_rate_code(),
'label' => $item->get_label(),
'taxTotal' => $item->get_tax_total(),
'shippingTaxTotal' => $item->get_shipping_tax_total(),
'isCompound' => $item->is_compound(),
'taxRate' => array( 'rateId' => $item->get_rate_id() ),
);
},
$order->get_items( 'tax' )
)
),
),
'lineItems' => array(
'nodes' => array_values(
array_map(
function( $item ) {
return array(
'productId' => $item->get_product_id(),
'variationId' => ! empty( $item->get_variation_id() )
? $item->get_variation_id()
: null,
'quantity' => $item->get_quantity(),
'taxClass' => ! empty( $item->get_tax_class() )
? strtoupper( $item->get_tax_class() )
: 'STANDARD',
'subtotal' => ! empty( $item->get_subtotal() ) ? $item->get_subtotal() : null,
'subtotalTax' => ! empty( $item->get_subtotal_tax() ) ? $item->get_subtotal_tax() : null,
'total' => ! empty( $item->get_total() ) ? $item->get_total() : null,
'totalTax' => ! empty( $item->get_total_tax() ) ? $item->get_total_tax() : null,
'taxStatus' => strtoupper( $item->get_tax_status() ),
'product' => array( 'id' => $this->product->to_relay_id( $item->get_product_id() ) ),
'variation' => ! empty( $item->get_variation_id() )
? array(
'id' => $this->variation->to_relay_id( $item->get_variation_id() )
)
: null,
);
},
$order->get_items()
)
),
),
)
),
'customer' => null,
'result' => 'success',
'redirect' => $available_gateways['bacs']->process_payment( $order->get_id() )['redirect'],
),
)
);

$this->assertEquals( $expected, $actual );
}
}