AliexpressModel = $AliexpressModel; $this->ExternalOrderFactory = $ExternalOrderFactory; $this->AliexpressHelper = $AliexpressHelper; $this->WoocommerceService = $WoocommerceService; $this->WoocommerceModel = $WoocommerceModel; $this->ProductService = $ProductService; $this->OrderShippingDataService = $OrderShippingDataService; } public function placeOrder(WC_Order $WC_Order, array $OrderItems): array { a2wl_init_error_handler(); try { $ExternalOrder = $this->ExternalOrderFactory ->createOrderFromWooOrder($WC_Order, $OrderItems); $currencyCode = get_setting('local_currency', 'USD'); $apiResult = $this->AliexpressModel->placeOrder($ExternalOrder, $currencyCode); if ($apiResult['state'] !== 'ok') { return $apiResult; } $aliexpressOrders = $apiResult['orders']['list']; foreach ($aliexpressOrders as $aliexpressOrder) { if (!isset($aliexpressOrder['child_order_list']['ae_child_order_info'])) { $errorText = _x( 'Bad API format in OrderFulfillmentService. Contact support.', 'api error', 'ali2woo' ); error_log($errorText); continue; } foreach ($aliexpressOrder['child_order_list']['ae_child_order_info'] as $ae_product_info) { foreach ($OrderItems as $order_item) { $a2wl_order_item = new WooCommerceOrderItem($order_item); $externalSkuId = $a2wl_order_item->get_external_sku_id(); $matchedBySku = $externalSkuId !== null && isset($ae_product_info['sku_id']) && (string)$externalSkuId === (string)$ae_product_info['sku_id']; $matchedByProduct = ($a2wl_order_item->get_external_product_id() == $ae_product_info['product_id']); if ($matchedBySku || $matchedByProduct) { $a2wl_order_item->update_external_order($aliexpressOrder['order_id'], true); } } } } foreach ($OrderItems as $order_item) { $a2wl_order_item = new WooCommerceOrderItem($order_item); $externalOrderId = $a2wl_order_item->get_external_order_id(); if ($externalOrderId) { a2wl_error_log(sprintf( 'A2WL fulfillment: external order id [%s] received for WC order #%d (item %d).', $externalOrderId, $WC_Order->get_id(), $order_item->get_id() )); } else { a2wl_error_log(sprintf( 'A2WL fulfillment: external order id NOT received for WC order #%d (item %d).', $WC_Order->get_id(), $order_item->get_id() )); } } $result = ResultBuilder::buildOk(); $placed_order_status = get_setting('placed_order_status'); if ($placed_order_status) { $WC_Order->update_status($placed_order_status); } restore_error_handler(); } catch (FactoryException $FactoryException) { $extraData = $FactoryException->getExtraData(); $result = ResultBuilder::buildError( $FactoryException->getMessage(), $extraData ?? false ); } catch (Throwable $Exception) { a2wl_print_throwable($Exception); $result = ResultBuilder::buildError($Exception->getMessage()); } return $result; } /** * @param array $orders * @param bool $is_wpml * @return array * @throws RepositoryException|ServiceException */ public function getFulfillmentOrdersData(array $orders, bool $is_wpml = false): array { global $sitepress; $orders_data = []; foreach ($orders as $order) { // copied from woocommerce/includes/admin/list-tables/class-wc-admin-list-table-orders.php $buyer = ''; if ($order->get_billing_first_name() || $order->get_billing_last_name()) { $buyerName = sprintf( /* translators: %1$s first name %2$s last name */ _x('%1$s %2$s', 'full name', 'woocommerce'), $order->get_billing_first_name(), $order->get_billing_last_name() ); $buyer = trim($buyerName); } elseif ($order->get_billing_company()) { $buyer = trim($order->get_billing_company()); } elseif ($order->get_customer_id()) { $user = get_user_by('id', $order->get_customer_id()); $buyer = ucwords($user->display_name); } /** * Filter buyer name in list table orders. * * @since 3.7.0 * @param string $buyer Buyer name. * @param WC_Order $order Order data. */ $order_data['buyer'] = apply_filters('woocommerce_admin_order_buyer_name', $buyer, $order); $shipping_address = $order->get_address('shipping'); if (empty($shipping_address['country'])) { $shipping_address = $order->get_address(); } $formatted_address = WC()->countries->get_formatted_address($shipping_address, ', '); $shipping_to_country = $this->AliexpressHelper ->convertToAliexpressCountryCode( $this->OrderShippingDataService->resolveShippingCountry($order) ); $order_data = [ 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'order' => $order, 'buyer' => $buyer, 'currency' => $order->get_currency(), 'shiping_to_country' => $shipping_to_country, 'shipping_address' => $shipping_address, 'formatted_address' => $formatted_address, 'total_cost' => 0, 'items' => [], ]; foreach ($order->get_items() as $item) { /** * todo: here can be a case when product is already deleted in Woocommerce * in this case the order item can be retrieved. */ $a2wl_order_item = new WooCommerceOrderItem($item); if (!$a2wl_order_item->get_external_product_id()) { continue; } $WC_Product = $item->get_product(); $image = $WC_Product->get_image(); $product_id = $item->get_product_id(); $variation_id = $item->get_variation_id(); $quantity = $item->get_quantity(); $countryFromCode = $this->WoocommerceService->getShippingFromByProduct($WC_Product); try { $importedProduct = $this->WoocommerceService ->updateProductShippingItems($WC_Product, $shipping_to_country, $countryFromCode, $quantity); } catch (RepositoryException | ServiceException $Exception) { $errorMessage = sprintf( 'OrderFulfillmentService::getFulfillmentOrderData: %s order id: %d', $Exception->getMessage(), $order->get_id() ); a2wl_error_log($errorMessage); $importedProduct = $this->WoocommerceService->getProductWithVariations($product_id); } $shippingItems = $this->ProductService->getShippingItems( $importedProduct, $shipping_to_country, $countryFromCode ); $ShippingItemDto = $this->ProductService->findDefaultFromShippingItems( $shippingItems, $importedProduct ); $current_shipping_company = ''; $current_delivery_time = '-'; $current_shipping_cost = ''; if ($ShippingItemDto->getMethodName()) { $current_shipping_company = $ShippingItemDto->getMethodName(); $current_shipping_cost = $ShippingItemDto->getCost(); $current_delivery_time = $ShippingItemDto->getDays(); } /* $shipping_meta_data = $item->get_meta(Shipping::get_order_item_shipping_meta_key()); if ($shipping_meta_data) { $shipping_meta_data = json_decode($shipping_meta_data, true); $current_shipping_company = $shipping_meta_data['service_name']; $current_delivery_time = $shipping_meta_data['delivery_time']; $current_shipping_cost = $shipping_meta_data['shipping_cost']; } $current_shipping_company = $current_shipping_company ?: $ShippingItemDto->getMethodName();*/ $wpml_product_id = $wpml_variation_id = ''; if ($is_wpml) { $wpml_object_id = apply_filters( 'wpml_object_id', $product_id, 'product', false, $sitepress->get_default_language() ); if ($wpml_object_id != $product_id) { $wpml_product = wc_get_product($wpml_object_id); if ($wpml_product) { $wpml_product_id = $wpml_object_id; } } if ($product_id) { $wpml_object_id = apply_filters( 'wpml_object_id', $product_id, 'product', false, $sitepress->get_default_language() ); if ($wpml_object_id != $product_id) { $wpml_variation = wc_get_product($wpml_object_id); if ($wpml_variation) { $wpml_variation_id = $wpml_object_id; } } } } if ($wpml_product_id) { $aliexpress_product_id = get_post_meta($wpml_product_id, '_a2w_external_id', true); $item_original_url = get_post_meta($wpml_product_id, '_a2w_original_product_url', true); } else { $aliexpress_product_id = get_post_meta($product_id, '_a2w_external_id', true); $item_original_url = get_post_meta($product_id, '_a2w_original_product_url', true); } $aliexpress_price = $this->get_aliexpress_price($item, $is_wpml); $attributes = []; if ($meta_data = $item->get_formatted_meta_data('')) { foreach ($meta_data as $meta_id => $meta) { $shouldSkip = !str_starts_with($meta->key, "pa_"); if ($shouldSkip) { continue; } $attributes[] = force_balance_tags($meta->display_value); } } $total_cost = floatval($aliexpress_price) * $item->get_quantity(); if (intval($current_shipping_cost) > 0) { $total_cost += intval($current_shipping_cost); } $order_data['items'][] = [ 'order_item_id' => $item->get_id(), 'product_id' => $item->get_product_id(), 'variation_id' => $item->get_product()->get_id(), 'image' => $image, 'name' => $item->get_name(), 'url' => $item_original_url, 'sku' => $WC_Product->get_sku(), 'attributes' => implode(' / ', $attributes), 'cost' => floatval($aliexpress_price), 'quantity' => $item->get_quantity(), 'shipping_items' => $shippingItems, 'current_shipping' => $current_shipping_company, 'current_delivery_time' => $current_delivery_time, 'current_shipping_cost' => $current_shipping_cost, 'total_cost' => $total_cost, ]; $order_data['total_cost'] += $total_cost; } if ($order_data['items']) { $orders_data[] = $order_data; } } foreach ($orders_data as &$order_data) { $urls = array_column($order_data['items'], 'url'); $order_data['sign_urls'] = $this->get_sign_urls($urls); } return $orders_data; } /** * @param WC_Order $order * @param array|OrderItemShippingDto[] $order_items * @param string $shipping_to_country * @param bool $is_wpml * @return UpdateFulfillmentShippingResult */ public function updateFulfillmentShipping( WC_Order $order, array $order_items, string $shipping_to_country, bool $is_wpml = false ): UpdateFulfillmentShippingResult { $result_items = []; $total_order_price = 0; foreach ($order->get_items() as $item) { $OrderItemShippingDto = $this->getOrderItemById($item->get_id(), $order_items); if ($OrderItemShippingDto) { $aliexpress_price = $this->get_aliexpress_price($item, $is_wpml); $WC_Product = $item->get_product(); $product_id = $item->get_product_id(); $quantity = $item->get_quantity(); $countryFromCode = $this->WoocommerceService->getShippingFromByProduct($WC_Product); try { $importedProduct = $this->WoocommerceService ->updateProductShippingItems($WC_Product, $shipping_to_country, $countryFromCode, $quantity); $shippingItems = $this->ProductService->getShippingItems( $importedProduct, $shipping_to_country, $countryFromCode ); } catch (RepositoryException | ServiceException $Exception) { a2wl_error_log($Exception->getMessage()); $shippingItems = []; } $shipping_meta_data = $item->get_meta(Shipping::get_order_item_shipping_meta_key()); $shipping_meta_data = $shipping_meta_data ? json_decode($shipping_meta_data, true) : [ 'company' => '', 'service_name' => '', 'delivery_time' => '', 'shipping_cost' => '', 'quantity' => $item->get_quantity(), 'cost_added' => true ]; $current_shipping_cost = 0; foreach ($shippingItems as $shippingItem) { if ($shippingItem['serviceName'] == $OrderItemShippingDto->getShippingCode()) { $current_shipping_cost = $shippingItem['freightAmount']['value']; $shipping_meta_data['company'] = $shippingItem['company']; $shipping_meta_data['service_name'] = $shippingItem['serviceName']; $shipping_meta_data['shipping_cost'] = $shippingItem['freightAmount']['value']; $shipping_meta_data['delivery_time'] = $shippingItem['time']; $result_items[] = [ 'order_item_id' => $item->get_id(), 'shiping_time' => $shippingItem['time'] . ' days', 'shiping_price' => wc_price( $shippingItem['freightAmount']['value'], ['currency' => $order->get_currency()] ), 'total_item_price' => wc_price( $aliexpress_price * $item->get_quantity() + $shippingItem['freightAmount']['value'], ['currency' => $order->get_currency()] ), ]; } } $item->update_meta_data( Shipping::get_order_item_shipping_meta_key(), wp_json_encode($shipping_meta_data) ); $item->save_meta_data(); $total_order_price += $aliexpress_price * $item->get_quantity() + $current_shipping_cost; } } return new UpdateFulfillmentShippingResult($total_order_price, $result_items); } private function get_aliexpress_price($order_item, $is_wpml = false) { $product_id = $order_item->get_product_id(); $variation_id = $order_item->get_variation_id(); $wpml_product_id = $wpml_variation_id = ''; if ($is_wpml) { global $sitepress; $wpml_object_id = apply_filters( 'wpml_object_id', $product_id, 'product', false, $sitepress->get_default_language() ); if ($wpml_object_id != $product_id) { $wpml_product = wc_get_product($wpml_object_id); if ($wpml_product) { $wpml_product_id = $wpml_object_id; } } if ($product_id) { $wpml_object_id = apply_filters( 'wpml_object_id', $product_id, 'product', false, $sitepress->get_default_language() ); if ($wpml_object_id != $product_id) { $wpml_variation = wc_get_product($wpml_object_id); if ($wpml_variation) { $wpml_variation_id = $wpml_object_id; } } } } if ($wpml_variation_id) { $aliexpress_price = get_post_meta($wpml_product_id, '_aliexpress_price', true); } elseif ($variation_id) { $aliexpress_price = get_post_meta($variation_id, '_aliexpress_price', true); } elseif ($wpml_product_id) { $aliexpress_price = get_post_meta($wpml_product_id, '_aliexpress_price', true); } else { $aliexpress_price = get_post_meta($product_id, '_aliexpress_price', true); } return $aliexpress_price; } private function get_sign_urls($urls): array { if (a2wl_check_defined('A2WL_DEMO_MODE')) { return []; } $payload = [ "urls" => $urls, ]; $args = []; $request_url = RequestHelper::build_request('sign_urls'); $request = a2wl_remote_post($request_url, $payload, $args); if (is_wp_error($request)) { $result = ResultBuilder::buildError($request->get_error_message()); } else { if (intval($request['response']['code']) == 200) { $result = json_decode($request['body'], true); } else { $result = ResultBuilder::buildError($request['response']['code'] . ' - ' . $request['response']['message']); } } if ($result['state'] == 'error') { $result = []; } else { $result = $result['urls']; } return $result; } /** * @param int $orderItemId * @param array|OrderItemShippingDto[] $order_items * @return null|OrderItemShippingDto */ private function getOrderItemById(int $orderItemId, array $order_items): ?OrderItemShippingDto { /** * @var OrderItemShippingDto $orderItemShipping */ foreach ($order_items as $orderItemShipping) { if ($orderItemShipping->getOrderItemID() == $orderItemId) { return $orderItemShipping; } } return null; } private function getWpmlProductData($product_id, bool $isWpml = false): array { global $sitepress; $result = [ 'wpml_product_id' => '', 'wpml_variation_id' => '', 'aliexpress_product_id' => get_post_meta($product_id, '_a2w_external_id', true), 'item_original_url' => get_post_meta($product_id, '_a2w_original_product_url', true) ]; if ($isWpml) { $wpml_object_id = apply_filters('wpml_object_id', $product_id, 'product', false, $sitepress->get_default_language()); if ($wpml_object_id != $product_id) { $wpml_product = wc_get_product($wpml_object_id); if ($wpml_product) { $result['wpml_product_id'] = $wpml_object_id; } } if ($product_id) { $wpml_object_id = apply_filters('wpml_object_id', $product_id, 'product', false, $sitepress->get_default_language()); if ($wpml_object_id != $product_id) { $wpml_variation = wc_get_product($wpml_object_id); if ($wpml_variation) { $result['wpml_variation_id'] = $wpml_object_id; } } } $wpml_product_id = $result['wpml_product_id']; if ($wpml_product_id) { $result['aliexpress_product_id'] = get_post_meta($wpml_product_id, '_a2w_external_id', true); $result['item_original_url'] = get_post_meta($wpml_product_id, '_a2w_original_product_url', true); } } return $result; } private function getProductAttributes(WC_Order_Item_Product $WC_Order_Item_Product): array { $attributes = []; if ($meta_data = $WC_Order_Item_Product->get_formatted_meta_data('')) { foreach ($meta_data as $meta_id => $meta) { $shouldSkip = !str_starts_with($meta->key, "pa_"); if ($shouldSkip) { continue; } $attributes[] = force_balance_tags($meta->display_value); } } return $attributes; } private function getFormattedOrderItemAttributes(ExternalOrderItem $ExternalOrderItem) : array { $attributes = []; $Attributes = $ExternalOrderItem->getAttributes(); foreach($Attributes as $ExternalOrderItemAttribute) { $attributes[] = sprintf('%s: "%s"', $ExternalOrderItemAttribute->getName(), $ExternalOrderItemAttribute->getValue() ); } return $attributes; } }