CreateOrderService.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <?php
  2. namespace addons\WangDianTong\common\service;
  3. use addons\WangDianTong\common\enums\WangDianTongEnum;
  4. use addons\WangDianTong\common\expand\sdk\wangdian\model\Order;
  5. use addons\WangDianTong\common\expand\sdk\wangdian\model\OrderItem;
  6. use addons\WangDianTong\common\expand\sdk\wangdian\qjb\model\RawTradeItemModel;
  7. use addons\WangDianTong\common\expand\sdk\wangdian\qjb\model\RawTradeOrderItemModel;
  8. use addons\WangDianTong\common\helper\EmojiHelper;
  9. use common\enums\StatusEnum;
  10. use common\models\goods\GoodsAttr;
  11. use common\models\user\User;
  12. class CreateOrderService
  13. {
  14. /**
  15. * @param array $item 订单
  16. * @param int|null $refund_status
  17. * @return array
  18. */
  19. public function assembleData(array $item, int $refund_status = null): array
  20. {
  21. $user = User::getOne([
  22. ['id' => $item['user_id']]
  23. ], false, null, null, 'id, nickname, username, avatar_url, mobile');
  24. $order = new Order();
  25. $order->tid = $item['order_no'];
  26. // 判断退款是否为5
  27. $trade_status = WangDianTongEnum::ORDER_STATUS_MAP[$item['order_status']] ?? 0;
  28. $order->trade_status = $trade_status;
  29. // wangdianbao 1:款到发货,2:货到付款(包含部分货到付款),3:分期付款,4:挂账
  30. // local 订单配送方式【1 物流配送 2 买家自提 3 货到付款 4 本地配送】
  31. $order->delivery_term = StatusEnum::ENABLED;
  32. // 平台订单付款状态:0:未付款,1:部分付款,2:已付款
  33. // 平台订单付款状态:0:未付款,1:部分付款,2:已付款
  34. $order->pay_status = $item['pay_status'] == 0 ? $item['pay_status'] : 2;
  35. $order->trade_time = date('Y-m-d H:i:s', $item['created_at']);
  36. $order->pay_time = $item['pay_status'] == StatusEnum::ENABLED ? date('Y-m-d H:i:s', $item['pay_time']) : '0000-00-00 00:00:00';
  37. $order->buyer_nick = EmojiHelper::convert(!empty($user->nickname) ? $user->nickname : "无昵称");
  38. // $order->buyer_email = '';
  39. // 如果是虚拟订单那么就没有收货地址
  40. $regions = explode(' ', $item['region_name']);
  41. $order->receiver_mobile = $item['mobile'];
  42. // $order->receiver_telno = '';
  43. $order->receiver_zip = $item['zip'];
  44. $order->receiver_province = $regions[0] ?? '';
  45. $order->receiver_name = $item['receiver_name'];
  46. $order->receiver_city = $regions[1] ?? '';
  47. $order->receiver_district = $regions[2] ?? '';
  48. $order->receiver_address = EmojiHelper::convert(sprintf("%s%s", ($regions[3] ?? ''), $item['address']));
  49. // 物流
  50. // $order->logistics_type = -1;
  51. // 发票相关
  52. // $order->invoice_kind = '';
  53. // $order->invoice_title = '';
  54. // $order->invoice_content = '';
  55. // 货品明细备注推送此字段ERP客户端需升级至V2.3.9.2及以上
  56. // 备注相关
  57. $order->remark = '';
  58. $order->buyer_message = EmojiHelper::convert(!empty($item['remark']) ? $item['remark'] : '');
  59. $order->seller_memo = EmojiHelper::convert(!empty($item['seller_remark']) ? $item['seller_remark'] : '');
  60. $order->remark_flag = StatusEnum::DISABLED;
  61. // 金额相关
  62. $order->post_amount = $item['shipping_money'];
  63. $order->other_amount = '0';
  64. $order->paid = $item['pay_money'];
  65. // 货到付款金额 cod金额=(price * num + adjust_amount -discount – share_discount)+post_amount+ext_cod_fee-paid
  66. $order->cod_amount = '0';
  67. // 货到付款买家费用,扣除货到付款订单金额后,卖家仍需支付的货到付款其他金额。这个钱卖家收不回来,是快递公司直接收走,但在快递单里是要打印出来,否则快递收款就错了
  68. $order->ext_cod_fee = '0';
  69. $order_list = [];
  70. // 订单金额对不上 -》 使用积分抵扣/支付随机抵扣
  71. $detail_total_amount = 0;
  72. $detail_total_amount_arr = [];
  73. $can_close = true;
  74. foreach ($item['detail'] as $key => $detail) {
  75. $tmp_total_amount = bcmul($detail['goods_price'], 1, 2);
  76. $detail_total_amount = bcadd($detail_total_amount, $tmp_total_amount, 2);
  77. $detail_total_amount_arr[$key] = $tmp_total_amount;
  78. $orderItem = new OrderItem();
  79. $orderItem->oid = "{$item['order_no']}_{$detail['id']}";
  80. $orderItem->num = $detail['num'];
  81. $orderItem->goods_id = $detail['goods_id'];
  82. $orderItem->price = $detail['price'];
  83. $orderItem->status = $refund_status == WangDianTongEnum::REFUND_STATUS_FINISH ?
  84. WangDianTongEnum::ORDER_STATUS_REFUND_FINISH :
  85. WangDianTongEnum::ORDER_STATUS_MAP[$detail['order_status']] ?? 0;
  86. // wangdianbao: 0:无退款,1:取消退款,2:已申请退款,3:等待退货,4:等待收货,5:退款成功。本字段在售前退款的时候,根据不同的场景填写不同的值,eg:申请退款值为2,取消退款值为1
  87. // local: 订单售后状态【0未售后 1售后中 2售后完成】
  88. if ($refund_status !== null) {
  89. $orderItem->refund_status = $refund_status;
  90. } else {
  91. $orderItem->refund_status = WangDianTongEnum::ORDER_REFUND_MAP[$detail['is_feedback']] ?? StatusEnum::DISABLED;
  92. }
  93. if ($orderItem->refund_status != WangDianTongEnum::ORDER_STATUS_REFUND_FINISH) {
  94. $can_close = false;
  95. }
  96. //获取商品规格信息
  97. $attr_info = GoodsAttr::getOne([
  98. ['id' => $detail['goods_attr_id']],
  99. ], true);
  100. // 平台系统单品(SKU)的的唯一标识,尽量不为空,spec_id和spec_no区别与SPU、SKU
  101. $orderItem->spec_id = $detail['goods_attr_id'];
  102. // 平台货品SPU编码,对应ERP货品编号,尽量不为空
  103. // $orderItem->goods_no = $detail['goods_attr_id'];
  104. // 平台货品SKU唯一码,对应ERP商家编码,goods_no和spec_no不能同时为空
  105. $orderItem->spec_no = $detail['goods_attr_id'];
  106. // 商品规格如果开启了‘是否启用商品编码’按钮,则使用规格对应填写的商家编码
  107. if ($attr_info['is_show_code'] == 1) {
  108. $orderItem->spec_no = $attr_info['spec_no'];
  109. }
  110. $orderItem->goods_name = EmojiHelper::convert(!empty($detail['goods_name']) ? $detail['goods_name'] : '');
  111. $orderItem->spec_name = EmojiHelper::convert(!empty($detail['goods_attr_name']) ? $detail['goods_attr_name'] : '');
  112. $orderItem->adjust_amount = abs($detail['adjust_money']);
  113. // 下单总折扣,客户下单时折扣(比如促销打折,不包含客服调整、分摊折扣,没有传0)
  114. // 确保 delivery_term = 1 trade_status = 30 pay_status = 2 ,且根据公式计算出正确的paid值,paid计算公式:paid = Σ(price * num + adjust_amount -discount – share_discount)+ post_amount+other_amount。
  115. $orderItem->discount = bcadd(abs($detail['adjust_money']), bcsub(bcmul($detail['price'], $detail['num'], 2), $tmp_total_amount, 2), 2);
  116. // 分摊总折扣,由总订单分摊而来,一般是付款时产生,如使用优惠券,没有传0。分摊优惠传值注意:例如三个商品,优惠10,分摊优惠可以是:3/3/4,或者3.33/3.33/3.34.即最后一个商品的分摊优惠使用减法计算
  117. $orderItem->share_discount = 0;
  118. // $orderItem->remark = ''; // 子订单备注
  119. // $orderItem->cid = ''; // 所属类目
  120. $order_list[] = $orderItem->toArray();
  121. }
  122. if ($can_close) {
  123. $order->trade_status = WangDianTongEnum::ORDER_STATUS_REFUND_FINISH;
  124. }
  125. // 抵扣信息
  126. $goods_total_price = bcsub($item['pay_money'], $item['shipping_money'], 2);
  127. $diff_amount = bcmul(bcsub($detail_total_amount, $goods_total_price, 2), 100, 0);
  128. if ($diff_amount > 0) {
  129. // 金额需要调整
  130. $index = count($detail_total_amount_arr) - 1;
  131. $total_discount = 0;
  132. foreach ($detail_total_amount_arr as $key => $amount) {
  133. if ($key == $index) {
  134. $order_list[$key]['share_discount'] = bcdiv(bcsub($diff_amount, $total_discount, 0), 100, 2);
  135. } else {
  136. $discount_rate = round(bcdiv($amount, $detail_total_amount, 3), 2);
  137. $total_discount += bcmul($diff_amount, $discount_rate, 0);
  138. $order_list[$key]['share_discount'] = bcdiv(bcmul($diff_amount, $discount_rate, 0), 100, 2);
  139. }
  140. }
  141. }
  142. $order->order_list = $order_list;
  143. return $order->toArray();
  144. }
  145. /**
  146. * 旗舰版
  147. * @param array $order
  148. * @return array
  149. */
  150. public function flagshipAssembleData(array $order)
  151. {
  152. date_default_timezone_set("Asia/Shanghai");
  153. $raw_trade_list = $raw_trade_order_list = $discount_list = [];
  154. // 取出买家信息
  155. $user = User::getOne([
  156. ['id' => $order['user_id']]
  157. ], false, null, null, 'id, nickname, username, avatar_url, mobile');
  158. $rawTradeItemModel = new RawTradeItemModel();
  159. $rawTradeItemModel->tid = $order['order_no'];
  160. // 默认10, 发货40, 签收60
  161. $rawTradeItemModel->process_status = WangDianTongEnum::ORDER_PROCESS_STATUS_MAP[$order['order_status']] ?? 10; // 默认是
  162. $rawTradeItemModel->trade_status = WangDianTongEnum::ORDER_STATUS_MAP[$order['order_status']] ?? 0;
  163. // 0无退款 1申请退款 2部分退款 3全部退款,单据状态变更点击文档查看
  164. // 判断是否
  165. $rawTradeItemModel->refund_status = $this->refundStatus($order);
  166. $rawTradeItemModel->pay_status = $order['pay_status'] == 0 ? $order['pay_status'] : 2; // 0未付款1部分付款2已付款
  167. $rawTradeItemModel->order_count = count($order['detail']);
  168. $rawTradeItemModel->goods_count = array_sum(array_column($order['detail'], 'num'));
  169. //
  170. if ($order['pay_status'] == StatusEnum::ENABLED) {
  171. $rawTradeItemModel->pay_method = WangDianTongEnum::PAYMENT_TYPE_MAP[$order['payment_type']] ??
  172. ($order['pay_status'] == StatusEnum::ENABLED ? 1 : 0); // 1在线转帐 2现金,3银行转账,4邮局汇款 5预付款 6刷卡 7支付宝 8微信支付
  173. }
  174. $rawTradeItemModel->trade_time = date('Y-m-d H:i:s', $order['created_at']);
  175. if ($order['pay_status'] == StatusEnum::ENABLED) $rawTradeItemModel->pay_time = date('Y-m-d H:i:s', $order['pay_time']);
  176. $rawTradeItemModel->end_time = null;
  177. $rawTradeItemModel->buyer_nick = EmojiHelper::convert(!empty($user->nickname) ? $user->nickname : '无昵称');
  178. $rawTradeItemModel->buyer_message = '';
  179. // $rawTradeItemModel->buyer_email = $order['order_no'];
  180. // $rawTradeItemModel->buyer_area = $order['order_no'];
  181. $rawTradeItemModel->receiver_name = EmojiHelper::convert(!empty($order['receiver_name']) ? $order['receiver_name'] : '');;
  182. $rawTradeItemModel->receiver_area = $order['region_name'];
  183. $rawTradeItemModel->receiver_address = $order['address'];
  184. $rawTradeItemModel->receiver_mobile = $order['mobile'];
  185. $rawTradeItemModel->post_amount = empty($order['shipping_money']) ? 0 : $order['shipping_money'];
  186. $rawTradeItemModel->other_amount = '0';
  187. $rawTradeItemModel->discount = '0';
  188. $rawTradeItemModel->receivable = $order['pay_money']; // 应收金额,售前退款会变化,“详细金额逻辑点击查看”
  189. $rawTradeItemModel->platform_cost = "0";
  190. // $rawTradeItemModel->logistics_type = $order['order_no'];
  191. // $rawTradeItemModel->cust_data = $order['order_no'];
  192. $rawTradeItemModel->delivery_term = 1; // 1款到发货 2货到付款(包含部分货到付款) 3分期付款
  193. // $rawTradeItemModel->pay_id = $order['order_no'];
  194. $rawTradeItemModel->remark = EmojiHelper::convert(!empty($item['seller_remark']) ? $item['seller_remark'] : '');;
  195. $rawTradeItemModel->remark_flag = StatusEnum::DISABLED;
  196. // $rawTradeItemModel->cod_amount = $order['order_no']; // 若delivery_term=2,则为应付金额,否则为0
  197. $rawTradeItemModel->is_auto_wms = false; // true自流转,false 非自流转
  198. // $rawTradeItemModel->warehouse_no = $order['order_no']; // 仅自流转订单填写该仓库编号, 非自流转订单传入空字符串即可
  199. $refund_status = null;
  200. // 订单金额对不上 -》 使用积分抵扣/支付随机抵扣
  201. $detail_total_amount = 0;
  202. $detail_total_amount_arr = [];
  203. $can_close = true;
  204. foreach ($order['detail'] as $key => $detail) {
  205. $tmp_total_amount = bcmul($detail['num'], $detail['price'], 2);
  206. $detail_total_amount = bcadd($detail_total_amount, $tmp_total_amount, 2);
  207. $detail_total_amount_arr[$key] = $tmp_total_amount;
  208. $rawTradeOrderModel = new RawTradeOrderItemModel();
  209. $rawTradeOrderModel->tid = $order['order_no'];
  210. $rawTradeOrderModel->oid = "{$order['order_no']}_{$detail['id']}";
  211. $rawTradeOrderModel->status = $refund_status == WangDianTongEnum::REFUND_STATUS_FINISH ?
  212. WangDianTongEnum::ORDER_STATUS_REFUND_FINISH :
  213. WangDianTongEnum::ORDER_STATUS_MAP[$detail['order_status']] ?? 0;
  214. if ($refund_status !== null) {
  215. $rawTradeOrderModel->refund_status = $refund_status;
  216. } else {
  217. $rawTradeOrderModel->refund_status = WangDianTongEnum::ORDER_REFUND_MAP[$detail['is_feedback']] ?? StatusEnum::DISABLED;
  218. }
  219. if ($rawTradeOrderModel->refund_status != WangDianTongEnum::ORDER_STATUS_REFUND_FINISH) {
  220. $can_close = false;
  221. }
  222. $rawTradeOrderModel->goods_id = $detail['goods_id'];
  223. $rawTradeOrderModel->spec_id = $detail['goods_attr_id'];
  224. $rawTradeOrderModel->goods_no = $detail['goods_attr_id'];
  225. $rawTradeOrderModel->spec_no = $detail['goods_attr_id'];
  226. $rawTradeOrderModel->goods_name = EmojiHelper::convert(!empty($detail['goods_name']) ? $detail['goods_name'] : '');
  227. $rawTradeOrderModel->spec_name = EmojiHelper::convert(!empty($detail['goods_attr_name']) ? $detail['goods_attr_name'] : '');
  228. $rawTradeOrderModel->order_type = $order['is_virtual']; // 0正常货品 1虚拟货品 2服务(不传默认为0)
  229. $rawTradeOrderModel->num = $detail['num'];
  230. $rawTradeOrderModel->price = $detail['price'];
  231. $rawTradeOrderModel->discount = bcadd(abs($detail['adjust_money']), bcsub(bcmul($detail['price'], $detail['num'], 2), $tmp_total_amount, 2), 2);
  232. $rawTradeOrderModel->share_discount = 0;
  233. $rawTradeOrderModel->total_amount = $detail['goods_price'];
  234. $rawTradeOrderModel->adjust_amount = abs($detail['adjust_money']);
  235. $rawTradeOrderModel->refund_amount = 0;
  236. $rawTradeOrderModel->remark = "暂无备注";
  237. $rawTradeOrderModel->json = "";
  238. $raw_trade_order_list[] = $rawTradeOrderModel->toArray();
  239. }
  240. if ($can_close) {
  241. $rawTradeItemModel->trade_status = WangDianTongEnum::ORDER_STATUS_REFUND_FINISH;
  242. }
  243. // 抵扣信息
  244. $goods_total_price = bcsub($order['pay_money'], $order['shipping_money'], 2);
  245. $diff_amount = bcmul(bcsub($detail_total_amount, $goods_total_price, 2), 100, 0);
  246. if ($diff_amount > 0) {
  247. // 金额需要调整
  248. // 拥有折扣金额需要分摊优惠金额
  249. $share_num = count($raw_trade_order_list);// 需要分摊的订单数量
  250. $total_amount_price = 0; // 平摊优惠总金额
  251. $last_key = $share_num - 1; // 最后一个商品key
  252. // 获取每一个商品平摊优惠金额
  253. $avg_discount_price = bcdiv($diff_amount, $share_num, 2);
  254. foreach ($raw_trade_order_list as $key=>$rawTradeOrderModel) {
  255. if ($key == $last_key) {
  256. // 最后一个商品使用减法计算
  257. $raw_trade_order_list[$key]['share_discount'] = bcsub($diff_amount, $total_amount_price, 2);
  258. } else {
  259. // 其他订单平均分配折扣金额
  260. $total_amount_price = bcadd($avg_discount_price, $total_amount_price, 2);
  261. $raw_trade_order_list[$key]['share_discount'] = $avg_discount_price;
  262. }
  263. }
  264. }
  265. // 优惠
  266. return [
  267. [$rawTradeItemModel->toArray()],
  268. $raw_trade_order_list,
  269. []
  270. ];
  271. }
  272. protected function refundStatus(array $order)
  273. {
  274. if ($order['is_feedback'] == 2) {
  275. return 3;
  276. }
  277. if ($order['is_feedback'] == 1) {
  278. return 1;
  279. }
  280. // 判断是否含有部分退款
  281. // 订单状态【0待付款 1待发货 2 已发货 3已收货 4已完成 -1申请售后 -2售后中 -3售后完成 -4 已关闭 -5撤销售后】
  282. $order_status = array_column($order['detail'], 'order_status');
  283. if (in_array(-3, $order_status)) {
  284. return 2;
  285. }
  286. return 0;
  287. }
  288. }