api.php
2 months ago
auth.php
5 months ago
cart.php
5 months ago
coupon-apply.php
5 months ago
coupon-get.php
5 months ago
giftcard-apply.php
11 months ago
order.php
7 months ago
prepay-cod.php
2 months ago
save-abandonment-data.php
11 months ago
shipping-info.php
11 months ago
order.php
378 lines
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * create order with status pending |
| 5 | * user, adddress, coupon and shipping are left blank |
| 6 | */ |
| 7 | use Automattic\WooCommerce\Utilities\OrderUtil; |
| 8 | |
| 9 | function createWcOrder(WP_REST_Request $request) |
| 10 | { |
| 11 | try |
| 12 | { |
| 13 | rzpLogInfo("createWcOrder"); |
| 14 | global $woocommerce; |
| 15 | $params = $request->get_params(); |
| 16 | $logObj = array(); |
| 17 | $logObj['api'] = 'createWcOrder'; |
| 18 | $logObj['params'] = $params; |
| 19 | |
| 20 | // fetching wp_woocommerce_session_ from cookies |
| 21 | $sessionVal = array_filter($params['cookies'], function($key) { |
| 22 | return strpos($key, 'wp_woocommerce_session_') === 0; |
| 23 | }, ARRAY_FILTER_USE_KEY); |
| 24 | |
| 25 | foreach($sessionVal as $key => $value){ |
| 26 | $expKey = explode('wp_woocommerce_session_', $key); |
| 27 | $sessionResult = $expKey[1]; |
| 28 | } |
| 29 | |
| 30 | //Abandoment cart plugin decode the coupon code from token |
| 31 | $couponCode = null; |
| 32 | if (isset($params['token'])) { |
| 33 | $token = sanitize_text_field($params['token']); |
| 34 | parse_str(base64_decode(urldecode($token)), $token); |
| 35 | if (is_array($token) && array_key_exists('wcf_session_id', $token) && isset($token['wcf_coupon_code'])) { |
| 36 | $couponCode = $token['wcf_coupon_code']; |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | $nonce = $request->get_header('X-WP-Nonce'); |
| 41 | $verifyReq = wp_verify_nonce($nonce, 'wp_rest'); |
| 42 | |
| 43 | if ($verifyReq === false) { |
| 44 | $response['status'] = false; |
| 45 | $response['message'] = 'Authentication failed'; |
| 46 | |
| 47 | $statusCode = 401; |
| 48 | $logObj['status_code'] = $statusCode; |
| 49 | $logObj['response'] = $response; |
| 50 | rzpLogError(json_encode($logObj)); |
| 51 | |
| 52 | return new WP_REST_Response($response, $statusCode); |
| 53 | } |
| 54 | |
| 55 | initCartCommon(); |
| 56 | |
| 57 | // check if cart is empty |
| 58 | checkCartEmpty($logObj); |
| 59 | |
| 60 | $cartHash = WC()->cart->get_cart_hash(); |
| 61 | $hash = $sessionResult."_".$cartHash; |
| 62 | //Setting the $orderIdFromHash to null, to create a fresh RZP order for each checkout initialisation. |
| 63 | //In future if we need to revert back to earlier flow then consider it from transient as mentioned below. |
| 64 | // $orderIdFromHash = get_transient(RZP_1CC_CART_HASH . $hash); |
| 65 | $orderIdFromHash = null; |
| 66 | |
| 67 | if (isHposEnabled()) { |
| 68 | $updateOrderStatus = 'checkout-draft'; |
| 69 | } else { |
| 70 | // Check if WooCommerce supports the "checkout-draft" status (added in newer versions). |
| 71 | $postStatus = get_post_status_object('wc-checkout-draft'); |
| 72 | if ($postStatus) { |
| 73 | $updateOrderStatus = 'checkout-draft'; |
| 74 | } else { |
| 75 | $updateOrderStatus = 'draft'; // Older WooCommerce versions fallback |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | if ($orderIdFromHash == null) { |
| 80 | $checkout = WC()->checkout(); |
| 81 | $orderId = $checkout->create_order(array()); |
| 82 | |
| 83 | if (is_wp_error($orderId) || empty($orderId)) { |
| 84 | $checkout_error = is_wp_error($orderId) ? $orderId->get_error_message() : "Invalid order ID returned"; |
| 85 | rzpLogError("WooCommerce Order Creation Failed: " . $checkout_error); |
| 86 | |
| 87 | $response = [ |
| 88 | 'status' => false, |
| 89 | 'message' => "Unable to create WooCommerce order: " . $checkout_error, |
| 90 | 'code' => 'ORDER_CREATION_FAILED', |
| 91 | ]; |
| 92 | $status = 500; |
| 93 | |
| 94 | return new WP_REST_Response($response, $status); |
| 95 | } |
| 96 | //Keep order in draft status untill customer info available |
| 97 | updateOrderStatus($orderId, $updateOrderStatus); |
| 98 | } else { |
| 99 | $existingOrder = wc_get_order($orderIdFromHash); |
| 100 | $orderStatus = $existingOrder->get_status(); |
| 101 | $existingOrder->calculate_totals(); |
| 102 | if ($orderStatus != $updateOrderStatus && $existingOrder->needs_payment() == false) { |
| 103 | $woocommerce->session->__unset(RZP_1CC_CART_HASH . $cartHash); |
| 104 | $checkout = WC()->checkout(); |
| 105 | $orderId = $checkout->create_order(array()); |
| 106 | |
| 107 | if (is_wp_error($orderId) || empty($orderId)) { |
| 108 | $checkout_error = is_wp_error($orderId) ? $orderId->get_error_message() : "Invalid order ID returned"; |
| 109 | rzpLogError("WooCommerce Order Creation Failed: " . $checkout_error); |
| 110 | |
| 111 | $response = [ |
| 112 | 'status' => false, |
| 113 | 'message' => "Unable to create WooCommerce order: " . $checkout_error, |
| 114 | 'code' => 'ORDER_CREATION_FAILED', |
| 115 | ]; |
| 116 | $status = 500; |
| 117 | |
| 118 | return new WP_REST_Response($response, $status); |
| 119 | } |
| 120 | //Keep order in draft status untill customer info available |
| 121 | updateOrderStatus($orderId, $updateOrderStatus); |
| 122 | } else { |
| 123 | $orderId = $orderIdFromHash; |
| 124 | //To get the applied coupon details from cart object. |
| 125 | $coupons = WC()->cart->get_coupons(); |
| 126 | $couponCode = !empty($coupons) ? array_key_first($coupons) : null; |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | $order = wc_get_order($orderId); |
| 131 | |
| 132 | if($order){ |
| 133 | |
| 134 | $disableCouponFlag = false; |
| 135 | |
| 136 | // Woo dynamic discount price plugin |
| 137 | if(is_plugin_active('yith-woocommerce-dynamic-pricing-and-discounts-premium/init.php')) { |
| 138 | foreach ($order->get_items() as $itemId => $item) { |
| 139 | $dynamicRules = $item->get_meta('_ywdpd_discounts'); |
| 140 | |
| 141 | if(empty($dynamicRules) == false){ |
| 142 | |
| 143 | foreach ($dynamicRules['applied_discounts'] as $appliedDiscount) { |
| 144 | if (isset( $appliedDiscount['set_id'])){ |
| 145 | $ruleId = $appliedDiscount['set_id']; |
| 146 | $rule = ywdpd_get_rule($ruleId); |
| 147 | } else { |
| 148 | $rule = $appliedDiscount['by']; |
| 149 | } |
| 150 | // check coupon is disable with discount price |
| 151 | if($rule->is_disabled_with_other_coupon() == 1){ |
| 152 | $disableCouponFlag = true; |
| 153 | } |
| 154 | } |
| 155 | } |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | // Pixel your site PRO UTM data |
| 160 | if (is_plugin_active('pixelyoursite-pro/pixelyoursite-pro.php')) { |
| 161 | |
| 162 | $pysData = get_option('pys_core'); |
| 163 | |
| 164 | // Store UTM data only if config enabled. |
| 165 | if ($pysData['woo_enabled_save_data_to_orders'] == true) { |
| 166 | wooSaveCheckoutUTMFields($order, $params); |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | // To remove coupon added on order. |
| 171 | $coupons = $order->get_coupon_codes(); |
| 172 | if (!empty($coupons)) { |
| 173 | foreach ($coupons as $coupon) { |
| 174 | $order->remove_coupon($coupon); |
| 175 | } |
| 176 | $couponCode = $coupons[0]; |
| 177 | } |
| 178 | |
| 179 | //To remove by default shipping method added on order. |
| 180 | $items = (array) $order->get_items('shipping'); |
| 181 | |
| 182 | if (sizeof($items) > 0) { |
| 183 | // Loop through shipping items |
| 184 | foreach ($items as $item_id => $item) { |
| 185 | $order->remove_item($item_id); |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | $order->calculate_totals(); |
| 190 | |
| 191 | if (isHposEnabled()) { |
| 192 | $order->update_meta_data( 'is_magic_checkout_order', 'yes' ); |
| 193 | $order->save(); |
| 194 | }else{ |
| 195 | update_post_meta($orderId, 'is_magic_checkout_order', 'yes'); |
| 196 | } |
| 197 | |
| 198 | $minCartAmount1cc = !empty(get_option('woocommerce_razorpay_settings')['1cc_min_cart_amount']) ? get_option('woocommerce_razorpay_settings')['1cc_min_cart_amount'] : 0; |
| 199 | |
| 200 | // Response sent to the user when order creation fails |
| 201 | if ($order->get_total() < $minCartAmount1cc) { |
| 202 | $response['status'] = false; |
| 203 | $response['message'] = 'Your current order total is ₹' . $order->get_total() . ' — you must have an order with a minimum of ₹' . $minCartAmount1cc . ' to place your order'; |
| 204 | $response['code'] = 'MIN_CART_AMOUNT_CHECK_FAILED'; |
| 205 | |
| 206 | $status = 400; |
| 207 | $logObj['response'] = $response; |
| 208 | $logObj['rzp_order_id'] = $rzp_order_id; |
| 209 | $logObj['rzp_response'] = $rzp_response; |
| 210 | rzpLogError(json_encode($logObj)); |
| 211 | |
| 212 | return new WP_REST_Response($response, $status); |
| 213 | } |
| 214 | |
| 215 | $razorpay = new WC_Razorpay(false); |
| 216 | |
| 217 | $rzp_order_id = $razorpay->createOrGetRazorpayOrderId($order, $orderId, 'yes'); |
| 218 | $rzp_response = $razorpay->getDefaultCheckoutArguments($order); |
| 219 | |
| 220 | // Response sent to the user when order creation fails |
| 221 | if (empty($rzp_response['order_id'])) { |
| 222 | $response['status'] = false; |
| 223 | $response['message'] = 'Unable to create order'; |
| 224 | $response['code'] = 'ORDER_CREATION_FAILED'; |
| 225 | |
| 226 | $status = 400; |
| 227 | $logObj['response'] = $response; |
| 228 | $logObj['rzp_order_id'] = $rzp_order_id; |
| 229 | $logObj['rzp_response'] = $rzp_response; |
| 230 | rzpLogError(json_encode($logObj)); |
| 231 | |
| 232 | $trackObject = $razorpay->newTrackPluginInstrumentation(); |
| 233 | $properties = [ |
| 234 | 'error' => 'Unable to create order', |
| 235 | 'log' => $logObj |
| 236 | ]; |
| 237 | $trackObject->rzpTrackDataLake('razorpay.1cc.create.order.failed', $properties); |
| 238 | |
| 239 | return new WP_REST_Response($response, $status); |
| 240 | } |
| 241 | |
| 242 | // TODO: getDefaultCheckoutArguments() is already being called in L65 above |
| 243 | $response = $razorpay->getDefaultCheckoutArguments($order); |
| 244 | |
| 245 | $fbAnalytics = get_option('woocommerce_razorpay_settings')['enable_1cc_fb_analytics'] === 'yes' ? true : false; |
| 246 | |
| 247 | |
| 248 | if($disableCouponFlag == true){ |
| 249 | $response['show_coupons'] = false; |
| 250 | } |
| 251 | |
| 252 | if ($fbAnalytics === true) { |
| 253 | //Customer cart related data for FB analytics. |
| 254 | $customer_cart['value'] = (string) WC()->cart->subtotal; |
| 255 | $customer_cart['content_type'] = 'product'; |
| 256 | $customer_cart['currency'] = 'INR'; |
| 257 | |
| 258 | $x = 0; |
| 259 | // Loop over $cart items |
| 260 | foreach (WC()->cart->get_cart() as $cart_item) { |
| 261 | |
| 262 | $customer_cart['contents'][$x]['id'] = (string) $cart_item['product_id']; |
| 263 | $customer_cart['contents'][$x]['name'] = $cart_item['data']->get_title(); |
| 264 | $customer_cart['contents'][$x]['quantity'] = (string) $cart_item['quantity']; |
| 265 | $customer_cart['contents'][$x]['value'] = (string) ($cart_item['line_subtotal'] + $cart_item['line_subtotal_tax']) / $cart_item['quantity']; |
| 266 | $customer_cart['contents'][$x]['variant_id'] = (string) $cart_item['variation_id']; |
| 267 | |
| 268 | $x++; |
| 269 | } |
| 270 | |
| 271 | $response['customer_cart'] = $customer_cart ?? ''; |
| 272 | } |
| 273 | |
| 274 | $hash = $sessionResult."_".$cartHash; |
| 275 | $woocommerce->session->set(RZP_1CC_CART_HASH . $hash, $orderId); |
| 276 | set_transient(RZP_1CC_CART_HASH . $orderId, $hash, 14400); |
| 277 | set_transient(RZP_1CC_CART_HASH . $hash, $orderId, 14400); |
| 278 | set_transient($razorpay::SESSION_KEY, $orderId, 14400); |
| 279 | |
| 280 | $logObj['response'] = $response; |
| 281 | rzpLogInfo(json_encode($logObj)); |
| 282 | |
| 283 | return new WP_REST_Response($response, 200); |
| 284 | } else { |
| 285 | $response['status'] = false; |
| 286 | $response['message'] = $checkout_error; |
| 287 | $response['code'] = 'WOOCOMMERCE_ORDER_CREATION_FAILED'; |
| 288 | |
| 289 | $logObj['response'] = $response; |
| 290 | $logObj['status_code'] = 400; |
| 291 | rzpLogError(json_encode($logObj)); |
| 292 | |
| 293 | $rzp = new WC_Razorpay(); |
| 294 | $trackObject = $rzp->newTrackPluginInstrumentation(); |
| 295 | $properties = [ |
| 296 | 'error' => $checkout_error, |
| 297 | 'log' => $logObj |
| 298 | ]; |
| 299 | $trackObject->rzpTrackDataLake('razorpay.1cc.create.woocommerce.order.failed', $properties); |
| 300 | |
| 301 | return new WP_REST_Response($response, 400); |
| 302 | } |
| 303 | } |
| 304 | catch (Throwable $e) |
| 305 | { |
| 306 | $rzp = new WC_Razorpay(); |
| 307 | $trackObject = $rzp->newTrackPluginInstrumentation(); |
| 308 | $properties = [ |
| 309 | 'error' => $e->getMessage(), |
| 310 | 'code' => $e->getCode(), |
| 311 | 'file' => $e->getFile(), |
| 312 | 'line' => $e->getLine() |
| 313 | ]; |
| 314 | $trackObject->rzpTrackDataLake('razorpay.1cc.create.order.processing.failed', $properties); |
| 315 | rzpLogError(json_encode($properties)); |
| 316 | |
| 317 | return new WP_REST_Response(['message' => "woocommerce server error : " . $e->getMessage()], 500); |
| 318 | } |
| 319 | } |
| 320 | |
| 321 | //Update order status according to the steps. |
| 322 | function updateOrderStatus($orderId, $orderStatus) |
| 323 | { |
| 324 | $order = wc_get_order( $orderId ); |
| 325 | |
| 326 | if (is_object($order) === false) { |
| 327 | return; |
| 328 | } |
| 329 | |
| 330 | if (isHposEnabled()) { |
| 331 | $order->update_status($orderStatus); |
| 332 | $order->save(); |
| 333 | }else{ |
| 334 | // Handling order status update for WooCommerce versions that do not support HPOS. |
| 335 | // We are unsure if older versions use `wp_update_post()`, while newer versions may use `$order->update_status()`. |
| 336 | // To maintain compatibility across different WooCommerce versions, we add an additional if-else condition. |
| 337 | if (!isHposEnabled()) { // Explicitly checking if HPOS is NOT enabled |
| 338 | $order->update_status($orderStatus); |
| 339 | $order->save(); // Save changes |
| 340 | } else { |
| 341 | wp_update_post([ |
| 342 | 'ID' => $orderId, |
| 343 | 'post_status' => $orderStatus, |
| 344 | ]); |
| 345 | } |
| 346 | } |
| 347 | |
| 348 | } |
| 349 | |
| 350 | function wooSaveCheckoutUTMFields($order, $params) |
| 351 | { |
| 352 | $pysData = []; |
| 353 | $cookieData = $params['cookies']; |
| 354 | $getQuery = $params['requestData']; |
| 355 | $browserTime = $params['dateTime']; |
| 356 | $pysData['pys_landing'] = isset($cookieData['pys_landing_page']) ? ($cookieData['pys_landing_page']) : ""; |
| 357 | $pysData['pys_source'] = isset($cookieData['pysTrafficSource']) ? ($cookieData['pysTrafficSource']) : "direct"; |
| 358 | if ($pysData['pys_source'] == 'direct') { |
| 359 | $pysData['pys_source'] = $params['referrerDomain'] != '' ? $params['referrerDomain'] : "direct"; |
| 360 | } |
| 361 | $pysUTMSource = $cookieData['pys_utm_source'] ?? $getQuery['utm_source']; |
| 362 | $pysUTMMedium = $cookieData['pys_utm_medium'] ?? $getQuery['utm_medium']; |
| 363 | $pysUTMCampaign = $cookieData['pys_utm_campaign'] ?? $getQuery['utm_medium']; |
| 364 | $pysUTMTerm = $cookieData['pys_utm_term'] ?? $getQuery['utm_term']; |
| 365 | $pysUTMContent = $cookieData['pys_utm_content'] ?? $getQuery['utm_content']; |
| 366 | |
| 367 | $pysData['pys_utm'] = "utm_source:" . $pysUTMSource . "|utm_medium:" . $pysUTMMedium . "|utm_campaign:" . $pysUTMCampaign . "|utm_term:" . $pysUTMTerm . "|utm_content:" . $pysUTMContent; |
| 368 | $pysData['pys_browser_time'] = $browserTime[0] . "|" . $browserTime[1] . "|" . $browserTime[2]; |
| 369 | |
| 370 | if (isHposEnabled()) { |
| 371 | $order->update_meta_data( 'pys_enrich_data', $pysData ); |
| 372 | $order->save(); |
| 373 | }else{ |
| 374 | update_post_meta($order->get_id(), "pys_enrich_data", $pysData); |
| 375 | } |
| 376 | |
| 377 | } |
| 378 |