同步订单状态

This commit is contained in:
Billy 2025-10-21 09:51:19 +08:00
parent ca82c79c78
commit a4b8b710d5

View File

@ -112,10 +112,23 @@ class CcbOrderService
// 获取订单商品列表 // 获取订单商品列表
$orderItems = Db::name('shopro_order_item') $orderItems = Db::name('shopro_order_item')
->where('order_id', $orderId) ->where('order_id', $orderId)
->select(); ->select()
->toArray();
// 获取支付流水号PAY_FLOW_ID必填字段
$payInfo = Db::name('shopro_pay')
->where('order_id', $orderId)
->where('status', 'paid')
->find();
if (!$payInfo || empty($payInfo['pay_sn'])) {
throw new \Exception('订单未支付或支付流水号不存在');
}
$payFlowId = $payInfo['pay_sn'];
// 构建订单数据符合A3341TP01接口规范 // 构建订单数据符合A3341TP01接口规范
$orderData = $this->buildOrderData($order, $orderItems, $ccbUserId); $orderData = $this->buildOrderData($order, $orderItems, $ccbUserId, $payFlowId);
// 记录请求数据(同步日志) // 记录请求数据(同步日志)
$txSeq = CcbMD5::generateTransactionSeq(); $txSeq = CcbMD5::generateTransactionSeq();
@ -270,13 +283,13 @@ class CcbOrderService
{ {
try { try {
// 获取订单信息 // 获取订单信息
$order = Order::find($orderId); $order = Db::name('shopro_order')->where('id', $orderId)->find();
if (!$order) { if (!$order) {
throw new \Exception('订单不存在'); throw new \Exception('订单不存在');
} }
// 验证退款金额 // 验证退款金额
if ($refundAmount > $order['total_amount']) { if ($refundAmount > $order['order_amount']) {
throw new \Exception('退款金额不能超过订单总额'); throw new \Exception('退款金额不能超过订单总额');
} }
@ -307,146 +320,110 @@ class CcbOrderService
} }
/** /**
* 构建符合建行要求的订单数据 * 构建符合建行 A3341TP01 接口规范的订单数据
* *
* ⚠️ 注意Shopro字段说明 * 📋 建行生活订单推送接口规范说明:
* - pay_fee: 实际支付金额Shopro字段 *
* - order_amount: 订单总金额Shopro字段 * 必填字段11个
* - total_discount_fee: 优惠总金额Shopro字段 * - USER_ID: 客户编号建行用户ID
* - paid_time: 支付时间毫秒时间戳需除以1000 * - ORDER_ID: 订单号
* - createtime: 创建时间毫秒时间戳需除以1000 * - ORDER_DT: 订单日期yyyyMMddHHmmss格式
* - TOTAL_AMT: 订单原金额
* - ORDER_STATUS: 订单状态
* - MCT_NM: 商户名称
* - CUS_ORDER_URL: 订单详情链接
* - PAY_FLOW_ID: 支付流水号(从 shopro_pay.pay_sn 获取)
* - PRPFTL_MRCH_ID: 门店商户号(使用 merchant_id
* - PAY_MRCH_ID: 支付商户号(使用 merchant_id
* - SKU_LIST: 商品信息JSON字符串
*
* 非必填但推荐字段:
* - PAY_AMT: 订单实际支付金额
* - DISCOUNT_AMT: 第三方平台优惠金额
* - DISCOUNT_AMT_DESC: 第三方平台优惠说明
* - REFUND_STATUS: 退款状态
* - PAY_MODE: 支付方式
* - PLAT_ORDER_TYPE: 服务方订单类型
* - COUPON_AMT: 优惠券金额
*
* ⚠️ 注意Shopro字段映射
* - pay_fee PAY_AMT实际支付金额
* - order_amount TOTAL_AMT订单总金额
* - total_discount_fee DISCOUNT_AMT优惠总金额
* - createtime ORDER_DT毫秒时间戳需除以1000
* *
* @param array $order 订单数组 * @param array $order 订单数组
* @param array $orderItems 订单商品列表 * @param array $orderItems 订单商品列表
* @param string $ccbUserId 建行用户ID * @param string $ccbUserId 建行用户ID
* @param string $payFlowId 支付流水号从shopro_pay表获取
* @return array * @return array
*/ */
private function buildOrderData($order, $orderItems, $ccbUserId) private function buildOrderData($order, $orderItems, $ccbUserId, $payFlowId)
{ {
// 构建商品列表 // 构建SKU商品列表JSON字符串格式
$goodsList = $this->buildGoodsList($orderItems); $skuList = $this->buildSkuList($orderItems);
// 计算各项金额保留2位小数
// 计算各项金额Shopro字段pay_fee=实付金额order_amount=订单总金额)
$totalAmount = number_format($order['order_amount'] ?? 0, 2, '.', ''); $totalAmount = number_format($order['order_amount'] ?? 0, 2, '.', '');
$payAmount = number_format($order['pay_fee'] ?? 0, 2, '.', ''); // 处理订单时间Shopro的createtime是毫秒时间戳需要除以1000
$discountAmount = number_format($order['total_discount_fee'] ?? 0, 2, '.', '');
// 处理支付时间Shopro的paid_time是毫秒时间戳需要除以1000
$payTime = '';
if (!empty($order['paid_time']) && is_numeric($order['paid_time'])) {
$payTime = date('YmdHis', intval($order['paid_time'] / 1000));
}
// 处理创建时间Shopro的createtime是毫秒时间戳需要除以1000
$createTimeValue = $order['createtime'] ?? null; $createTimeValue = $order['createtime'] ?? null;
if (empty($createTimeValue) || !is_numeric($createTimeValue)) { if (empty($createTimeValue) || !is_numeric($createTimeValue)) {
$createTimeValue = time() * 1000; // 当前时间的毫秒时间戳 $createTimeValue = time() * 1000;
} }
$createTime = date('YmdHis', intval($createTimeValue / 1000)); $orderDt = date('YmdHis', intval($createTimeValue / 1000));
// 获取订单地址信息Shopro将地址存储在单独的表中 // 构建符合A3341TP01接口规范的订单数据
$orderAddress = Db::name('shopro_order_address')
->where('order_id', $order['id'])
->find();
// 获取支付方式Shopro将支付信息存储在单独的表中
$payInfo = Db::name('shopro_pay')
->where('order_id', $order['id'])
->where('status', 'paid')
->find();
// 获取快递信息Shopro将快递信息存储在单独的表中
$expressInfo = Db::name('shopro_order_express')
->where('order_id', $order['id'])
->find();
// 构建订单数据34个必填字段
return [ return [
'USER_ID' => $ccbUserId, // 建行用户ID // ========== 必填字段 ==========
'USER_ID' => $ccbUserId, // 客户编号
'ORDER_ID' => $order['order_sn'], // 订单号 'ORDER_ID' => $order['order_sn'], // 订单号
'ORDER_DT' => $createTime, // 订单时间 'ORDER_DT' => $orderDt, // 订单日期yyyyMMddHHmmss
'TOTAL_AMT' => $totalAmount, // 订单原金额 'TOTAL_AMT' => $totalAmount, // 订单原金额
'PAY_AMT' => $payAmount, // 实付金额
'DISCOUNT_AMT' => $discountAmount, // 优惠金额
'ORDER_STATUS' => $this->mapOrderStatus($order['status']), // 订单状态 'ORDER_STATUS' => $this->mapOrderStatus($order['status']), // 订单状态
'REFUND_STATUS' => '0', // 退款状态(默认无退款) 'REFUND_STATUS' => $this->mapRefundStatus($order['refund_status'] ?? 0), // 退款状态
'MCT_NM' => $this->config['merchant']['name'] ?? '商户名称', // 商户名称 'MCT_NM' => $this->config['merchant']['name'] ?? '商户名称', // 商户名称
'MCT_ORDER_ID' => $order['id'], // 商户订单ID 'CUS_ORDER_URL' => $this->config['merchant']['order_detail_url'] . $order['id'], // 订单详情链接
'GOODS_LIST' => json_encode($goodsList, JSON_UNESCAPED_UNICODE), // 商品列表 'PAY_FLOW_ID' => $payFlowId, // 支付流水号(必填!)
'PAY_TYPE' => $this->mapPayType($payInfo['pay_type'] ?? ''), // 支付方式(从支付表获取) 'PAY_MRCH_ID' => $this->config['merchant_id'], // 支付商户号(必填!)
'PAY_TIME' => $payTime, // 支付时间(毫秒转秒) 'SKU_LIST' => $skuList, // 商品信息JSON字符串必填
'DELIVERY_TYPE' => '01', // 配送方式01快递 // ========== 非必填字段 ==========
'DELIVERY_STATUS' => $this->mapDeliveryStatus($order['status']), // 配送状态 'PLAT_ORDER_TYPE' => "T0000", // 服务方订单类型
'DELIVERY_TIME' => !empty($expressInfo['createtime']) ? date('YmdHis', intval($expressInfo['createtime'] / 1000)) : '', // 发货时间
'RECEIVE_NAME' => $orderAddress['consignee'] ?? '', // 收货人姓名(从地址表获取)
'RECEIVE_PHONE' => $orderAddress['mobile'] ?? '', // 收货人电话(从地址表获取)
'RECEIVE_ADDRESS' => $this->buildAddress($order), // 收货地址(从地址表获取)
'EXPRESS_COMPANY' => $expressInfo['express_name'] ?? '', // 快递公司(从快递表获取)
'EXPRESS_NO' => $expressInfo['express_no'] ?? '', // 快递单号(从快递表获取)
'REMARK' => $order['remark'] ?? '', // 备注
'ORDER_TYPE' => '01', // 订单类型01普通订单
'IS_VIRTUAL' => '0', // 是否虚拟商品
'ORDER_URL' => $this->config['merchant']['order_detail_url'] . $order['id'], // 订单详情链接
'CREATE_TIME' => $createTime, // 创建时间
'UPDATE_TIME' => date('YmdHis'), // 更新时间
'SHOP_ID' => '1', // 店铺ID
'SHOP_NAME' => $this->config['merchant']['name'] ?? '', // 店铺名称
'ACTIVITY_ID' => '', // 活动ID
'ACTIVITY_NAME' => '', // 活动名称
'COUPON_AMT' => number_format($order['coupon_discount_fee'] ?? 0, 2, '.', ''), // 优惠券金额
'FREIGHT_AMT' => number_format($order['dispatch_amount'] ?? 0, 2, '.', ''), // 运费Shopro字段名为dispatch_amount
]; ];
} }
/** /**
* 构建商品列表 * 构建符合建行规范的SKU商品列表JSON字符串格式
* *
* @param array $items 订单商品项 * 📋 建行 SKU_LIST 字段规范:
* @return array *
* 必填字段4个
* - SKU_NAME: 商品名称(必填)
* - SKU_REF_PRICE: 商品参考价必填支持小数最多2位
* - SKU_NUM: 商品数量必填支持小数最多1位
* - SKU_SELL_PRICE: 商品售价必填支持小数最多2位
*
* ⚠️ 注意Shopro字段映射
* - goods_title SKU_NAME商品名称
* - goods_original_price SKU_REF_PRICE商品原价作为参考价
* - goods_num SKU_NUM购买数量
* - goods_price SKU_SELL_PRICE商品实际售价
*
* @param array $items 订单商品项数组
* @return string JSON字符串格式的SKU列表
*/ */
private function buildGoodsList($items) private function buildSkuList($items)
{ {
$goodsList = []; $skuList = [];
foreach ($items as $item) { foreach ($items as $item) {
$goodsList[] = [ $skuList[] = [
'goods_id' => $item['goods_id'], 'SKU_NAME' => $item['goods_title'], // 商品名称(必填)
'goods_name' => $item['goods_title'], 'SKU_REF_PRICE' => number_format($item['goods_original_price'] ?? $item['goods_price'], 2, '.', ''), // 商品参考价(必填)
'goods_price' => number_format($item['goods_price'], 2, '.', ''), 'SKU_NUM' => $item['goods_num'], // 商品数量(必填)
'goods_num' => $item['goods_num'], 'SKU_SELL_PRICE' => number_format($item['goods_price'], 2, '.', ''), // 商品售价(必填)
'goods_amount' => number_format($item['goods_amount'], 2, '.', ''),
'goods_image' => $item['goods_image'] ?? '',
'goods_sku' => $item['goods_sku_text'] ?? ''
]; ];
} }
return $goodsList;
}
/** // 返回JSON字符串不转义Unicode保持中文可读
* 构建收货地址 return json_encode($skuList, JSON_UNESCAPED_UNICODE);
*
* ⚠️ 注意Shopro的收货地址存储在单独的表 shopro_order_address
*
* @param array $order 订单数组
* @return string
*/
private function buildAddress($order)
{
// 从订单地址表获取地址信息
$orderAddress = Db::name('shopro_order_address')
->where('order_id', $order['id'])
->find();
if (!$orderAddress) {
return '';
}
$address = '';
if (!empty($orderAddress['province_name'])) $address .= $orderAddress['province_name'];
if (!empty($orderAddress['city_name'])) $address .= $orderAddress['city_name'];
if (!empty($orderAddress['district_name'])) $address .= $orderAddress['district_name'];
if (!empty($orderAddress['address'])) $address .= $orderAddress['address'];
return $address;
} }
/** /**
@ -543,38 +520,6 @@ class CcbOrderService
return '0'; return '0';
} }
/**
* 映射支付方式
*
* @param string $payType 支付类型
* @return string
*/
private function mapPayType($payType)
{
$payMap = [
'wechat' => '01', // 微信支付
'alipay' => '02', // 支付宝
'ccb' => '03', // 建行支付
'balance' => '04' // 余额支付
];
return $payMap[$payType] ?? '00';
}
/**
* 映射配送状态
*
* @param string $status 订单状态
* @return string
*/
private function mapDeliveryStatus($status)
{
if (in_array($status, ['unpaid', 'paid'])) return '0'; // 未发货
if ($status == 'shipped') return '1'; // 已发货
if (in_array($status, ['received', 'completed'])) return '2'; // 已收货
return '0';
}
/** /**
* 批量同步订单 * 批量同步订单
* 用于初始化或定时同步 * 用于初始化或定时同步