Process.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. <?php
  2. class Laybuy_Processes_CreateOrder_WC_LT_3_6_Process extends Laybuy_Processes_CreateOrder_CreateOrderAbstract
  3. {
  4. public $quoteId;
  5. public function setQuoteId($quoteId)
  6. {
  7. $this->quoteId = $quoteId;
  8. }
  9. public function getQuoteId()
  10. {
  11. return $this->quoteId;
  12. }
  13. public function execute()
  14. {
  15. try {
  16. $quote_id = $this->getQuoteId();
  17. WC_Laybuy_Logger::log("Creating an WC order from a quote {$quote_id}. Transaction start");
  18. // Start transaction if available
  19. wc_transaction_query( 'start' );
  20. # Retrieve the order data from the Laybuy_Quote item.
  21. $_POST = $this->_decode(get_post_meta( $quote_id, '$_POST', true ));
  22. $customer_id = get_post_meta( $quote_id, 'customer_id', true );
  23. $cart_hash = get_post_meta( $quote_id, 'cart_hash', true );
  24. $cart_shipping_total = (float)get_post_meta( $quote_id, 'cart_shipping_total', true );
  25. $cart_shipping_tax_total = (float)get_post_meta( $quote_id, 'cart_shipping_tax_total', true );
  26. $cart_discount_total = (float)get_post_meta( $quote_id, 'cart_discount_total', true );
  27. $cart_discount_tax_total = (float)get_post_meta( $quote_id, 'cart_discount_tax_total', true );
  28. $cart_tax_total = (float)get_post_meta( $quote_id, 'cart_tax_total', true );
  29. $cart_total = (float)get_post_meta( $quote_id, 'cart_total', true );
  30. $cart_items = json_decode(get_post_meta( $quote_id, 'cart_items', true ), true);
  31. $cart_fees = json_decode(get_post_meta( $quote_id, 'cart_fees', true ), false);
  32. $cart_coupons = json_decode(get_post_meta( $quote_id, 'cart_coupons', true ), true);
  33. $cart_taxes = json_decode(get_post_meta( $quote_id, 'cart_taxes', true ), true);
  34. if ( WC_Laybuy_Helper::is_wc_gt( '3.0' ) ) {
  35. $chosen_shipping_methods = json_decode(get_post_meta( $quote_id, 'chosen_shipping_methods', true ), true);
  36. }
  37. $shipping_packages = json_decode(get_post_meta( $quote_id, 'shipping_packages', true ), true);
  38. $billing_address = json_decode(get_post_meta( $quote_id, 'billing_address', true ), true);
  39. $shipping_address = json_decode(get_post_meta( $quote_id, 'shipping_address', true ), true);
  40. $posted = json_decode(get_post_meta( $quote_id, 'posted', true ), true);
  41. // Force-delete the Laybuy_Quote item. This will make its ID available to be used as the WC_Order ID.
  42. wp_delete_post( $quote_id, true );
  43. // Create the WC_Order item.
  44. $order_data = array(
  45. 'status' => apply_filters( 'woocommerce_default_order_status', 'pending' ),
  46. 'customer_id' => $customer_id,
  47. 'customer_note' => isset( $posted['order_comments'] ) ? $posted['order_comments'] : '',
  48. 'cart_hash' => $cart_hash,
  49. 'created_via' => 'checkout',
  50. );
  51. $GLOBALS['laybuy_quote_id'] = $quote_id;
  52. $order = wc_create_order( $order_data );
  53. if (isset($GLOBALS['laybuy_quote_id'])) {
  54. unset($GLOBALS['laybuy_quote_id']);
  55. }
  56. if ( is_wp_error( $order ) ) {
  57. throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 520 ) );
  58. } elseif ( false === $order ) {
  59. throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 521 ) );
  60. } else {
  61. # avoid older WooCommerce error
  62. if (method_exists($order, "get_id")) {
  63. $order_id = $order->get_id();
  64. }
  65. else {
  66. $order_id = $order->ID;
  67. }
  68. do_action( 'woocommerce_new_order', $order_id );
  69. }
  70. $this->create_order_line_items($order, $cart_items);
  71. $this->create_order_fee_lines($order, $cart_fees);
  72. $this->create_order_shipping_lines($order, $shipping_packages, $chosen_shipping_methods);
  73. $this->create_order_tax_lines($order, $cart_taxes);
  74. $this->create_order_coupon_lines($order, $cart_coupons);
  75. /**
  76. * @since 2.0.3
  77. * Decode the shipping & billing address fields.
  78. */
  79. foreach($billing_address as $key => $billing_data) {
  80. $billing_address[$key] = $this->_decode($billing_data);
  81. }
  82. foreach($shipping_address as $key => $shipping_data) {
  83. $shipping_address[$key] = $this->_decode($shipping_data);
  84. }
  85. $order->set_address( $billing_address, 'billing' );
  86. $order->set_address( $shipping_address, 'shipping' );
  87. $order->set_payment_method( $this->getProcessManager()->getWcGateway() );
  88. if ( WC_Laybuy_Helper::is_wc_gt( '3.0' ) ) {
  89. $order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
  90. $order->set_customer_ip_address( WC_Geolocation::get_ip_address() );
  91. $order->set_customer_user_agent( wc_get_user_agent() );
  92. $order->set_shipping_total( $cart_shipping_total );
  93. $order->set_discount_total( $cart_discount_total );
  94. $order->set_discount_tax( $cart_discount_tax_total );
  95. $order->set_cart_tax( $cart_tax_total );
  96. $order->set_shipping_tax( $cart_shipping_tax_total );
  97. } else {
  98. $order->set_total( $cart_shipping_total, 'shipping' );
  99. $order->set_total( $cart_discount_total, 'cart_discount' );
  100. $order->set_total( $cart_discount_tax_total, 'cart_discount_tax' );
  101. $order->set_total( $cart_tax_total, 'tax' );
  102. $order->set_total( $cart_shipping_tax_total, 'shipping_tax' );
  103. }
  104. $order->set_total( $cart_total );
  105. do_action( 'woocommerce_checkout_update_order_meta', $order_id, $posted );
  106. WC_Laybuy_Logger::log("Committing transaction");
  107. // If we got here, the order was created without problems!
  108. wc_transaction_query( 'commit' );
  109. WC_Laybuy_Logger::log("Order created successfully from a quote {$quote_id}");
  110. } catch ( Exception $e ) {
  111. // There was an error adding order data!
  112. wc_transaction_query( 'rollback' );
  113. WC_Laybuy_Logger::log("Error while WC creating an order from a quote {$quote_id} " . $e->getMessage());
  114. return new WP_Error( 'checkout-error', $e->getMessage() );
  115. }
  116. return $order;
  117. }
  118. public function create_order_line_items($order, $cart_items) {
  119. WC_Laybuy_Logger::log("create_order_line_items - Start");
  120. WC_Laybuy_Logger::log("cart_items: " . print_r($cart_items, true));
  121. // Store the line items to the new/resumed order
  122. foreach ( $cart_items as $cart_item_key => $cart_item ) {
  123. if ( WC_Laybuy_Helper::is_wc_gt( '3.0' ) ) {
  124. $values = array(
  125. 'data' => wc_get_product($cart_item['id']),
  126. 'quantity' => $cart_item['props']['quantity'],
  127. 'variation' => $this->_decode($cart_item['props']['variation']),
  128. 'line_subtotal' => $cart_item['props']['subtotal'],
  129. 'line_total' => $cart_item['props']['total'],
  130. 'line_subtotal_tax' => $cart_item['props']['subtotal_tax'],
  131. 'line_tax' => $cart_item['props']['total_tax'],
  132. 'line_tax_data' => $cart_item['props']['taxes']
  133. );
  134. # Also reinsert any custom line item fields
  135. # that may have been attached by third-party plugins.
  136. foreach( $cart_item as $cart_item_key => $cart_item_value ) {
  137. if( !in_array($cart_item_key, array('id', 'props')) ) {
  138. $values[$cart_item_key] = $this->_decode($cart_item_value);
  139. }
  140. }
  141. $item = apply_filters( 'woocommerce_checkout_create_order_line_item_object', new WC_Order_Item_Product(), $cart_item_key, $values, $order );
  142. $item->legacy_values = $values; // @deprecated For legacy actions.
  143. $item->legacy_cart_item_key = $cart_item_key; // @deprecated For legacy actions.
  144. $item->set_props( array(
  145. 'quantity' => $cart_item['props']['quantity'],
  146. 'variation' => $this->_decode($cart_item['props']['variation']),
  147. 'subtotal' => $cart_item['props']['subtotal'],
  148. 'total' => $cart_item['props']['total'],
  149. 'subtotal_tax' => $cart_item['props']['subtotal_tax'],
  150. 'total_tax' => $cart_item['props']['total_tax'],
  151. 'taxes' => $cart_item['props']['taxes'],
  152. 'name' => $this->_decode($cart_item['props']['name']),
  153. 'tax_class' => $this->_decode($cart_item['props']['tax_class']),
  154. 'product_id' => $cart_item['props']['product_id'],
  155. 'variation_id' => $cart_item['props']['variation_id']
  156. ) );
  157. $item->set_backorder_meta();
  158. do_action( 'woocommerce_checkout_create_order_line_item', $item, $cart_item_key, $values, $order );
  159. // Add item to order and save.
  160. $order->add_item( $item );
  161. } else {
  162. $product = new $cart_item['class']( $cart_item['id'] );
  163. unset( $cart_item['class'] );
  164. unset( $cart_item['id'] );
  165. $cart_item['data'] = $product;
  166. $item_id = $order->add_product(
  167. $product,
  168. $cart_item['quantity'],
  169. array(
  170. 'variation' => $this->_decode($cart_item['variation']),
  171. 'totals' => $cart_item['totals']
  172. )
  173. );
  174. if ( ! $item_id ) {
  175. throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 525 ) );
  176. }
  177. // Allow plugins to add order item meta
  178. do_action( 'woocommerce_add_order_item_meta', $item_id, $cart_item, $cart_item_key );
  179. }
  180. }
  181. WC_Laybuy_Logger::log("create_order_line_items - End");
  182. }
  183. /*
  184. * Add coupon lines to the order.
  185. */
  186. public function create_order_coupon_lines($order, $cart_coupons) {
  187. WC_Laybuy_Logger::log("create_order_coupon_lines - Start");
  188. WC_Laybuy_Logger::log("cart_coupons: " . print_r($cart_coupons, true));
  189. // Store coupons
  190. foreach ( $cart_coupons as $code => $coupon_data ) {
  191. if ( WC_Laybuy_Helper::is_wc_gt( '3.0' ) ) {
  192. $item = new WC_Order_Item_Coupon();
  193. $item->set_props(
  194. array(
  195. 'code' => $code,
  196. 'discount' => $coupon_data['discount_amount'],
  197. 'discount_tax' => $coupon_data['discount_tax_amount'],
  198. )
  199. );
  200. // Avoid storing used_by - it's not needed and can get large.
  201. if (isset($coupon_data['used_by'])) {
  202. unset( $coupon_data['used_by'] );
  203. }
  204. $item->add_meta_data( 'coupon_data', $coupon_data );
  205. $coupon = new WC_Coupon( $code );
  206. /**
  207. * Action hook to adjust item before save.
  208. *
  209. * @since 3.0.0
  210. */
  211. do_action( 'woocommerce_checkout_create_order_coupon_item', $item, $code, $coupon, $order );
  212. // Add item to order and save.
  213. $order->add_item( $item );
  214. } else {
  215. if ( ! $order->add_coupon( $code, $coupon_data['discount_amount'], $coupon_data['discount_tax_amount'] ) ) {
  216. throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 529 ) );
  217. }
  218. }
  219. }
  220. }
  221. public function create_order_tax_lines($order, $cart_taxes) {
  222. WC_Laybuy_Logger::log("create_order_tax_lines - Start");
  223. WC_Laybuy_Logger::log("cart_taxes: " . print_r($cart_taxes, true));
  224. // Store tax rows
  225. foreach ( $cart_taxes as $tax_rate_id => $cart_tax ) {
  226. if ( WC_Laybuy_Helper::is_wc_gt( '3.0' ) ) {
  227. if ( $tax_rate_id && apply_filters( 'woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated' ) !== $tax_rate_id ) {
  228. $item = new WC_Order_Item_Tax();
  229. $item->set_props(
  230. array(
  231. 'rate_id' => $tax_rate_id,
  232. 'tax_total' => $cart_tax['tax_amount'],
  233. 'shipping_tax_total' => $cart_tax['shipping_tax_amount'],
  234. 'rate_code' => WC_Tax::get_rate_code( $tax_rate_id ),
  235. 'label' => WC_Tax::get_rate_label( $tax_rate_id ),
  236. 'compound' => WC_Tax::is_compound( $tax_rate_id ),
  237. )
  238. );
  239. /**
  240. * Action hook to adjust item before save.
  241. *
  242. * @since 3.0.0
  243. */
  244. do_action( 'woocommerce_checkout_create_order_tax_item', $item, $tax_rate_id, $order );
  245. // Add item to order and save.
  246. $order->add_item( $item );
  247. } else {
  248. if ( ! $order->add_tax( $tax_rate_id, $cart_tax['tax_amount'], $cart_tax['shipping_tax_amount'] ) ) {
  249. throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 528 ) );
  250. }
  251. }
  252. }
  253. }
  254. WC_Laybuy_Logger::log("create_order_tax_lines - End");
  255. }
  256. public function create_order_shipping_lines($order, $shipping_packages, $chosen_shipping_methods) {
  257. WC_Laybuy_Logger::log("create_order_shipping_lines - Start");
  258. WC_Laybuy_Logger::log("shipping_packages: " . print_r($shipping_packages, true));
  259. /**
  260. * Store shipping for all packages
  261. * see WC_Checkout::create_order_shipping_lines
  262. */
  263. foreach ( $shipping_packages as $package_key => $package_data ) {
  264. $package_metadata = $this->_decode( $package_data['package_metadata'] );
  265. if (version_compare( WC_VERSION, '3.0.0', '>=' )) {
  266. $package = $this->_decode( $package_data['package'] );
  267. if ( isset( $chosen_shipping_methods[ $package_key ], $package['rates'][ $chosen_shipping_methods[ $package_key ] ] ) ) {
  268. $shipping_rate = $package['rates'][ $chosen_shipping_methods[ $package_key ] ];
  269. $item = new WC_Order_Item_Shipping;
  270. $item->legacy_package_key = $package_key; // @deprecated For legacy actions.
  271. $item->set_props( array(
  272. 'method_title' => $shipping_rate->label,
  273. 'method_id' => $shipping_rate->method_id,
  274. 'instance_id' => $shipping_rate->instance_id,
  275. 'total' => wc_format_decimal( $shipping_rate->cost ),
  276. 'taxes' => array(
  277. 'total' => $shipping_rate->taxes,
  278. ),
  279. ) );
  280. foreach ( $package_metadata as $key => $value ) {
  281. $item->add_meta_data( $key, $value, true );
  282. }
  283. /**
  284. * Action hook to adjust item before save.
  285. * @since WooCommerce 3.0.0
  286. */
  287. do_action( 'woocommerce_checkout_create_order_shipping_item', $item, $package_key, $package, $order );
  288. // Add item to order and save.
  289. $order->add_item( $item );
  290. }
  291. } else {
  292. $package = new WC_Shipping_Rate( $package_data['id'], $this->_decode($package_data['label']), $package_data['cost'], $package_data['taxes'], $package_data['method_id'] );
  293. foreach ($package_metadata as $key => $value) {
  294. $package->add_meta_data($key, $value);
  295. }
  296. $item_id = $order->add_shipping( $package );
  297. if ( ! $item_id ) {
  298. throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 527 ) );
  299. }
  300. // Allows plugins to add order item meta to shipping
  301. do_action( 'woocommerce_add_shipping_order_item', $order->get_id(), $item_id, $package_key );
  302. }
  303. }
  304. WC_Laybuy_Logger::log("create_order_shipping_lines - End");
  305. }
  306. public function create_order_fee_lines($order, $cart_fees) {
  307. WC_Laybuy_Logger::log("create_order_fee_lines - Start");
  308. WC_Laybuy_Logger::log("cart_fees: " . print_r($cart_fees, true));
  309. // Store fees
  310. foreach ( $cart_fees as $fee_key => $fee ) {
  311. $tax_data = array();
  312. if (is_string($fee)) { // decode custom fee object
  313. $fee = $this->_decode($fee);
  314. }
  315. foreach ($fee->tax_data as $key_str => $amount) {
  316. $tax_data[(int)$key_str] = $this->_decode($amount);
  317. }
  318. if ( WC_Laybuy_Helper::is_wc_gt( '3.0' ) ) {
  319. $item = new WC_Order_Item_Fee();
  320. $item->legacy_fee = $fee; // @deprecated For legacy actions.
  321. $item->legacy_fee_key = $fee_key; // @deprecated For legacy actions.
  322. $item->set_props(
  323. array(
  324. 'name' => $fee->name,
  325. 'tax_class' => $fee->taxable ? $fee->tax_class : 0,
  326. 'amount' => $fee->amount,
  327. 'total' => $fee->total,
  328. 'total_tax' => $fee->tax,
  329. 'taxes' => array(
  330. 'total' => $tax_data,
  331. ),
  332. )
  333. );
  334. /**
  335. * Action hook to adjust item before save.
  336. *
  337. * @since 3.0.0
  338. */
  339. do_action( 'woocommerce_checkout_create_order_fee_item', $item, $fee_key, $fee, $order );
  340. // Add item to order and save.
  341. $order->add_item( $item );
  342. } else {
  343. $fee->tax_data = $tax_data;
  344. $item_id = $order->add_fee( $fee );
  345. if ( ! $item_id ) {
  346. throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 526 ) );
  347. }
  348. }
  349. // Allow plugins to add order item meta to fees
  350. do_action( 'woocommerce_add_order_fee_meta', $order->get_id(), $item_id, $fee, $fee_key );
  351. }
  352. WC_Laybuy_Logger::log("create_order_fee_lines - End");
  353. }
  354. }