$this->getCompany()->id, 'platform_id' => $this->getPlatform()->id, 'store_id' => $this->getStore()->id, 'order_status_id' => $this->getOrderStatusId($record['status']), 'platform_order_id' => $record['tid'], 'payment_method_id' => $this->getPaymentMethodId(), 'presale' => false, 'total_amount' => $record['total_fee'], 'total_paid' => $record['payment'], 'total_discount' => $record['discount_fee'], // 实际收到的金额,如果平台有商家补贴,此金额需要重新计算 - 部分退款订单也影响此字段的值 'total_received' => $record['received_payment'], 'freight_fee' => 0, 'tax_fee' => 0, 'discount_fee' => 0, 'commission_fee' => 0, 'coupon_amount' => 0, 'voucher_amount' => 0, 'order_type_id' => OrderType::Normor_Order->value, 'created_date' => $record['created'], 'updated_date' => $record['modified'] ?? null, 'paid_date' => $record['pay_time'] ?? null, 'shipping_date' => $record['consign_time'] ?? null, 'zipcode' => $record['receiver_zip'] ?? '', 'city' => $record['receiver_city'] ?? '', 'province' => $record['receiver_state'] ?? '', 'country' => 'CN', 'raw' => $raw, 'ext' => null, 'buyer_user_id' => $record['buyer_open_uid'], 'raw_hash' => \md5($raw), 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), ]; } }); } /** * 获取实体的唯一键字段(用于 upsert 的 uniqueBy 参数) * * 定义订单的唯一约束字段组合 * * @return array 唯一键字段名数组 */ public function getUniqueBy(): array { // 天猫订单的唯一性由店铺 + 平台订单号确定(实际上由平台订单号就已经足够) // @attention create_date 为数据库强制要求,必需携带 return ['store_id', 'platform_order_id', 'created_date']; } /** * 获取可更新的字段列表(用于 upsert 的 update 参数) * * 明确定义哪些字段在更新时可以被修改 * 排除:主键、唯一键、创建时间、关联 ID 等不应变更的字段 * * @return array 可更新字段名数组 */ public function getUpdateFields(): array { // 方案1:手动指定可更新字段(推荐,最明确) // 根据实际业务需求添加其他可更新字段 return [ 'company_id', 'platform_id', 'store_id', 'order_status_id', 'platform_order_id', 'payment_method_id', 'presale', 'total_amount', 'total_paid', 'total_discount', 'total_received', 'freight_fee', 'tax_fee', 'discount_fee', 'commission_fee', 'coupon_amount', 'voucher_amount', 'order_type_id', 'created_date', 'updated_date', 'paid_date', 'shipping_date', 'zipcode', 'city', 'province', 'country', 'raw', 'ext', 'buyer_user_id', 'raw_hash', 'updated_at', // 更新时刷新,created_at 不包含以保留原始创建时间 ]; // 方案2:动态计算(如果字段较多且经常变动) // $entity = $this->entityMatch($this->getData()); // $excludeFields = array_merge( // ['id', 'created_at', 'created_date', 'company_id', 'platform_id'], // $this->getUniqueBy() // ); // return $this->getTableColumnsExcept($entity, $excludeFields); } /** * 根据淘宝订单状态确定对应的 Tools 订单状态 * * @param string $platformOrderStatus 淘宝平台订单状态 * @return int Tools 订单状态 ID */ public function getOrderStatusId(string $platformOrderStatus): int { $statusMap = $this->orderStatusMap(); return $statusMap[$platformOrderStatus] ?? OrderStatus::PAYMENT_COMPLETE->value; } /** * 淘宝订单状态到 Tools 订单状态的映射 * * @return array */ private function orderStatusMap(): array { return [ // Payment pending (1) 'TRADE_NO_CREATE_PAY' => OrderStatus::PAYMENT_PENDING->value, // 没有创建支付宝交易 'WAIT_BUYER_PAY' => OrderStatus::PAYMENT_PENDING->value, // 等待买家付款 'PAY_PENDING' => OrderStatus::PAYMENT_PENDING->value, // 国际信用卡支付付款确认中 'WAIT_PRE_AUTH_CONFIRM' => OrderStatus::PAYMENT_PENDING->value, // 0元购合约中 // Payment fail (2) 'TRADE_CLOSED_BY_TAOBAO' => OrderStatus::PAYMENT_FAIL->value, // 付款以前,卖家或买家主动关闭交易 // Payment complete (3) 'SELLER_CONSIGNED_PART' => OrderStatus::PAYMENT_COMPLETE->value, // 卖家部分发货 'WAIT_SELLER_SEND_GOODS' => OrderStatus::PAYMENT_COMPLETE->value, // 等待卖家发货,即:买家已付款 // Awaiting shipment (4) 'PAID_FORBID_CONSIGN' => OrderStatus::AWAITING_SHIPMENT->value, // 拼团中订单或者发货强管控的订单,已付款但禁止发货 // Shipped (5) 'WAIT_BUYER_CONFIRM_GOODS' => OrderStatus::SHIPPED->value, // 等待买家确认收货,即:卖家已发货 'TRADE_BUYER_SIGNED' => OrderStatus::SHIPPED->value, // 买家已签收,货到付款专用 // Finished (8) 'TRADE_FINISHED' => OrderStatus::FINISHED->value, // 交易成功 // Cancel before shipping (9) 'TRADE_CLOSED' => OrderStatus::CANCEL_BEFORE_SHIPPING->value, // 付款以后用户退款成功,交易自动关闭 ]; } public function getPaymentMethodId() : int { // @attention 暂时固定返回支付方式为支付宝, 其他平台需要定义付款方式映射 return PaymentMethod::ALIPAY_CN->value; } /** * * orderItems 的输出结果为 \App\Model\OrderItem::fill() 可以直接使用的数据格式 * * @param array $rawData * @return array */ public function formatOrderItemsFromRaw(array $rawData, array $platform_orders_id_to_local_db_order_id_map): array { // 由于 $rawData 是批量数据,包含多条订单结果,因此订单子项需要从集合中提取 // Tmall 平台响应体的数据格式为: collection->payload->orders // $platform_orders_id_to_local_db_order_id_map 内部元素数据格式为 [platform_order_id => local db order id] if(empty($rawData['orders'])){ return []; } $items = []; foreach ($rawData as $raw_orders) { foreach ($raw_orders['orders'] as $raw_order_item){ // 数据库中父订单 id $db_order_id = $platform_orders_id_to_local_db_order_id_map[$raw_orders['tid']]; $items[] = $this->tmallOrderItemMap($raw_order_item, $raw_orders['tid'], $db_order_id, $raw_orders['created']); } } return $items; } /** * Tmall 订单子项映射转换 * @return void */ private function tmallOrderItemMap(array $item, string $platform_order_id, int $parent_order_id, string $parent_order_created_date): array { //@TODO order item 的业务映射需进一步补全 return [ 'company_id' => $this->getCompany()->id, 'platform_id' => $this->getPlatform()->id, 'store_id' => $this->getStore()->id, 'order_id' => $parent_order_id, 'platform_order_id' => $platform_order_id, 'sub_order_id' => $item['oid'], // @attention sku 的处理需要仅以规范和约束,确保 sku 准确 'sub_order_type_id' => '', 'product_id' => '', 'platform_product_id' =>$item['num_iid'], 'product_sku' => $item['outer_sku_id'], 'product_barcode' => '', 'unit_price' => $item['price'], 'quantity' => $item['num'], 'discount' => $item['discount_fee'], 'total' => $item['divide_order_fee'], // @attention 扩展字段,用来存储其他信息 'ext' => '', 'created_date' => $parent_order_created_date, ]; } }