Order.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. <?php
  2. namespace app\data\controller\api\auth;
  3. use app\data\controller\api\Auth;
  4. use app\data\service\GoodsService;
  5. use app\data\service\OrderService;
  6. use app\data\service\PaymentService;
  7. use app\data\service\TruckService;
  8. use app\data\service\UserService;
  9. use think\admin\extend\CodeExtend;
  10. use think\exception\HttpResponseException;
  11. /**
  12. * 用户订单数据接口
  13. * Class Order
  14. * @package app\data\controller\api\auth
  15. */
  16. class Order extends Auth
  17. {
  18. /**
  19. * 控制器初始化
  20. */
  21. protected function initialize()
  22. {
  23. parent::initialize();
  24. if (empty($this->user['status'])) {
  25. $this->error('账户已被冻结,不能操作订单数据哦!');
  26. }
  27. }
  28. /**
  29. * 获取订单列表
  30. * @throws \think\db\exception\DataNotFoundException
  31. * @throws \think\db\exception\DbException
  32. * @throws \think\db\exception\ModelNotFoundException
  33. */
  34. public function get()
  35. {
  36. $map = ['uid' => $this->uuid, 'deleted' => 0];
  37. $query = $this->_query('ShopOrder')->in('status')->equal('order_no');
  38. $result = $query->where($map)->order('id desc')->page(true, false, false, 20);
  39. if (count($result['list']) > 0) OrderService::instance()->buildItemData($result['list']);
  40. $this->success('获取订单数据成功!', $result);
  41. }
  42. /**
  43. * 用户创建订单
  44. * @throws \think\db\exception\DataNotFoundException
  45. * @throws \think\db\exception\DbException
  46. * @throws \think\db\exception\ModelNotFoundException
  47. */
  48. public function add()
  49. {
  50. // 商品规则
  51. $rules = $this->request->post('items', '');
  52. if (empty($rules)) $this->error('商品不能为空');
  53. // 订单数据
  54. [$codes, $items] = [[], []];
  55. $order = ['uid' => $this->uuid, 'status' => 1];
  56. $order['order_no'] = CodeExtend::uniqidDate(18, 'N');
  57. // 推荐人处理
  58. $order['from'] = input('from_uid', $this->user['from']);
  59. if ($order['from'] == $this->uuid) $order['from'] = 0;
  60. if ($order['from'] > 0) {
  61. $map = ['id' => $order['from'], 'status' => 1];
  62. $from = $this->app->db->name('DataUser')->where($map)->find();
  63. if (empty($from)) $this->error('推荐人异常');
  64. }
  65. foreach (explode('||', $rules) as $rule) {
  66. [$code, $spec, $count] = explode('@', $rule);
  67. // 商品信息检查
  68. $map = ['code' => $code, 'status' => 1, 'deleted' => 0];
  69. $goodsInfo = $this->app->db->name('ShopGoods')->where($map)->find();
  70. if (empty($goodsInfo)) $this->error('商品数据异常');
  71. $map = ['goods_code' => $code, 'goods_spec' => $spec, 'status' => 1];
  72. $goodsItem = $this->app->db->name('ShopGoodsItem')->where($map)->find();
  73. if (empty($goodsItem)) $this->error('商品规格异常');
  74. // 商品库存检查
  75. if ($goodsItem['stock_sales'] + $count > $goodsItem['stock_total']) {
  76. $this->error('商品库存不足');
  77. }
  78. // 订单详情处理
  79. $items[] = [
  80. 'uid' => $order['uid'],
  81. 'order_no' => $order['order_no'],
  82. // 商品字段
  83. 'goods_name' => $goodsInfo['name'],
  84. 'goods_cover' => $goodsInfo['cover'],
  85. 'goods_sku' => $goodsItem['goods_sku'],
  86. 'goods_code' => $goodsItem['goods_code'],
  87. 'goods_spec' => $goodsItem['goods_spec'],
  88. // 数量处理
  89. 'stock_sales' => $count,
  90. 'truck_tcode' => $goodsInfo['truck_tcode'],
  91. 'truck_count' => $goodsItem['number_express'] * $count,
  92. // 费用字段
  93. 'price_market' => $goodsItem['price_market'],
  94. 'price_selling' => $goodsItem['price_selling'],
  95. 'total_market' => $goodsItem['price_market'] * $count,
  96. 'total_selling' => $goodsItem['price_selling'] * $count,
  97. ];
  98. }
  99. try {
  100. // 统计商品数量
  101. $order['number_goods'] = array_sum(array_column($items, 'stock_sales'));
  102. // 统计商品金额
  103. $order['amount_goods'] = array_sum(array_column($items, 'total_selling'));
  104. // 订单随机免减
  105. $order['amount_reduct'] = OrderService::instance()->getReduct();
  106. if ($order['amount_reduct'] > $order['amount_goods']) {
  107. $order['amount_reduct'] = $order['amount_goods'];
  108. }
  109. // 统计订单金额
  110. $order['amount_real'] = $order['amount_goods'] - $order['amount_reduct'];
  111. $order['amount_total'] = $order['amount_goods'];
  112. // 写入订单商品数据
  113. $this->app->db->name('ShopOrder')->insert($order);
  114. $this->app->db->name('ShopOrderItem')->insertAll($items);
  115. // 同步商品库存销量
  116. foreach ($codes as $code) GoodsService::instance()->syncStock($code);
  117. // 触发订单创建事件
  118. $this->app->event->trigger('ShopOrderCreate', $order['order_no']);
  119. // 组装订单商品数据
  120. $order['items'] = $items;
  121. // 返回处理成功数据
  122. $this->success('商品下单成功', $order);
  123. } catch (HttpResponseException $exception) {
  124. throw $exception;
  125. } catch (\Exception $exception) {
  126. $this->error("商品下单失败,{$exception->getMessage()}");
  127. }
  128. }
  129. /**
  130. * 模拟计算订单运费
  131. * @throws \think\db\exception\DataNotFoundException
  132. * @throws \think\db\exception\DbException
  133. * @throws \think\db\exception\ModelNotFoundException
  134. */
  135. public function express()
  136. {
  137. $data = $this->_vali([
  138. 'code.require' => '地址不能为空',
  139. 'order_no.require' => '单号不能为空',
  140. ]);
  141. // 用户收货地址
  142. $map = ['uid' => $this->uuid, 'code' => $data['code']];
  143. $addr = $this->app->db->name('DataUserAddress')->where($map)->find();
  144. if (empty($addr)) $this->error('收货地址异常');
  145. // 订单状态检查
  146. $map = ['uid' => $this->uuid, 'order_no' => $data['order_no']];
  147. $tCount = $this->app->db->name('ShopOrderItem')->where($map)->sum('truck_count');
  148. // 根据地址计算运费
  149. $map = ['status' => 1, 'deleted' => 0, 'order_no' => $data['order_no']];
  150. $tCode = $this->app->db->name('ShopOrderItem')->where($map)->column('truck_tcode');
  151. [$amount, , , $remark] = TruckService::instance()->amount($tCode, $addr['province'], $addr['city'], $tCount);
  152. $this->success('计算运费成功', ['amount' => $amount, 'remark' => $remark]);
  153. }
  154. /**
  155. * 订单信息完成
  156. * @throws \think\db\exception\DataNotFoundException
  157. * @throws \think\db\exception\DbException
  158. * @throws \think\db\exception\ModelNotFoundException
  159. */
  160. public function perfect()
  161. {
  162. $data = $this->_vali([
  163. 'code.require' => '地址不能为空',
  164. 'order_no.require' => '单号不能为空',
  165. ]);
  166. // 用户收货地址
  167. $map = ['uid' => $this->uuid, 'code' => $data['code'], 'deleted' => 0];
  168. $addr = $this->app->db->name('DataUserAddress')->where($map)->find();
  169. if (empty($addr)) $this->error('收货地址异常');
  170. // 订单状态检查
  171. $map = ['uid' => $this->uuid, 'order_no' => $data['order_no']];
  172. $order = $this->app->db->name('ShopOrder')->where($map)->whereIn('status', [1, 2])->find();
  173. $tCount = $this->app->db->name('ShopOrderItem')->where($map)->sum('truck_count');
  174. if (empty($order)) $this->error('不能修改地址');
  175. // 根据地址计算运费
  176. $map = ['status' => 1, 'deleted' => 0, 'order_no' => $data['order_no']];
  177. $tCodes = $this->app->db->name('ShopOrderItem')->where($map)->column('truck_tcode');
  178. [$amount, $tCount, $tCode, $remark] = TruckService::instance()->amount($tCodes, $addr['province'], $addr['city'], $tCount);
  179. // 创建订单发货信息
  180. $express = [
  181. 'template_code' => $tCode, 'template_count' => $tCount, 'uid' => $this->uuid,
  182. 'template_remark' => $remark, 'template_amount' => $amount, 'status' => 1,
  183. ];
  184. $express['order_no'] = $data['order_no'];
  185. $express['address_code'] = $data['code'];
  186. $express['address_name'] = $addr['name'];
  187. $express['address_phone'] = $addr['phone'];
  188. $express['address_idcode'] = $addr['idcode'];
  189. $express['address_province'] = $addr['province'];
  190. $express['address_city'] = $addr['city'];
  191. $express['address_area'] = $addr['area'];
  192. $express['address_content'] = $addr['address'];
  193. $express['address_datetime'] = date('Y-m-d H:i:s');
  194. data_save('ShopOrderSend', $express, 'order_no');
  195. // 组装更新订单数据
  196. $update = ['status' => 2, 'amount_express' => $express['template_amount']];
  197. // 重新计算订单金额
  198. $update['amount_real'] = $order['amount_goods'] + $amount - $order['amount_reduct'] - $order['amount_discount'];
  199. $update['amount_total'] = $order['amount_goods'] + $amount;
  200. // 支付金额不能为零
  201. if ($update['amount_real'] <= 0) $update['amount_real'] = 0.00;
  202. if ($update['amount_total'] <= 0) $update['amount_total'] = 0.00;
  203. // 更新用户订单数据
  204. $map = ['uid' => $this->uuid, 'order_no' => $data['order_no']];
  205. if ($this->app->db->name('ShopOrder')->where($map)->update($update) !== false) {
  206. // 触发订单确认事件
  207. $this->app->event->trigger('ShopOrderPerfect', $order['order_no']);
  208. // 返回处理成功数据
  209. $this->success('订单确认成功', ['order_no' => $order['order_no']]);
  210. } else {
  211. $this->error('订单确认失败');
  212. }
  213. }
  214. /**
  215. * 获取订单支付状态
  216. * @throws \think\db\exception\DataNotFoundException
  217. * @throws \think\db\exception\DbException
  218. * @throws \think\db\exception\ModelNotFoundException
  219. */
  220. public function payment()
  221. {
  222. $data = $this->_vali([
  223. 'order_no.require' => '单号不能为空',
  224. 'payment_code.require' => '参数不能为空',
  225. 'payment_back.default' => '', # 支付回跳地址
  226. ]);
  227. $map = ['order_no' => $data['order_no']];
  228. $order = $this->app->db->name('ShopOrder')->where($map)->find();
  229. if (empty($order)) $this->error('读取订单失败');
  230. if ($order['status'] != 2) $this->error('不能发起支付');
  231. if ($order['payment_status'] > 0) $this->error('已经完成支付');
  232. try {
  233. $openid = '';
  234. if (in_array($this->type, [UserService::APITYPE_WXAPP, UserService::APITYPE_WECHAT])) {
  235. $openid = $this->user[UserService::TYPES[$this->type]['auth']] ?? '';
  236. if (empty($openid)) $this->error("无法创建支付");
  237. }
  238. // 返回订单数据及支付发起参数
  239. $type = $order['amount_real'] <= 0 ? 'empty' : $data['payment_code'];
  240. $param = PaymentService::instance($type)->create($openid, $order['order_no'], $order['amount_real'], '商城订单支付', '', $data['payment_back']);
  241. $order = $this->app->db->name('ShopOrder')->where($map)->find() ?: new \stdClass();
  242. $this->success('获取支付参数', ['order' => $order, 'param' => $param]);
  243. } catch (HttpResponseException $exception) {
  244. throw $exception;
  245. } catch (\Exception $exception) {
  246. $this->error($exception->getMessage());
  247. }
  248. }
  249. /**
  250. * 主动取消未支付的订单
  251. * @throws \think\db\exception\DataNotFoundException
  252. * @throws \think\db\exception\DbException
  253. * @throws \think\db\exception\ModelNotFoundException
  254. */
  255. public function cancel()
  256. {
  257. $map = $this->_vali([
  258. 'uid.value' => $this->uuid,
  259. 'order_no.require' => '单号不能为空',
  260. ]);
  261. $order = $this->app->db->name('ShopOrder')->where($map)->find();
  262. if (empty($order)) $this->error('读取订单失败');
  263. if (in_array($order['status'], [1, 2])) {
  264. $result = $this->app->db->name('ShopOrder')->where($map)->update([
  265. 'status' => 0,
  266. 'cancel_status' => 1,
  267. 'cancel_remark' => '用户主动取消订单!',
  268. 'cancel_datetime' => date('Y-m-d H:i:s'),
  269. ]);
  270. if ($result !== false && OrderService::instance()->syncStock($order['order_no'])) {
  271. // 触发订单取消事件
  272. $this->app->event->trigger('ShopOrderCancel', $order['order_no']);
  273. // 返回处理成功数据
  274. $this->success('订单取消成功');
  275. } else {
  276. $this->error('订单取消失败');
  277. }
  278. } else {
  279. $this->error('订单不可取消');
  280. }
  281. }
  282. /**
  283. * 用户主动删除已取消的订单
  284. * @throws \think\db\exception\DataNotFoundException
  285. * @throws \think\db\exception\DbException
  286. * @throws \think\db\exception\ModelNotFoundException
  287. */
  288. public function remove()
  289. {
  290. $map = $this->_vali([
  291. 'uid.value' => $this->uuid,
  292. 'order_no.require' => '单号不能为空',
  293. ]);
  294. $order = $this->app->db->name('ShopOrder')->where($map)->find();
  295. if (empty($order)) $this->error('读取订单失败');
  296. if (in_array($order['status'], [0])) {
  297. $result = $this->app->db->name('ShopOrder')->where($map)->update([
  298. 'status' => 0,
  299. 'deleted' => 1,
  300. 'deleted_remark' => '用户主动删除订单!',
  301. 'deleted_datetime' => date('Y-m-d H:i:s'),
  302. ]);
  303. if ($result !== false) {
  304. // 触发订单删除事件
  305. $this->app->event->trigger('ShopOrderRemove', $order['order_no']);
  306. // 返回处理成功数据
  307. $this->success('订单删除成功');
  308. } else {
  309. $this->error('订单删除失败');
  310. }
  311. } else {
  312. $this->error('订单不可删除');
  313. }
  314. }
  315. /**
  316. * 订单确认收货
  317. * @throws \think\db\exception\DataNotFoundException
  318. * @throws \think\db\exception\DbException
  319. * @throws \think\db\exception\ModelNotFoundException
  320. */
  321. public function confirm()
  322. {
  323. $map = $this->_vali([
  324. 'uid.value' => $this->uuid,
  325. 'order_no.require' => '单号不能为空',
  326. ]);
  327. $order = $this->app->db->name('ShopOrder')->where($map)->find();
  328. if (empty($order)) $this->error('读取订单失败');
  329. if (in_array($order['status'], [4])) {
  330. if ($this->app->db->name('ShopOrder')->where($map)->update(['status' => 5]) !== false) {
  331. // 触发订单确认事件
  332. $this->app->event->trigger('ShopOrderConfirm', $order['order_no']);
  333. // 返回处理成功数据
  334. $this->success('订单确认成功');
  335. } else {
  336. $this->error('订单确认失败');
  337. }
  338. } else {
  339. $this->error('订单确认失败');
  340. }
  341. }
  342. /**
  343. * 订单状态统计
  344. * @throws \think\db\exception\DataNotFoundException
  345. * @throws \think\db\exception\DbException
  346. * @throws \think\db\exception\ModelNotFoundException
  347. */
  348. public function total()
  349. {
  350. $map = ['uid' => $this->uuid, 'deleted' => 0];
  351. $data = ['t0' => 0, 't1' => 0, 't2' => 0, 't3' => 0, 't4' => 0, 't5' => 0];
  352. $query = $this->app->db->name('ShopOrder')->fieldRaw('status,count(1) count');
  353. $query->where($map)->group('status')->select()->each(function ($item) use (&$data) {
  354. $data["t{$item['status']}"] = $item['count'];
  355. });
  356. $this->success('获取统计成功', $data);
  357. }
  358. /**
  359. * 物流追踪查询
  360. */
  361. public function track()
  362. {
  363. try {
  364. $data = $this->_vali([
  365. 'code.require' => '快递不能为空',
  366. 'number.require' => '单号不能为空',
  367. ]);
  368. $result = TruckService::instance()->query($data['code'], $data['number']);
  369. empty($result['code']) ? $this->error($result['info']) : $this->success('快递追踪信息', $result);
  370. } catch (HttpResponseException $exception) {
  371. throw $exception;
  372. } catch (\Exception $exception) {
  373. $this->error($exception->getMessage());
  374. }
  375. }
  376. }