OrderStatus.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. <?php
  2. namespace app\admin\model\shopro\order\traits;
  3. use app\admin\model\shopro\order\Order;
  4. use app\admin\model\shopro\order\OrderItem;
  5. use app\admin\model\shopro\activity\Groupon;
  6. use app\admin\model\shopro\Config;
  7. trait OrderStatus
  8. {
  9. protected function getStatus($data, $type)
  10. {
  11. $btns = []; // 前端订单操作按钮
  12. $backendBtns = [];
  13. $status_text = '';
  14. $status_desc = '';
  15. $ext = $this->ext;
  16. switch ($this->status_code) {
  17. case 'cancel':
  18. $status_text = '已取消';
  19. $status_desc = '买家已取消';
  20. $btns[] = 'delete'; // 删除订单
  21. break;
  22. case 'closed':
  23. $status_text = '交易关闭';
  24. if (isset($ext['closed_type']) && $ext['closed_type'] == 'refuse') {
  25. $status_desc = '买家拒绝收货';
  26. } else {
  27. $status_desc = '买家未在规定时间内付款';
  28. }
  29. $btns[] = 'delete'; // 删除订单
  30. break;
  31. case 'unpaid':
  32. $status_text = '待付款';
  33. $status_desc = '等待买家付款';
  34. $btns[] = 'cancel'; // 取消订单
  35. $btns[] = 'pay'; // 支付
  36. $backendBtns[] = 'change_fee'; // 订单改价
  37. break;
  38. // 已支付的
  39. case 'apply_refund':
  40. $status_text = '申请退款中';
  41. $status_desc = '等待卖家处理退款';
  42. $backendBtns[] = 'apply_refund_oper'; // 处理申请退款按钮
  43. $backendBtns[] = 'refund'; // 只能退款,或者在列表上拒绝申请退款
  44. break;
  45. case 'commented':
  46. $status_text = '已评价';
  47. $status_desc = '订单已评价';
  48. $dispatchType = $this->getItemDispatchTypes();
  49. if (in_array('express', $dispatchType)) {
  50. $btns[] = 'express'; // 查看物流
  51. }
  52. $backendBtns[] = 'refund';
  53. break;
  54. case 'nocomment':
  55. $status_text = '待评价';
  56. $status_desc = '等待买家评价';
  57. $dispatchType = $this->getItemDispatchTypes();
  58. if (in_array('express', $dispatchType)) {
  59. $btns[] = 'express'; // 查看物流
  60. }
  61. $btns[] = 'comment';
  62. $backendBtns[] = 'refund';
  63. break;
  64. case 'noget':
  65. $status_text = '待收货';
  66. $status_desc = '等待买家收货';
  67. $dispatchType = $this->getItemDispatchTypes();
  68. if (in_array('express', $dispatchType)) {
  69. $btns[] = 'express'; // 查看物流
  70. }
  71. if ($this->isOffline($data)) {
  72. $status_desc = '卖家已发货,等待包裹运达';
  73. // 用户可以拒收,后台确认收货
  74. $btns[] = 'refuse'; // 用户拒收
  75. $backendBtns[] = 'confirm';
  76. }else {
  77. // 计算自动确认收货时间
  78. $send_time = $ext['send_time'] ?? 0;
  79. $auto_confirm = Config::getConfigField('shop.order.auto_confirm');
  80. $auto_confirm_unix = $auto_confirm * 86400;
  81. if ($send_time && $auto_confirm_unix) {
  82. $auto_confirm_time = $send_time + $auto_confirm_unix;
  83. $status_desc .= ',还剩' . diff_in_time($auto_confirm_time, null, true, true) . '自动确认';
  84. }
  85. $btns[] = 'confirm'; // 确认收货
  86. $backendBtns[] = 'refund';
  87. }
  88. break;
  89. case 'nosend':
  90. $status_text = '待发货';
  91. $status_desc = '等待卖家发货';
  92. $statusCodes = $this->getItemStatusCode();
  93. if (in_array('noget', $statusCodes)) { // 只要存在待收货的item
  94. $btns[] = 'confirm'; // 确认收货 (部分发货时也可以收货)
  95. }
  96. if ($this->isOffline($data)) {
  97. // 发货之前用户可以取消
  98. $btns[] = 'cancel'; // 用户取消订单
  99. } else {
  100. $backendBtns[] = 'refund';
  101. }
  102. $backendBtns[] = 'send';
  103. if (!isset($ext['need_address']) || $ext['need_address']) { // 自动发货这些不需要收货地址的,没有 edit_consignee
  104. $backendBtns[] = 'edit_consignee'; //修改收货地址
  105. }
  106. break;
  107. case 'refund_completed':
  108. $status_text = '退款完成';
  109. $status_desc = '订单退款完成';
  110. break;
  111. case 'refund_agree':
  112. $status_text = '退款完成';
  113. $status_desc = '订单退款完成';
  114. break;
  115. case 'groupon_ing':
  116. $status_text = '等待成团';
  117. $status_desc = '等待拼团成功';
  118. if ($this->isOffline($data)) {
  119. // 货到付款未付款,不能退款,等待拼团时还未发货,用户可取消订单
  120. $btns[] = 'cancel'; // 用户取消订单
  121. } else {
  122. $backendBtns[] = 'refund'; // 全部退款 直接不申请退款
  123. }
  124. break;
  125. case 'groupon_invalid':
  126. $status_text = '拼团失败';
  127. $status_desc = '拼团失败';
  128. break;
  129. // 已支付的结束
  130. case 'completed':
  131. $status_text = '交易完成';
  132. $status_desc = '交易已完成';
  133. $btns[] = 'delete'; // 删除订单
  134. break;
  135. }
  136. // 有活动
  137. if (in_array($data['activity_type'], ['groupon', 'groupon_ladder', 'groupon_lucky'])) {
  138. // 是拼团订单
  139. if (isset($ext['groupon_id']) && $ext['groupon_id']) {
  140. $btns[] = 'groupon'; // 拼团详情
  141. }
  142. }
  143. if (in_array($this->status_code, ['nosend', 'groupon_ing']) && !$this->isOffline($data)) { // 线下付款订单,不可申请全额退款
  144. if (in_array($data['apply_refund_status'], [Order::APPLY_REFUND_STATUS_NOAPPLY, Order::APPLY_REFUND_STATUS_REFUSE])) {
  145. // 获取所有的 item 状态
  146. $statusCodes = $this->getItemStatusCode();
  147. if (count($statusCodes) == 1 && current($statusCodes) == 'nosend') {
  148. // items 只有 未发货,就显示 申请退款按钮
  149. if ($data['apply_refund_status'] == Order::APPLY_REFUND_STATUS_REFUSE) {
  150. $btns[] = 're_apply_refund'; // 重新申请退款
  151. } else {
  152. $btns[] = 'apply_refund'; // 申请退款
  153. }
  154. }
  155. }
  156. }
  157. if ($data['invoice_status'] == 1) {
  158. $btns[] = 'invoice'; // 查看发票
  159. }
  160. $return = null;
  161. switch ($type) {
  162. case 'status_text':
  163. $return = $status_text;
  164. break;
  165. case 'btns':
  166. $return = $btns;
  167. break;
  168. case 'status_desc':
  169. $return = $status_desc;
  170. break;
  171. case 'backend_btns':
  172. if (in_array('refund', $backendBtns)) {
  173. // 判断是否有退款,如果存在退款就移除 refund 按钮
  174. $refundCount = OrderItem::where('order_id', $data['id'])->where('refund_status', '<>', OrderItem::REFUND_STATUS_NOREFUND)->count();
  175. if ($refundCount && ($key = array_search('refund', $backendBtns))) {
  176. unset($backendBtns[$key]);
  177. }
  178. $backendBtns = array_values($backendBtns);
  179. }
  180. $return = $backendBtns;
  181. break;
  182. }
  183. return $return;
  184. }
  185. /**
  186. * 获取支付成功之后的子状态
  187. */
  188. public function getPayedStatusCode($data)
  189. {
  190. $status_code = '';
  191. // 获取所有的 item 状态
  192. $statusCodes = $this->getItemStatusCode();
  193. if (in_array('nosend', $statusCodes)) {
  194. // 存在待发货就是待发货
  195. $status_code = 'nosend';
  196. } else if (in_array('noget', $statusCodes)) {
  197. // 存在待收货,就是待收货
  198. $status_code = 'noget';
  199. } else if (in_array('nocomment', $statusCodes)) {
  200. // 存在待评价,就是待评价
  201. $status_code = 'nocomment';
  202. } else if (in_array('commented', $statusCodes)) {
  203. // 存在已评价,就是已评价
  204. $status_code = 'commented';
  205. } else if (in_array('refund_completed', $statusCodes)) {
  206. // 所有商品退款完成,或者退款中(不可能存在待发货或者收货的商品,上面已判断过)
  207. $status_code = 'refund_completed';
  208. } else if (in_array('refund_agree', $statusCodes)) {
  209. // 所有商品都同意退款了 (不可能存在待发货或者收货的商品,上面已判断过)
  210. $status_code = 'refund_agree';
  211. } // 售后都不在总状态显示
  212. if ($data['apply_refund_status'] == Order::APPLY_REFUND_STATUS_APPLY && !in_array($status_code, ['refund_completed', 'refund_agree'])) {
  213. return $status_code = 'apply_refund'; // 申请退款中,并且还没退款
  214. }
  215. $ext = $this->ext;
  216. // 是拼团订单
  217. if (
  218. in_array($data['activity_type'], ['groupon', 'groupon_ladder', 'groupon_lucky']) &&
  219. isset($ext['groupon_id']) && $ext['groupon_id']
  220. ) {
  221. $groupon = Groupon::where('id', $ext['groupon_id'])->find();
  222. if ($groupon) {
  223. if ($groupon['status'] == 'ing') {
  224. // 尚未成团
  225. $status_code = $statusCodes[0] ?? ''; // 拼团订单只能有一个商品
  226. $status_code = in_array($status_code, ['refund_agree', 'refund_completed']) ? $status_code : 'groupon_ing'; // 如果订单已退款,则是退款状态,不显示拼团中
  227. } else if ($groupon['status'] == 'invalid') {
  228. $status_code = 'groupon_invalid';
  229. }
  230. }
  231. }
  232. return $status_code;
  233. }
  234. /**
  235. * 获取订单items状态
  236. *
  237. * @param string $type
  238. * @return array
  239. */
  240. private function getItemStatusCode($type = 'order')
  241. {
  242. // 循环判断 item 状态
  243. $itemStatusCode = [];
  244. foreach ($this->items as $key => $item) {
  245. // 获取 item status
  246. $itemStatusCode[] = (new OrderItem)->getBaseStatusCode($item, $type);
  247. }
  248. // 取出不重复不为空的 status_code
  249. $statusCodes = array_values(array_unique(array_filter($itemStatusCode)));
  250. return $statusCodes;
  251. }
  252. private function getItemDispatchTypes()
  253. {
  254. $dispatchType = [];
  255. foreach ($this->items as $key => $item) {
  256. // 获取 item status
  257. $dispatchType[] = $item['dispatch_type'];
  258. }
  259. $dispatchType = array_unique(array_filter($dispatchType)); // 过滤重复,过滤空值
  260. return $dispatchType;
  261. }
  262. public function getStatusTextAttr($value, $data)
  263. {
  264. return $this->getStatus($data, 'status_text');
  265. }
  266. public function getStatusDescAttr($value, $data)
  267. {
  268. return $this->getStatus($data, 'status_desc');
  269. }
  270. public function getBtnsAttr($value, $data)
  271. {
  272. $btn_name = strpos(request()->url(), 'addons/shopro') !== false ? 'btns' : 'backend_btns';
  273. return $this->getStatus($data, $btn_name);
  274. }
  275. // 获取订单状态
  276. public function getStatusCodeAttr($value, $data)
  277. {
  278. $status_code = '';
  279. switch ($data['status']) {
  280. case Order::STATUS_CLOSED:
  281. $status_code = 'closed'; // 订单交易关闭
  282. break;
  283. case Order::STATUS_CANCEL:
  284. $status_code = 'cancel'; // 订单已取消
  285. break;
  286. case Order::STATUS_UNPAID:
  287. $status_code = 'unpaid'; // 订单等待支付
  288. break;
  289. case Order::STATUS_PENDING:
  290. $status_code = $this->getPayedStatusCode($data); // 订单线下付款
  291. break;
  292. case Order::STATUS_PAID:
  293. // 根据 item 获取支付后的状态信息
  294. $status_code = $this->getPayedStatusCode($data);
  295. break;
  296. case Order::STATUS_COMPLETED:
  297. $status_code = 'completed';
  298. break;
  299. }
  300. return $status_code;
  301. }
  302. /**
  303. * 处理未支付 item status_code
  304. * 查询列表 item status_code 不关联订单表,使用这个方法进行处理
  305. */
  306. public function setOrderItemStatusByOrder($order)
  307. {
  308. $order = $order instanceof \think\Model ? $order->toArray() : $order;
  309. foreach ($order['items'] as $key => &$item) {
  310. if ((!in_array($order['status'], [Order::STATUS_PAID, Order::STATUS_COMPLETED]) && !$this->isOffline($order)) // 没有支付,并且也不是货到付款
  311. || $order['apply_refund_status'] == Order::APPLY_REFUND_STATUS_APPLY) {
  312. // 未支付,status_code = 订单的 status_code
  313. $item['status_code'] = $order['status_code'];
  314. $item['status_text'] = '';
  315. $item['status_desc'] = '';
  316. $item['btns'] = [];
  317. } else {
  318. if (strpos(request()->url(), 'addons/shopro') !== false) {
  319. // 前端
  320. if (strpos($item['status_code'], 'nosend') !== false) {
  321. if (!$this->isOffline($order) && !array_intersect(['re_apply_refund', 'apply_refund'], $order['btns'])) {
  322. // 不能申请全额退款了(有部分发货,或者退款)的待发货的 item 要显示申请售后的按钮
  323. $aftersale_id = (isset($item['ext']['aftersale_id']) && !empty($item['ext']['aftersale_id'])) ? $item['ext']['aftersale_id'] : 0;
  324. if (strpos($item['status_code'], 'aftersale_ing') === false && strpos($item['status_code'], 'aftersale_completed') === false) {
  325. // 不是售后中,也不是售后完成
  326. if (strpos($item['status_code'], 'aftersale_refuse') !== false && $aftersale_id) {
  327. // 如果申请过退款,被拒绝了,则为重新申请售后
  328. $item['btns'][] = 're_aftersale';
  329. } else {
  330. // 取消售后是 re_aftersale ,未申请过是 aftersale
  331. $item['btns'][] = $aftersale_id ? 're_aftersale' : 'aftersale'; // 售后,售后取消会有 aftersale_id
  332. }
  333. }
  334. }
  335. } else if (strpos($item['status_code'], 'noget') !== false) {
  336. // 如果是货到付款的 待收货
  337. if ($this->isOffline($order)) {
  338. foreach($item['btns'] as $btnk => $btn) {
  339. if (in_array($btn, ['re_aftersale', 'aftersale'])) {
  340. unset($item['btns'][$btnk]);
  341. }
  342. }
  343. }
  344. }
  345. } else {
  346. // 后端,如果是货到付款, 并且还没收货,不显示退款按钮
  347. if ($this->isOffline($order) && (strpos($item['status_code'], 'nosend') !== false || strpos($item['status_code'], 'noget') !== false)) {
  348. $refund_key = array_search('refund', $item['btns']);
  349. if ($refund_key !== false) {
  350. unset($item['btns'][$refund_key]);
  351. }
  352. }
  353. }
  354. }
  355. }
  356. return $order;
  357. }
  358. }