OrderOper.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <?php
  2. namespace addons\shopro\service\order;
  3. use app\admin\model\shopro\user\User;
  4. use app\admin\model\shopro\order\Order;
  5. use app\admin\model\shopro\order\OrderItem;
  6. use app\admin\model\shopro\order\Action;
  7. use app\admin\model\shopro\goods\Comment;
  8. use app\admin\model\shopro\activity\GiftLog;
  9. use app\admin\model\shopro\activity\Order as ActivityOrderModel;
  10. use think\Db;
  11. class OrderOper
  12. {
  13. public function __construct()
  14. {
  15. }
  16. /**
  17. * 订单自动关闭`
  18. *
  19. * @param \think\Model $order
  20. * @param \think\Model|null $user
  21. * @param string $type
  22. * @return void
  23. */
  24. public function close($order, $user = null, $type = 'user', $msg = '', $ext = [])
  25. {
  26. $order->status = Order::STATUS_CLOSED;
  27. $order->ext = array_merge($order->ext, $ext, ['closed_time' => time()]); // 关闭时间
  28. $order->allowField(true)->save();
  29. Action::add($order, null, $user, $type, ($msg ? : $this->getOperText($type) . '关闭订单'));
  30. // 订单自动关闭之后 行为 返还用户优惠券,积分
  31. $data = ['order' => $order];
  32. \think\Hook::listen('order_close_after', $data);
  33. return $order;
  34. }
  35. /**
  36. * 订单取消
  37. *
  38. * @param object $order
  39. * @param object $user
  40. * @param string $type
  41. * @return object
  42. */
  43. public function cancel($order, $user = null, $type = 'user', $msg = '')
  44. {
  45. $order->status = Order::STATUS_CANCEL; // 取消订单
  46. $order->ext = array_merge($order->ext, ['cancel_time' => time()]); // 取消时间
  47. $order->allowField(true)->save();
  48. //商城,未付款取消,冗余到bill表
  49. Db::name('bill')->where([
  50. 'table_name' => 'shopro_order',
  51. 'table_id' => $order->id,
  52. ])->update([
  53. 'status' => 5, //已取消
  54. ]);
  55. Action::add($order, null, $user, $type, ($msg ?: $this->getOperText($type) . '取消订单'));
  56. // 订单取消,退回库存,退回优惠券积分,等
  57. $data = ['order' => $order];
  58. \think\Hook::listen('order_cancel_after', $data);
  59. return $order;
  60. }
  61. /**
  62. * 申请全额退款
  63. *
  64. * @param object $order
  65. * @param object $user
  66. * @param string $type
  67. * @return object
  68. */
  69. public function applyRefund($order, $user, $type = 'user',$reason = '')
  70. {
  71. $items = OrderItem::where('order_id', $order->id)->lock(true)->select();
  72. foreach ($items as $key => $item) {
  73. if (in_array($item['refund_status'], [
  74. OrderItem::REFUND_STATUS_AGREE,
  75. OrderItem::REFUND_STATUS_COMPLETED,
  76. ])) {
  77. error_stop('订单有退款,不可申请');
  78. }
  79. if ($item['dispatch_status'] != OrderItem::DISPATCH_STATUS_NOSEND) {
  80. error_stop('订单已发货,不可申请');
  81. }
  82. }
  83. $order->apply_refund_status = Order::APPLY_REFUND_STATUS_APPLY; // 申请退款
  84. $order->ext = array_merge($order->ext, ['apply_refund_time' => time()]); // 申请时间
  85. $order->save();
  86. //商城,已支付未发货全额退款,冗余到bill表
  87. Db::name('bill')->where([
  88. 'table_name' => 'shopro_order',
  89. 'table_id' => $order->id,
  90. ])->update([
  91. 'status' => 5, //已取消
  92. ]);
  93. Action::add($order, null, $user, $type, $this->getOperText($type) . '申请全额退款。' . $reason);
  94. // 订单申请全额退款 orderApplyRefundAfter
  95. $data = ['order' => $order, 'user' => $user];
  96. \think\Hook::listen('order_apply_refund_after', $data);
  97. return $order;
  98. }
  99. /**
  100. * 确认收货
  101. *
  102. * @param object $order
  103. * @param array $itemIds
  104. * @param object|null $user
  105. * @param string $type
  106. * @return object
  107. */
  108. public function confirm($order, $itemIds = [], $user = null, $type = 'user')
  109. {
  110. $items = OrderItem::canConfirm()->where('order_id', $order->id)->where(function ($query) use ($itemIds) {
  111. if ($itemIds) {
  112. // 只确认收货传入的 ids
  113. $query->whereIn('id', $itemIds);
  114. }
  115. })->lock(true)->select();
  116. if (!$items) {
  117. error_stop('订单已确认收货,请不要重复确认收货');
  118. }
  119. foreach ($items as $item) {
  120. $item->ext = array_merge($item->ext, ['confirm_time' => time()]);
  121. $item->dispatch_status = OrderItem::DISPATCH_STATUS_GETED; // 确认收货
  122. $item->save();
  123. Action::add($order, $item, $user, $type, $this->getOperText($type) . '确认收货');
  124. // 订单确认收货后
  125. $data = ['order' => $order, 'item' => $item];
  126. \think\Hook::listen('order_confirm_after', $data);
  127. }
  128. //商城,确认收货,冗余到bill表
  129. Db::name('bill')->where([
  130. 'table_name' => 'shopro_order',
  131. 'table_id' => $order->id,
  132. ])->update([
  133. 'status' => 3, //已完成
  134. ]);
  135. return $order;
  136. }
  137. /**
  138. * 拒收收货
  139. *
  140. * @param object $order
  141. * @param array $itemIds
  142. * @param object|null $user
  143. * @param string $type
  144. * @return object
  145. */
  146. public function refuse($order, $user = null, $type = 'user')
  147. {
  148. $items = OrderItem::canConfirm()->where('order_id', $order->id)->lock(true)->select();
  149. if (!$items) {
  150. error_stop('没有可拒收的商品');
  151. }
  152. foreach ($items as $item) {
  153. $item->ext = array_merge($item->ext, ['refuse_time' => time()]);
  154. $item->dispatch_status = OrderItem::DISPATCH_STATUS_REFUSE; // 拒收
  155. $item->save();
  156. Action::add($order, $item, $user, $type, $this->getOperText($type) . '操作,用户拒绝收货');
  157. }
  158. // 订单拒收后事件
  159. $data = ['order' => $order];
  160. \think\Hook::listen('order_refuse_after', $data);
  161. return $order;
  162. }
  163. /**
  164. * 评价 (根据 comments 中的数据进行评价, 可以之评价一个(系统自动评价时候))
  165. *
  166. * @param object $order
  167. * @param object|null $user
  168. * @param string $type
  169. * @return object
  170. */
  171. public function comment($order, $comments, $user = null, $type = 'user')
  172. {
  173. // 评价的orderItem id
  174. $comments = array_column($comments, null, 'item_id');
  175. $itemIds = array_keys($comments);
  176. $items = OrderItem::canComment()->where('order_id', $order->id)->lock(true)->select();
  177. if (!$items) {
  178. if ($type == 'system') {
  179. return $order; // 系统自动评价时检测到用户已经自己评价,这里直接返回,不抛出异常
  180. }
  181. error_stop('订单已评价,请不要重复评价');
  182. }
  183. $orderConfig = sheep_config('shop.order');
  184. $orderUser = User::get($order->user_id);
  185. foreach ($items as $item) {
  186. if (!in_array($item['id'], $itemIds)) {
  187. // 不在本次评价列表
  188. continue;
  189. }
  190. $comment = $comments[$item['id']] ?? [];
  191. $status = 'normal';
  192. if (isset($orderConfig['comment_check']) && $orderConfig['comment_check'] && $type != 'system') {
  193. // 需要检查,并且不是系统自动评价
  194. $status = 'hidden';
  195. }
  196. Comment::create([
  197. 'goods_id' => $item->goods_id,
  198. 'order_id' => $order->id,
  199. 'order_item_id' => $item->id,
  200. 'user_id' => $order->user_id,
  201. 'user_nickname' => $orderUser ? $orderUser->nickname : null,
  202. 'user_avatar' => $orderUser ? $orderUser->avatar : null,
  203. 'level' => $comment['level'] ?? 5,
  204. 'content' => $comment['content'] ?? ($orderConfig['auto_comment_content'] ?? '用户默认好评'),
  205. 'images' => $comment['images'] ?? [],
  206. 'status' => $status
  207. ]);
  208. $item->ext = array_merge($item->ext, ['comment_time' => time()]);
  209. $item->comment_status = OrderItem::COMMENT_STATUS_OK; // 评价
  210. $item->save();
  211. Action::add($order, $item, $user, $type, $this->getOperText($type) . '评价完成');
  212. // 订单评价后
  213. $data = ['order' => $order, 'item' => $item, 'user' => $user];
  214. \think\Hook::listen('order_comment_after', $data);
  215. }
  216. return $order;
  217. }
  218. /**
  219. * 删除订单
  220. *
  221. * @param object $order
  222. * @param object|null $user
  223. * @param string $type
  224. * @return void
  225. */
  226. public function delete($order, $user = null, $type = 'user')
  227. {
  228. $order->delete(); // 删除订单
  229. Action::add($order, null, $user, 'user', '用户删除订单');
  230. }
  231. /**
  232. * 存储活动信息
  233. *
  234. * @param \think\Model $order
  235. * @param array $result
  236. * @return void
  237. */
  238. public function addActivityOrder($order)
  239. {
  240. $ext = $order->ext;
  241. $items = $order->items;
  242. $goodsIds = array_column($items, 'goods_id');
  243. $model = new ActivityOrderModel();
  244. $model->order_id = $order->id;
  245. $model->user_id = $order->user_id;
  246. $model->activity_id = $order->activity_id;
  247. $model->activity_title = $ext['activity_title'] ?? null;
  248. $model->activity_type = $ext['activity_type'] ?? null;
  249. $model->pay_fee = $order->pay_fee;
  250. $model->goods_amount = $order->goods_amount;
  251. $model->discount_fee = $ext['activity_discount_amount'] ?? 0; // 普通商品总额和活动时商品总额的差
  252. $model->goods_ids = join(',', $goodsIds);
  253. $model->save();
  254. }
  255. /**
  256. * 存储促销信息
  257. *
  258. * @param \think\Model $order
  259. * @param array $result
  260. * @return void
  261. */
  262. public function addPromosOrder($order)
  263. {
  264. $ext = $order->ext;
  265. $promoInfos = $ext['promo_infos'] ?? [];
  266. foreach ($promoInfos as $key => $info) {
  267. $model = new ActivityOrderModel();
  268. $model->order_id = $order->id;
  269. $model->user_id = $order->user_id;
  270. $model->activity_id = $info['activity_id'];
  271. $model->activity_title = $info['activity_title'];
  272. $model->activity_type = $info['activity_type'];
  273. $model->pay_fee = $order->pay_fee;
  274. $model->goods_amount = $info['promo_goods_amount'];
  275. $model->discount_fee = 0;
  276. if (in_array($info['activity_type'], ['full_reduce', 'full_discount', 'free_shipping'])) {
  277. $model->discount_fee = $info['promo_discount_money'];
  278. } else if ($info['activity_type'] == 'full_gift') {
  279. // 这里设置为 0,等支付成功之后补充
  280. $model->discount_fee = 0;
  281. }
  282. $model->goods_ids = join(',', $info['goods_ids']);
  283. $rules = [
  284. 'rule_type' => $info['rule_type'],
  285. 'discount_rule' => $info['discount_rule'],
  286. ];
  287. if ($info['activity_type'] == 'full_gift') {
  288. $rules['limit_num'] = $info['limit_num'] ?? 0;
  289. $rules['event'] = $info['event'] ?? 0;
  290. }
  291. $currentExt['rules'] = $rules;
  292. $model->ext = $currentExt;
  293. $model->save();
  294. }
  295. }
  296. /**
  297. * 将活动订单标记为已支付
  298. *
  299. * @param [type] $order
  300. * @return void
  301. */
  302. public function activityOrderPaid($order)
  303. {
  304. $activityOrders = ActivityOrderModel::where('order_id', $order->id)->select();
  305. foreach ($activityOrders as $activityOrder) {
  306. if ($activityOrder->activity_type == 'full_gift') {
  307. $value_money = GiftLog::where('activity_id', $activityOrder->activity_id)
  308. ->where('order_id', $activityOrder->order_id)
  309. ->where('user_id', $activityOrder->user_id)
  310. ->whereIn('type', ['money', 'coupon']) // 这里只算 赠送的余额,和优惠券(不算积分,和赠送商品的价值)
  311. ->sum('value');
  312. $activityOrder->discount_fee = $value_money; // 补充赠送的价值
  313. } else if (in_array($activityOrder->activity_type, ['groupon', 'groupon_ladder'])) {
  314. $ext = $order->ext;
  315. $currentExt['buy_type'] = $ext['buy_type'] ?? '';
  316. $currentExt['groupon_id'] = $ext['groupon_id'] ?? 0; // 开团时候,支付之后才会有 groupon_id
  317. $activityOrder->ext = $currentExt;
  318. }
  319. $activityOrder->status = ActivityOrderModel::STATUS_PAID;
  320. $activityOrder->save();
  321. }
  322. }
  323. /**
  324. * 根据 oper_type 获取对应的用户
  325. */
  326. private function getOperText($oper_type)
  327. {
  328. switch($oper_type) {
  329. case 'user':
  330. $oper_text = '用户';
  331. break;
  332. case 'admin':
  333. $oper_text = '管理员';
  334. break;
  335. case 'system':
  336. $oper_text = '系统自动';
  337. break;
  338. default :
  339. $oper_text = '系统自动';
  340. break;
  341. }
  342. return $oper_text;
  343. }
  344. }