$postId, 'l_name' => $postName, 'warehouseRemark' => '' ]; $rt = $this->post('open/express/register/upload', $postList); $this->orderPush($oid, 'WAIT_BUYER_CONFIRM_GOODS', '', [], [ 'l_id' => $postId, 'l_name' => $postName, 'warehouseRemark' => '' ]); return $rt; } /** * 推送订单到聚水潭(含支付/发货/退款等状态同步) * @param int $oid * @param string $status * @param string $rftype * @param array $rfinfo * @param array $extpm * @return bool */ public function orderPush(int $oid, string $status = 'WAIT_SELLER_SEND_GOODS', $rftype = '', $rfinfo = [], $extpm = []): bool { Log::info('jst.order_push.start ' . $oid . ' ' . $status); /** @var StoreOrderServices $orderServices */ $orderServices = app()->make(StoreOrderServices::class); $order = $orderServices->get($oid, ['*'], ['store']); if (!$order || $order['id'] < 1) { throw new AdminException('订单信息不能为空'); } if ($order['product_type'] != 4) { if ($order['product_type'] > 0 || !$order['paid']) { return true; } } $rid = $order['supplier_id'] ?? 0; $shopid = (int)$this->getShopId(); if ($rid) { /** @var SystemSupplierServices $systemSupplierServices */ $systemSupplierServices = app()->make(SystemSupplierServices::class); $info = $systemSupplierServices->getSupplierInfo((int)$rid, 'erp_shopid'); if (!$info || !$info['erp_shopid']) return true; $shopid = (int)$info['erp_shopid']; if (!$shopid) return true; } $items = $this->getItems($oid, (int)$order['uid'], $order['unique'], $rftype); if (isset($extpm['l_id'])) { $order['delivery_id'] = $extpm['l_id']; $order['delivery_name'] = $extpm['l_name']; } $biz = [ 'shop_id' => $shopid, 'so_id' => $order['order_id'], 'shop_status' => $status, 'buyer_message' => $order['mark'], 'shop_buyer_id' => (string)$order['uid'], 'receiver_name' => $order['real_name'], 'receiver_mobile' => $order['user_phone'], 'pay_amount' => (float)$order['pay_price'], 'freight' => (float)$order['freight_price'], 'order_date' => date('Y-m-d H:i:s', $order['add_time']), 'shop_modified' => date('Y-m-d H:i:s', $order['add_time']), 'items' => $items, 'l_id' => $order['delivery_id'] ?? '', 'logistics_company' => $order['delivery_name'] ?? '', 'pay' => [], ]; if ($rfinfo) { $biz['pay'] = [ 'outer_pay_id' => $rfinfo['order_id'] ?? $order['order_id'], 'pay_date' => date('Y-m-d H:i:s'), 'payment' => $order['pay_type'], 'seller_account' => 'seller', 'buyer_account' => 'buyer' . $order['uid'], 'amount' => 0 - (float)($rfinfo['refunded_price'] ?? 0) ]; $q = [ 'shop_id' => $shopid, 'so_ids' => [$order['order_id']] ]; $resultb = $this->post('open/orders/single/query', $q)['data']; $biz['shop_status'] = $resultb['orders'][0]['shop_status'] ?? $status; } else { $biz['pay'] = [ 'outer_pay_id' => $order['order_id'], 'pay_date' => date('Y-m-d H:i:s', $order['pay_time']), 'payment' => $order['pay_type'], 'seller_account' => 'seller', 'buyer_account' => 'buyer' . $order['uid'], 'amount' => (float)$order['pay_price'] ]; } $addr = $this->getAddress($order['user_address']); $biz = array_merge($biz, $addr); if (isset($biz['l_id']) && $biz['l_id'] === '') { unset($biz['l_id']); } if (isset($biz['logistics_company']) && $biz['logistics_company'] === '') { unset($biz['logistics_company']); } if (isset($biz['receiver_zip']) && $biz['receiver_zip'] === '') { unset($biz['receiver_zip']); } if (isset($biz['items']) && is_array($biz['items'])) { foreach ($biz['items'] as $k => $item) { if (is_array($item) && isset($item['pic']) && $item['pic'] === '') { unset($item['pic']); $biz['items'][$k] = $item; } } } Log::info('jst.orders_upload.request ' . json_encode([ 'api' => 'open/jushuitan/orders/upload', 'oid' => $oid, 'shop_status' => $status, 'biz' => $biz, ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); $num = 3; for ($i = $num; $i >= 0; $i--) { if ($i <= 0) { Log::error('ERP订单上传失败 ' . json_encode([ 'api' => 'open/jushuitan/orders/upload', 'shop_id' => $shopid, 'so_id' => (string)($biz['so_id'] ?? ''), ], JSON_UNESCAPED_UNICODE)); return false; } try { $resp = $this->post('open/jushuitan/orders/upload', [$biz]); $result = $resp['data'] ?? []; if (!empty($result['datas'][0]['issuccess']) && $order['erp_order_id'] != $biz['so_id']) { $order->save(['erp_id' => $result['datas'][0]['o_id'], 'erp_order_id' => $biz['so_id']]); } break; } catch (\Throwable $e) { usleep(1000 * 50); Log::error('ERP订单上传失败:' . $e->getMessage() . ' ' . json_encode([ 'try' => ($num - $i + 1), 'api' => 'open/jushuitan/orders/upload', 'shop_id' => $shopid, 'so_id' => (string)($biz['so_id'] ?? ''), ], JSON_UNESCAPED_UNICODE)); } } return true; } /** * 售后单创建推送(本地 -> 聚水潭) * @param int $refundId * @return bool */ public function afterSaleCreatePush(int $refundId): bool { $api = 'open/aftersale/upload'; Log::info('jst.after_sale.create.start ' . json_encode(['refund_id' => $refundId], JSON_UNESCAPED_UNICODE)); /** @var StoreOrderRefundServices $storeOrderRefundServices */ $storeOrderRefundServices = app()->make(StoreOrderRefundServices::class); $refund = $storeOrderRefundServices->get($refundId); if (!$refund) { Log::warning('jst.after_sale.create.skip ' . json_encode(['refund_id' => $refundId, 'reason' => 'refund_missing'], JSON_UNESCAPED_UNICODE)); return true; } if (method_exists($refund, 'toArray')) { $refund = $refund->toArray(); } /** @var StoreOrderServices $storeOrderServices */ $storeOrderServices = app()->make(StoreOrderServices::class); $order = $storeOrderServices->get((int)($refund['store_order_id'] ?? 0), ['*'], ['store']); if (!$order) { Log::warning('jst.after_sale.create.skip ' . json_encode(['refund_id' => $refundId, 'reason' => 'order_missing'], JSON_UNESCAPED_UNICODE)); return true; } if (($order['product_type'] ?? 0) != 4) { if (($order['product_type'] ?? 0) > 0 || !($order['paid'] ?? 0)) { Log::info('jst.after_sale.create.skip ' . json_encode([ 'refund_id' => $refundId, 'reason' => 'product_filter', 'product_type' => $order['product_type'] ?? null, 'paid' => $order['paid'] ?? null, ], JSON_UNESCAPED_UNICODE)); return true; } } $shopid = $this->resolveShopIdByOrder($order); if (!$shopid) { Log::info('jst.after_sale.create.skip ' . json_encode([ 'refund_id' => $refundId, 'reason' => 'missing_shopid', 'supplier_id' => $order['supplier_id'] ?? 0 ], JSON_UNESCAPED_UNICODE)); return true; } $outerAsId = (string)($refund['order_id'] ?? ''); if ($outerAsId === '') { $outerAsId = (string)$refundId; } $items = $this->buildAfterSaleItemsFromRefund($refund); $applyType = (int)($refund['apply_type'] ?? $refund['refund_type'] ?? 0); if ($applyType == 1) { $typeStr = '仅退款'; $goodStatus = 'BUYER_NOT_RECEIVED'; } else { $typeStr = '普通退货'; $goodStatus = 'BUYER_RETURNED_GOODS'; } if ($applyType == 1) { $items = []; } elseif (is_array($items)) { foreach ($items as $idx => $it) { if (is_array($it)) { $it['type'] = '退货'; $items[$idx] = $it; } } } $biz = [ 'shop_id' => $shopid, 'so_id' => (string)($order['order_id'] ?? ''), 'outer_as_id' => $outerAsId, 'type' => $typeStr, 'good_status' => $goodStatus, 'shop_status' => 'wait', 'total_amount' => (float)($order['pay_price'] ?? 0), 'payment' => 0.00, 'question_type' => (string)($refund['refund_reason'] ?? $refund['refund_explain'] ?? ''), 'refund' => (float)($refund['refund_price'] ?? $refund['apply_price'] ?? 0), 'remark' => (string)($refund['remark'] ?? ''), 'items' => $items, ]; $this->retryPost($api, [$biz], 'jst.after_sale.create'); return true; } /** * 售后单撤销推送(本地 -> 聚水潭) * @param int $refundId * @return bool */ public function afterSaleCancelPush(int $refundId): bool { $api = 'open/webapi/aftersaleapi/open/cancel'; Log::info('jst.after_sale.cancel.start ' . json_encode(['refund_id' => $refundId], JSON_UNESCAPED_UNICODE)); /** @var StoreOrderRefundServices $storeOrderRefundServices */ $storeOrderRefundServices = app()->make(StoreOrderRefundServices::class); $refund = $storeOrderRefundServices->get($refundId); if (!$refund) { Log::warning('jst.after_sale.cancel.skip ' . json_encode(['refund_id' => $refundId, 'reason' => 'refund_missing'], JSON_UNESCAPED_UNICODE)); return true; } if (method_exists($refund, 'toArray')) { $refund = $refund->toArray(); } /** @var StoreOrderServices $storeOrderServices */ $storeOrderServices = app()->make(StoreOrderServices::class); $order = $storeOrderServices->get((int)($refund['store_order_id'] ?? 0), ['*'], ['store']); if (!$order) { Log::warning('jst.after_sale.cancel.skip ' . json_encode(['refund_id' => $refundId, 'reason' => 'order_missing'], JSON_UNESCAPED_UNICODE)); return true; } if (($order['product_type'] ?? 0) != 4) { if (($order['product_type'] ?? 0) > 0 || !($order['paid'] ?? 0)) { Log::info('jst.after_sale.cancel.skip ' . json_encode([ 'refund_id' => $refundId, 'reason' => 'product_filter', 'product_type' => $order['product_type'] ?? null, 'paid' => $order['paid'] ?? null, ], JSON_UNESCAPED_UNICODE)); return true; } } $shopid = $this->resolveShopIdByOrder($order); if (!$shopid) { Log::info('jst.after_sale.cancel.skip ' . json_encode([ 'refund_id' => $refundId, 'reason' => 'missing_shopid', 'supplier_id' => $order['supplier_id'] ?? 0 ], JSON_UNESCAPED_UNICODE)); return true; } $outerAsId = (string)($refund['order_id'] ?? ''); if ($outerAsId === '') { $outerAsId = (string)$refundId; } $erpInfo = []; if (!empty($refund['erp'])) { $erpInfo = json_decode($refund['erp'], true) ?: []; } $asId = $erpInfo['as_id'] ?? 0; if ($asId) { $biz = [ 'as_ids' => [(int)$asId], ]; } else { $biz = [ 'shop_id' => $shopid, 'so_id' => (string)($order['order_id'] ?? ''), 'outer_as_id' => $outerAsId, 'reason' => (string)($refund['refuse_reason'] ?? $refund['refund_reason'] ?? ''), ]; } $this->retryPost($api, $biz, 'jst.after_sale.cancel'); return true; } /** * 售后单确认退款推送(本地 -> 聚水潭) * @param int $refundId * @return bool */ public function afterSaleRefundedPush(int $refundId): bool { $api = 'open/webapi/aftersaleapi/open/confirm'; Log::info('jst.after_sale.refunded.start ' . json_encode(['refund_id' => $refundId], JSON_UNESCAPED_UNICODE)); /** @var StoreOrderRefundServices $storeOrderRefundServices */ $storeOrderRefundServices = app()->make(StoreOrderRefundServices::class); $refund = $storeOrderRefundServices->get($refundId); if (!$refund) { Log::warning('jst.after_sale.refunded.skip ' . json_encode(['refund_id' => $refundId, 'reason' => 'refund_missing'], JSON_UNESCAPED_UNICODE)); return true; } if (method_exists($refund, 'toArray')) { $refund = $refund->toArray(); } /** @var StoreOrderServices $storeOrderServices */ $storeOrderServices = app()->make(StoreOrderServices::class); $order = $storeOrderServices->get((int)($refund['store_order_id'] ?? 0), ['*'], ['store']); if (!$order) { Log::warning('jst.after_sale.refunded.skip ' . json_encode(['refund_id' => $refundId, 'reason' => 'order_missing'], JSON_UNESCAPED_UNICODE)); return true; } if (($order['product_type'] ?? 0) != 4) { if (($order['product_type'] ?? 0) > 0 || !($order['paid'] ?? 0)) { Log::info('jst.after_sale.refunded.skip ' . json_encode([ 'refund_id' => $refundId, 'reason' => 'product_filter', 'product_type' => $order['product_type'] ?? null, 'paid' => $order['paid'] ?? null, ], JSON_UNESCAPED_UNICODE)); return true; } } $shopid = $this->resolveShopIdByOrder($order); if (!$shopid) { Log::info('jst.after_sale.refunded.skip ' . json_encode([ 'refund_id' => $refundId, 'reason' => 'missing_shopid', 'supplier_id' => $order['supplier_id'] ?? 0 ], JSON_UNESCAPED_UNICODE)); return true; } $outerAsId = (string)($refund['order_id'] ?? ''); if ($outerAsId === '') { $outerAsId = (string)$refundId; } $erpInfo = []; if (!empty($refund['erp'])) { $erpInfo = json_decode($refund['erp'], true) ?: []; } $asId = $erpInfo['as_id'] ?? 0; if ($asId) { $biz = [ 'as_ids' => [(int)$asId], 'exchange_force' => true, 'confirm_refund' => true, ]; } else { $biz = [ 'shop_id' => $shopid, 'so_id' => (string)($order['order_id'] ?? ''), 'outer_as_id' => $outerAsId, 'amount' => sprintf('%.2f', (float)($refund['refund_price'] ?? $refund['apply_price'] ?? 0)), ]; } $this->retryPost($api, $biz, 'jst.after_sale.refunded'); return true; } public function getItems(int $oid, int $uid, string $unique, $rftype = ''): array { /** @var StoreOrderCartInfoServices $storeOrderCartInfoServices */ $storeOrderCartInfoServices = app()->make(StoreOrderCartInfoServices::class); $cartInfo = $storeOrderCartInfoServices->getOrderCartInfo($oid); if (empty($cartInfo)) { /** @var StoreOrderServices $orderServices */ $orderServices = app()->make(StoreOrderServices::class); $orderInfo = $orderServices->getCacheOrderInfo($uid, $unique); $cartInfo = $orderInfo['cartInfo'] ?? []; } $items = []; foreach ($cartInfo as $cart) { $cart = $cart['cart_info'] ?? $cart; $attrInfo = $cart['productInfo']['attrInfo']; $truePrice = (string)($cart['sum_true_price'] ?? $cart['truePrice']); $itemdet = [ 'sku_id' => $attrInfo['code'] ?: ($attrInfo['unique'] . 'ok'), 'shop_sku_id' => $attrInfo['code'] ?: ($attrInfo['unique'] . 'ok'), 'base_price' => (float)($attrInfo['price'] ?? 0), 'price' => (float)bcdiv($truePrice, (string)$cart['cart_num'], 2), 'amount' => (float)$truePrice, 'qty' => $cart['cart_num'], 'pic' => $cart['productInfo']['image'], 'name' => $cart['productInfo']['store_name'], 'properties_value' => $attrInfo['suk'], 'outer_oi_id' => $cart['product_attr_unique'], 'refund_qty' => $rftype == 'refund_nosend' ? $cart['cart_num'] : ($cart['refund_num'] ?? 0), ]; if ($itemdet['qty'] == $itemdet['refund_qty']) { $itemdet['refund_status'] = 'success'; } $items[] = $itemdet; } return $items; } private function resolveShopIdByOrder($order): int { $rid = $order['supplier_id'] ?? 0; $shopid = (int)$this->getShopId(); if ($rid) { /** @var SystemSupplierServices $systemSupplierServices */ $systemSupplierServices = app()->make(SystemSupplierServices::class); $info = $systemSupplierServices->getSupplierInfo((int)$rid, 'erp_shopid'); if (!$info || !$info['erp_shopid']) { return 0; } $shopid = (int)$info['erp_shopid']; } return (int)$shopid; } private function buildAfterSaleItemsFromRefund(array $refund): array { $cartInfo = $refund['cart_info'] ?? []; if (is_string($cartInfo)) { $decoded = json_decode($cartInfo, true); if (is_array($decoded)) { $cartInfo = $decoded; } } if (!is_array($cartInfo)) { $cartInfo = []; } $items = []; foreach ($cartInfo as $cart) { $cart = $cart['cart_info'] ?? $cart; $productInfo = $cart['productInfo'] ?? []; $attrInfo = $productInfo['attrInfo'] ?? []; $skuId = (string)($attrInfo['code'] ?? ''); if ($skuId === '') { $skuId = (string)($attrInfo['unique'] ?? ''); if ($skuId !== '') { $skuId .= 'ok'; } } $items[] = [ 'sku_id' => $skuId, 'qty' => (int)($cart['cart_num'] ?? 0), 'price' => sprintf('%.2f', (float)($attrInfo['price'] ?? 0)), 'amount' => sprintf('%.2f', (float)($cart['sum_true_price'] ?? 0)), 'outer_oi_id' => (string)($cart['product_attr_unique'] ?? ''), 'name' => (string)($productInfo['store_name'] ?? ''), ]; } return $items; } private function retryPost(string $api, array $biz, string $logPrefix): void { $meta = $this->extractBizMeta($biz); $num = 3; for ($i = $num; $i >= 0; $i--) { if ($i <= 0) { Log::error($logPrefix . '.failed ' . json_encode(array_merge([ 'api' => $api, ], $meta), JSON_UNESCAPED_UNICODE)); return; } try { $rt = $this->post($api, $biz); return; } catch (\Throwable $e) { usleep(1000 * 50); Log::error($logPrefix . '.error ' . $e->getMessage() . ' ' . json_encode(array_merge([ 'try' => ($num - $i + 1), 'api' => $api, ], $meta), JSON_UNESCAPED_UNICODE)); } } } private function extractBizMeta(array $biz): array { $first = $biz; if ($this->isListArray($biz) && isset($biz[0]) && is_array($biz[0])) { $first = $biz[0]; } if (!is_array($first)) { return []; } $meta = []; foreach (['shop_id', 'so_id', 'outer_as_id', 'as_ids'] as $k) { if (array_key_exists($k, $first)) { $meta[$k] = $first[$k]; } } return $meta; } private function isListArray(array $arr): bool { if ($arr === []) { return true; } return array_keys($arr) === range(0, count($arr) - 1); } private function getAddress($address): array { if (is_string($address)) { $decoded = json_decode($address, true); if (is_array($decoded)) { $address = $decoded; } else { $parts = preg_split('/\s+/u', trim($address)); if (is_array($parts) && count($parts) >= 3) { $address = [ 'province' => $parts[0] ?? '', 'city' => $parts[1] ?? '', 'area' => $parts[2] ?? '', 'detail' => trim(implode(' ', array_slice($parts, 3))), ]; if (($address['detail'] ?? '') === '') { $address['detail'] = $parts[2] ?? ''; } } else { $address = ['detail' => $address]; } } } if (!is_array($address)) { $address = []; } return [ 'receiver_address' => $address['detail'] ?? '', 'receiver_state' => $address['province'] ?? '', 'receiver_city' => $address['city'] ?? '', 'receiver_district' => $address['area'] ?? '', 'receiver_zip' => $address['post_code'] ?? '', ]; } public static function getServices(): HaichaoJstServices { return new HaichaoJstServices(); } public function getProductListShop($key = ''): array { $time = 1; $data = $this->post('open/skumap/query', [ 'modified_begin' => date('Y-m-d H:i', (time() - (86400 * $time))), 'modified_end' => date('Y-m-d H:i', time() - (86400 * $time) + 7 * 86400), 'page_index' => 1, 'page_size' => 50, 'shop_id' => $key ])['data']; return $data; } public function getProductListName($key = ''): array { $data = $this->post('open/sku/query', [ 'exactly_name' => $key, 'page_index' => 1, 'page_size' => 10, ])['data']; return $data; } public function syncProductSingle($data, $pid = 0) { $jstProductSync = app()->make(\app\haichao\sync\JstProductSync::class); return $jstProductSync->syncProductSingle($data, $pid); } public function getProductListSku($key = ''): array { $data = $this->post('open/sku/query', [ 'sku_ids' => $key, 'page_index' => 1, 'page_size' => 10, ])['data']; return $data; } public function getProductListKuan($key = ''): array { $data = $this->post('open/mall/item/query', [ 'i_ids' => [$key], 'page_index' => 1, 'page_size' => 10, 'date_field' => '', ])['data']; return $data; } /** * 按时间范围获取聚水潭商品列表 * @param string $startTime 开始时间 Y-m-d H:i:s * @param string $endTime 结束时间 Y-m-d H:i:s * @param int $pageIndex 页码 * @param int $pageSize 每页数量 * @return array */ public function getProductListByTime(string $startTime, string $endTime, int $pageIndex = 1, int $pageSize = 50): array { $data = $this->post('open/mall/item/query', [ 'modified_begin' => $startTime, 'modified_end' => $endTime, 'page_index' => $pageIndex, 'page_size' => $pageSize, 'date_field' => '', ])['data']; return $data; } public function getProductListStand(): array { $time = 10; $data = $this->post('open/mall/item/query', [ 'modified_begin' => date('Y-m-d H:i', (time() - (86400 * $time))), 'modified_end' => date('Y-m-d H:i', time() - (86400 * $time) + 7 * 86400), 'i_ids' => [], 'page_index' => 1, 'page_size' => 50, 'date_field' => '', ])['data']; return $data; } public function getProductList(): array { $time = 1; if (file_exists(root_path() . 'runtime/jstdata/synctime.txt')) { $time = file_get_contents(root_path() . 'runtime/jstdata/synctime.txt'); } $syncint = 0; if (file_exists(root_path() . 'runtime/jstdata/syncint.txt')) { $syncint = file_get_contents(root_path() . 'runtime/jstdata/syncint.txt'); } $syncint++; // 这里的 $syncint 实际上代表要拉取的页码(page_index) $data = $this->post('open/mall/item/query', [ 'modified_begin' => date('Y-m-d H:i', (time() - (86400 * $time))), 'modified_end' => date('Y-m-d H:i', time() - (86400 * $time) + 7 * 86400), 'i_ids' => [], 'page_index' => $syncint, // 将写死的 1 改为动态的页码变量 'page_size' => 10, 'date_field' => '', ])['data']; if ($syncint > $data['page_count']) { $syncint = 1; $time += 7; if ($time > 500) { $time = 1; } } if (!is_dir(root_path() . 'runtime/jstdata')) { mkdir(root_path() . 'runtime/jstdata', 0777, true); } file_put_contents(root_path() . 'runtime/jstdata/syncint.txt', $syncint); file_put_contents(root_path() . 'runtime/jstdata/synctime.txt', $time); return $data; } public function uploadItemSku(array $items): array { return $this->post('open/jushuitan/itemsku/upload', [ 'items' => $items, ]); } public function uploadItemSkuByProductIds(array $productIds): array { $productIds = array_values(array_unique(array_map('intval', $productIds))); if (!$productIds) { throw new ValidateException('请选择商品'); } $products = \app\model\product\product\StoreProduct::whereIn('id', $productIds) ->where('is_del', 0) ->with(['attrValue']) ->select() ->toArray(); $items = []; $errors = []; foreach ($products as $product) { $iId = trim((string)($product['code'] ?? '')); $productId = (int)($product['id'] ?? 0); if (!$iId) { $errors[] = [ 'product_id' => $productId, 'msg' => '商品编码(code)为空', ]; continue; } $skuList = $product['attr_value'] ?? ($product['attrValue'] ?? []); if (!is_array($skuList) || !$skuList) { $errors[] = [ 'product_id' => $productId, 'i_id' => $iId, 'msg' => '商品规格为空', ]; continue; } $productImage = (string)($product['image'] ?? ''); $productName = (string)($product['store_name'] ?? ''); $enabled = ((int)($product['is_show'] ?? 0) === 1) ? 1 : -1; foreach ($skuList as $sku) { $skuId = trim((string)($sku['code'] ?? '')); if (!$skuId) { $errors[] = [ 'product_id' => $productId, 'i_id' => $iId, 'msg' => '规格编码(code)为空', ]; continue; } $skuImage = (string)($sku['image'] ?? $productImage); $propertiesValue = (string)($sku['suk'] ?? ''); $propertiesValue = str_replace(',', ';', $propertiesValue); $items[] = [ 'i_id' => $iId, 'sku_id' => $skuId, 'name' => $productName, 'properties_value' => $propertiesValue, 's_price' => (float)($sku['price'] ?? ($product['price'] ?? 0)), 'market_price' => (float)($sku['ot_price'] ?? ($product['ot_price'] ?? 0)), 'c_price' => (float)($sku['cost'] ?? ($product['cost'] ?? 0)), 'pic' => $productImage, 'pic_big' => $productImage, 'sku_pic' => $skuImage, 'enabled' => $enabled, ]; } } if (!$items) { throw new ValidateException('没有可同步的商品规格'); } $rt = $this->uploadItemSku($items); return [ 'upload_count' => count($items), 'errors' => $errors, 'jst' => $rt, ]; } public function getStork(string $ids): array { return $this->post('open/inventory/query', [ 'page_index' => 1, 'page_size' => 100, 'sku_ids' => $ids, ]); } public function getInneropenItemList(): array { $return = []; $n = 1; if (file_exists(root_path() . 'runtime/jstdata/syncintgood.txt')) { $n = file_get_contents(root_path() . 'runtime/jstdata/syncintgood.txt'); } $data = $this->post('open/api/goods/inneropen/goods/querygoodslist', [ 'page_num' => $n, 'page_size' => 10, 'sort' => 'ASC' ])['data']; $result = $data['list']; $return = array_merge($result, $return); if (file_exists(root_path() . 'runtime/jstdata/syncintgood.txt')) { $n = file_get_contents(root_path() . 'runtime/jstdata/syncintgood.txt'); $n++; if ($n > ceil($data['total'] / 10)) { $n = 1; } } if (!is_dir(root_path() . 'runtime/jstdata')) { mkdir(root_path() . 'runtime/jstdata', 0777, true); } file_put_contents(root_path() . 'runtime/jstdata/syncintgood.txt', $n); return $return; } public function getInneropenItemDetail($skuId): array { return $this->post('open/api/goods/inneropen/goods/querygoodsdetail', [ 'item_spuId' => $skuId ])['data']; } public function findStockBySkuId($skuid = ''): array { $result = $this->post('open/inventory/query', [ 'page_num' => 1, 'page_size' => 500, 'sku_ids' => $skuid, ])['data']['inventorys']; return $result; } public function getInneropenStockAndDetailList(array|string $styleCodes, ?array &$stats = null): array { $rt = []; $codeList = is_array($styleCodes) ? $styleCodes : explode(',', trim($styleCodes, ", \t\n\r\0\x0B")); $codeList = array_values(array_filter(array_map('trim', $codeList), static fn($v) => $v !== '')); foreach (array_chunk($codeList, 100) as $chunkCodes) { if ($stats !== null) { $stats['chunk_count'] = (int)($stats['chunk_count'] ?? 0) + 1; $stats['request_sku_count'] = (int)($stats['request_sku_count'] ?? 0) + count($chunkCodes); } $i = 1; do { if ($stats !== null) { $stats['api_call_count'] = (int)($stats['api_call_count'] ?? 0) + 1; } $result = $this->post('open/inventory/query', [ 'page_index' => $i++, 'page_size' => 100, 'sku_ids' => implode(',', $chunkCodes) ])['data']['inventorys'] ?? []; if ($stats !== null) { $stats['api_resp_row_count'] = (int)($stats['api_resp_row_count'] ?? 0) + count($result); } $formatResult = []; foreach ($result as $item) { $formatResult[] = [ 'item_code' => $item['sku_id'], 'stock' => max(0, ($item['qty'] ?? 0) - ($item['order_lock'] ?? 0)) ]; } $rt = array_merge($formatResult, $rt); usleep(550000); } while (count($result) == 100); } return $rt; } public function findAllInneropenItemBySkuId(string $skuIds): array { return $this->getInneropenStockAndDetailList($skuIds); } public function getInneropenList(int $status = 2): array { $rt = $this->post('open/api/company/inneropen/partner/channel/querymysupplier', [ 'page_num' => 1, 'page_size' => 100, ])['data']['supplier_vos']; $rtr = []; foreach ($rt as $inneropen) { if ($inneropen['status'] == $status) { $rtr[] = $inneropen; } } return $rtr; } public function getSyncProduct(): \app\haichao\sync\JstProductSync { return new \app\haichao\sync\JstProductSync(); } public function getSyncStork(): \app\haichao\sync\JstStorkSync { return new \app\haichao\sync\JstStorkSync(); } }