Order.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2017~2024 https://www.yiovo.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
  8. // +----------------------------------------------------------------------
  9. // | Author: 萤火科技 <admin@yiovo.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\store\model;
  13. use app\common\model\Order as OrderModel;
  14. use app\common\service\Order as OrderService;
  15. use app\common\service\order\Refund as RefundService;
  16. use app\common\service\order\Printer as PrinterService;
  17. use app\common\enum\order\{
  18. DataType as DataTypeEnum,
  19. PayStatus as PayStatusEnum,
  20. OrderStatus as OrderStatusEnum,
  21. ReceiptStatus as ReceiptStatusEnum,
  22. DeliveryStatus as DeliveryStatusEnum
  23. };
  24. use app\common\library\helper;
  25. use cores\exception\BaseException;
  26. /**
  27. * 订单管理
  28. * Class Order
  29. * @package app\store\model
  30. */
  31. class Order extends OrderModel
  32. {
  33. /**
  34. * 订单详情页数据
  35. * @param int $orderId
  36. * @return Order|array|null
  37. */
  38. public function getDetail(int $orderId)
  39. {
  40. return static::detail($orderId, [
  41. 'user', 'address', 'express',
  42. 'goods.image',
  43. 'delivery' => ['goods', 'express'],
  44. 'trade',
  45. ]);
  46. }
  47. /**
  48. * 订单列表
  49. * @param array $param
  50. * @return mixed
  51. */
  52. public function getList(array $param = [])
  53. {
  54. // 检索查询条件
  55. $filter = $this->getQueryFilter($param);
  56. // 设置订单类型条件
  57. $dataTypeFilter = $this->getFilterDataType($param['dataType']);
  58. // 获取数据列表
  59. return $this->with(['goods.image', 'user.avatar', 'address'])
  60. ->alias('order')
  61. ->field('order.*')
  62. ->leftJoin('user', 'user.user_id = order.user_id')
  63. ->leftJoin('order_address address', 'address.order_id = order.order_id')
  64. ->where($dataTypeFilter)
  65. ->where($filter)
  66. ->where('order.is_delete', '=', 0)
  67. ->order(['order.create_time' => 'desc'])
  68. ->paginate(10);
  69. }
  70. /**
  71. * 订单列表(全部)
  72. * @param array $param
  73. * @return iterable|\think\model\Collection|\think\Paginator
  74. */
  75. public function getListAll(array $param = [])
  76. {
  77. // 检索查询条件
  78. $queryFilter = $this->getQueryFilter($param);
  79. // 设置订单类型条件
  80. $dataTypeFilter = $this->getFilterDataType($param['dataType']);
  81. // 获取数据列表
  82. return $this->with(['goods.image', 'address', 'user.avatar', 'express'])
  83. ->alias('order')
  84. ->field('order.*')
  85. ->join('user', 'user.user_id = order.user_id')
  86. ->where($dataTypeFilter)
  87. ->where($queryFilter)
  88. ->where('order.is_delete', '=', 0)
  89. ->order(['order.create_time' => 'desc'])
  90. ->select();
  91. }
  92. /**
  93. * 设置检索查询条件
  94. * @param array $param
  95. * @return array
  96. */
  97. private function getQueryFilter(array $param): array
  98. {
  99. // 默认参数
  100. $params = $this->setQueryDefaultValue($param, [
  101. 'searchType' => '', // 关键词类型 (10订单号 20会员昵称 30会员ID 40收货人姓名 50收货人电话)
  102. 'searchValue' => '', // 关键词内容
  103. 'orderSource' => -1, // 订单来源
  104. 'payMethod' => '', // 支付方式
  105. 'deliveryType' => -1, // 配送方式
  106. 'betweenTime' => [], // 起止时间
  107. 'userId' => 0, // 会员ID
  108. ]);
  109. // 检索查询条件
  110. $filter = [];
  111. // 关键词
  112. if (!empty($params['searchValue'])) {
  113. $searchWhere = [
  114. 10 => ['order.order_no', 'like', "%{$params['searchValue']}%"],
  115. 20 => ['user.nick_name', 'like', "%{$params['searchValue']}%"],
  116. 30 => ['order.user_id', '=', (int)$params['searchValue']],
  117. 40 => ['address.name', 'like', "%{$params['searchValue']}%"],
  118. 50 => ['address.phone', 'like', "%{$params['searchValue']}%"],
  119. ];
  120. array_key_exists($params['searchType'], $searchWhere) && $filter[] = $searchWhere[$params['searchType']];
  121. }
  122. // 起止时间
  123. if (!empty($params['betweenTime'])) {
  124. $times = between_time($params['betweenTime']);
  125. $filter[] = ['order.create_time', '>=', $times['start_time']];
  126. $filter[] = ['order.create_time', '<', $times['end_time'] + 86400];
  127. }
  128. // 订单来源
  129. $params['orderSource'] > -1 && $filter[] = ['order_source', '=', (int)$params['orderSource']];
  130. // 支付方式
  131. !empty($params['payMethod']) && $filter[] = ['pay_method', '=', $params['payMethod']];
  132. // 配送方式
  133. $params['deliveryType'] > -1 && $filter[] = ['delivery_type', '=', (int)$params['deliveryType']];
  134. // 会员ID
  135. $params['userId'] > 0 && $filter[] = ['order.user_id', '=', (int)$params['userId']];
  136. return $filter;
  137. }
  138. /**
  139. * 设置订单类型条件
  140. * @param string $dataType
  141. * @return array
  142. */
  143. private function getFilterDataType(string $dataType): array
  144. {
  145. // 数据类型
  146. $filter = [];
  147. switch ($dataType) {
  148. case DataTypeEnum::ALL:
  149. break;
  150. case DataTypeEnum::PAY:
  151. $filter[] = ['pay_status', '=', PayStatusEnum::PENDING];
  152. $filter[] = ['order_status', '=', OrderStatusEnum::NORMAL];
  153. break;
  154. case DataTypeEnum::DELIVERY:
  155. $filter = [
  156. ['pay_status', '=', PayStatusEnum::SUCCESS],
  157. ['delivery_status', '<>', DeliveryStatusEnum::DELIVERED],
  158. ['order_status', 'in', [OrderStatusEnum::NORMAL, OrderStatusEnum::APPLY_CANCEL]]
  159. ];
  160. break;
  161. case DataTypeEnum::RECEIPT:
  162. $filter = [
  163. ['pay_status', '=', PayStatusEnum::SUCCESS],
  164. ['delivery_status', '=', DeliveryStatusEnum::DELIVERED],
  165. ['receipt_status', '=', ReceiptStatusEnum::NOT_RECEIVED]
  166. ];
  167. break;
  168. case DataTypeEnum::COMPLETE:
  169. $filter[] = ['order_status', '=', OrderStatusEnum::COMPLETED];
  170. break;
  171. case DataTypeEnum::APPLY_CANCEL:
  172. $filter[] = ['order_status', '=', OrderStatusEnum::APPLY_CANCEL];
  173. break;
  174. case DataTypeEnum::CANCEL:
  175. $filter[] = ['order_status', '=', OrderStatusEnum::CANCELLED];
  176. break;
  177. }
  178. return $filter;
  179. }
  180. /**
  181. * 修改订单价格
  182. * @param array $data
  183. * @return bool
  184. */
  185. public function updatePrice(array $data): bool
  186. {
  187. if ($this['pay_status'] != PayStatusEnum::PENDING) {
  188. $this->error = '该订单不合法';
  189. return false;
  190. }
  191. // 实际付款金额
  192. $payPrice = helper::bcadd($data['order_price'], $data['express_price']);
  193. if ($payPrice <= 0) {
  194. $this->error = '订单实付款价格不能为0.00元';
  195. return false;
  196. }
  197. // 改价的金额差价
  198. $updatePrice = helper::bcsub($data['order_price'], $this['order_price']);
  199. // 更新订单记录
  200. return $this->save([
  201. 'order_price' => $data['order_price'],
  202. 'pay_price' => $payPrice,
  203. 'update_price' => $updatePrice,
  204. 'express_price' => $data['express_price']
  205. ]) !== false;
  206. }
  207. /**
  208. * 修改商家备注
  209. * @param array $data
  210. * @return bool
  211. */
  212. public function updateRemark(array $data): bool
  213. {
  214. return $this->save(['merchant_remark' => $data['content'] ?? '']);
  215. }
  216. /**
  217. * 小票打印
  218. * @param array $data
  219. * @return bool
  220. * @throws BaseException
  221. * @throws \think\db\exception\DataNotFoundException
  222. * @throws \think\db\exception\DbException
  223. * @throws \think\db\exception\ModelNotFoundException
  224. */
  225. public function printer(array $data): bool
  226. {
  227. // 实例化打印机驱动
  228. $Printer = new PrinterService;
  229. // 手动打印小票
  230. $status = $Printer->printEvent($this, $data['printerId']);
  231. if ($status === false) {
  232. $this->error = $Printer->getError();
  233. }
  234. return $status;
  235. }
  236. /**
  237. * 审核:用户取消订单
  238. * @param array $data
  239. * @return bool|mixed
  240. */
  241. public function confirmCancel(array $data)
  242. {
  243. // 判断订单是否有效
  244. if (
  245. $this['pay_status'] != PayStatusEnum::SUCCESS
  246. || $this['order_status'] != OrderStatusEnum::APPLY_CANCEL
  247. ) {
  248. $this->error = '该订单不合法';
  249. return false;
  250. }
  251. // 订单取消事件
  252. return $this->transaction(function () use ($data) {
  253. if ($data['status']) {
  254. // 执行退款操作
  255. if (!(new RefundService)->handle($this)) {
  256. throwError('执行订单退款失败');
  257. }
  258. // 订单取消事件
  259. OrderService::cancelEvent($this);
  260. }
  261. // 更新订单状态
  262. return $this->save([
  263. 'order_status' => $data['status'] ? OrderStatusEnum::CANCELLED : OrderStatusEnum::NORMAL
  264. ]);
  265. });
  266. }
  267. /**
  268. * 将订单记录设置为已删除
  269. * @return bool
  270. */
  271. public function setDelete(): bool
  272. {
  273. return $this->save(['is_delete' => 1]);
  274. }
  275. /**
  276. * 获取已付款订单总数 (可指定某天)
  277. * @param null $startDate
  278. * @param null $endDate
  279. * @return int
  280. */
  281. public function getPayOrderTotal($startDate = null, $endDate = null): int
  282. {
  283. $filter = [
  284. ['pay_status', '=', PayStatusEnum::SUCCESS],
  285. ['order_status', '<>', OrderStatusEnum::CANCELLED]
  286. ];
  287. if (!is_null($startDate) && !is_null($endDate)) {
  288. $filter[] = ['pay_time', '>=', strtotime($startDate)];
  289. $filter[] = ['pay_time', '<', strtotime($endDate) + 86400];
  290. }
  291. return $this->getOrderTotal($filter);
  292. }
  293. /**
  294. * 获取未发货订单数量
  295. * @return int
  296. */
  297. public function getNotDeliveredOrderTotal(): int
  298. {
  299. $filter = [
  300. ['pay_status', '=', PayStatusEnum::SUCCESS],
  301. ['delivery_status', '<>', DeliveryStatusEnum::DELIVERED],
  302. ['order_status', 'in', [OrderStatusEnum::NORMAL, OrderStatusEnum::APPLY_CANCEL]]
  303. ];
  304. return $this->getOrderTotal($filter);
  305. }
  306. /**
  307. * 获取未付款订单数量
  308. * @return int
  309. */
  310. public function getNotPayOrderTotal(): int
  311. {
  312. $filter = [
  313. ['pay_status', '=', PayStatusEnum::PENDING],
  314. ['order_status', '=', OrderStatusEnum::NORMAL]
  315. ];
  316. return $this->getOrderTotal($filter);
  317. }
  318. /**
  319. * 获取订单总数
  320. * @param array $filter
  321. * @return int
  322. */
  323. private function getOrderTotal(array $filter = []): int
  324. {
  325. // 获取订单总数量
  326. return $this->where($filter)
  327. ->where('is_delete', '=', 0)
  328. ->count();
  329. }
  330. /**
  331. * 获取某天的总销售额
  332. * @param null $startDate
  333. * @param null $endDate
  334. * @return float
  335. */
  336. public function getOrderTotalPrice($startDate = null, $endDate = null): float
  337. {
  338. // 查询对象
  339. $query = $this->getNewQuery();
  340. // 设置查询条件
  341. if (!is_null($startDate) && !is_null($endDate)) {
  342. $query->where('pay_time', '>=', strtotime($startDate))
  343. ->where('pay_time', '<', strtotime($endDate) + 86400);
  344. }
  345. // 总销售额
  346. return $query->where('pay_status', '=', PayStatusEnum::SUCCESS)
  347. ->where('order_status', '<>', OrderStatusEnum::CANCELLED)
  348. ->where('is_delete', '=', 0)
  349. ->sum('pay_price');
  350. }
  351. /**
  352. * 获取某天的下单用户数
  353. * @param string $day
  354. * @return float|int
  355. */
  356. public function getPayOrderUserTotal(string $day)
  357. {
  358. $startTime = strtotime($day);
  359. return $this->field('user_id')
  360. ->where('pay_time', '>=', $startTime)
  361. ->where('pay_time', '<', $startTime + 86400)
  362. ->where('pay_status', '=', PayStatusEnum::SUCCESS)
  363. ->where('is_delete', '=', '0')
  364. ->group('user_id')
  365. ->count();
  366. }
  367. /**
  368. * 根据订单号获取ID集
  369. * @param array $orderNoArr
  370. * @return array
  371. * @throws \think\db\exception\DataNotFoundException
  372. * @throws \think\db\exception\DbException
  373. * @throws \think\db\exception\ModelNotFoundException
  374. */
  375. public static function getOrderIds(array $orderNoArr): array
  376. {
  377. $list = (new static)->where('order_no', 'in', $orderNoArr)->select();
  378. $data = [];
  379. foreach ($list as $item) {
  380. $data[$item['order_no']] = $item['order_id'];
  381. }
  382. return $data;
  383. }
  384. }