Order.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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_no' => $this->orderNo(), // 修改订单号, 否则微信支付提示重复
  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. */
  222. public function printer(array $data): bool
  223. {
  224. // 实例化打印机驱动
  225. $Printer = new PrinterService;
  226. // 手动打印小票
  227. $status = $Printer->printEvent($this, $data['printerId']);
  228. if ($status === false) {
  229. $this->error = $Printer->getError();
  230. }
  231. return $status;
  232. }
  233. /**
  234. * 审核:用户取消订单
  235. * @param array $data
  236. * @return bool|mixed
  237. */
  238. public function confirmCancel(array $data)
  239. {
  240. // 判断订单是否有效
  241. if (
  242. $this['pay_status'] != PayStatusEnum::SUCCESS
  243. || $this['order_status'] != OrderStatusEnum::APPLY_CANCEL
  244. ) {
  245. $this->error = '该订单不合法';
  246. return false;
  247. }
  248. // 订单取消事件
  249. return $this->transaction(function () use ($data) {
  250. if ($data['status']) {
  251. // 执行退款操作
  252. if (!(new RefundService)->handle($this)) {
  253. throwError('执行订单退款失败');
  254. }
  255. // 订单取消事件
  256. OrderService::cancelEvent($this);
  257. }
  258. // 更新订单状态
  259. return $this->save([
  260. 'order_status' => $data['status'] ? OrderStatusEnum::CANCELLED : OrderStatusEnum::NORMAL
  261. ]);
  262. });
  263. }
  264. /**
  265. * 将订单记录设置为已删除
  266. * @return bool
  267. */
  268. public function setDelete(): bool
  269. {
  270. return $this->save(['is_delete' => 1]);
  271. }
  272. /**
  273. * 获取已付款订单总数 (可指定某天)
  274. * @param null $startDate
  275. * @param null $endDate
  276. * @return int
  277. */
  278. public function getPayOrderTotal($startDate = null, $endDate = null): int
  279. {
  280. $filter = [
  281. ['pay_status', '=', PayStatusEnum::SUCCESS],
  282. ['order_status', '<>', OrderStatusEnum::CANCELLED]
  283. ];
  284. if (!is_null($startDate) && !is_null($endDate)) {
  285. $filter[] = ['pay_time', '>=', strtotime($startDate)];
  286. $filter[] = ['pay_time', '<', strtotime($endDate) + 86400];
  287. }
  288. return $this->getOrderTotal($filter);
  289. }
  290. /**
  291. * 获取未发货订单数量
  292. * @return int
  293. */
  294. public function getNotDeliveredOrderTotal(): int
  295. {
  296. $filter = [
  297. ['pay_status', '=', PayStatusEnum::SUCCESS],
  298. ['delivery_status', '<>', DeliveryStatusEnum::DELIVERED],
  299. ['order_status', 'in', [OrderStatusEnum::NORMAL, OrderStatusEnum::APPLY_CANCEL]]
  300. ];
  301. return $this->getOrderTotal($filter);
  302. }
  303. /**
  304. * 获取未付款订单数量
  305. * @return int
  306. */
  307. public function getNotPayOrderTotal(): int
  308. {
  309. $filter = [
  310. ['pay_status', '=', PayStatusEnum::PENDING],
  311. ['order_status', '=', OrderStatusEnum::NORMAL]
  312. ];
  313. return $this->getOrderTotal($filter);
  314. }
  315. /**
  316. * 获取订单总数
  317. * @param array $filter
  318. * @return int
  319. */
  320. private function getOrderTotal(array $filter = []): int
  321. {
  322. // 获取订单总数量
  323. return $this->where($filter)
  324. ->where('is_delete', '=', 0)
  325. ->count();
  326. }
  327. /**
  328. * 获取某天的总销售额
  329. * @param null $startDate
  330. * @param null $endDate
  331. * @return float
  332. */
  333. public function getOrderTotalPrice($startDate = null, $endDate = null): float
  334. {
  335. // 查询对象
  336. $query = $this->getNewQuery();
  337. // 设置查询条件
  338. if (!is_null($startDate) && !is_null($endDate)) {
  339. $query->where('pay_time', '>=', strtotime($startDate))
  340. ->where('pay_time', '<', strtotime($endDate) + 86400);
  341. }
  342. // 总销售额
  343. return $query->where('pay_status', '=', PayStatusEnum::SUCCESS)
  344. ->where('order_status', '<>', OrderStatusEnum::CANCELLED)
  345. ->where('is_delete', '=', 0)
  346. ->sum('pay_price');
  347. }
  348. /**
  349. * 获取某天的下单用户数
  350. * @param string $day
  351. * @return float|int
  352. */
  353. public function getPayOrderUserTotal(string $day)
  354. {
  355. $startTime = strtotime($day);
  356. return $this->field('user_id')
  357. ->where('pay_time', '>=', $startTime)
  358. ->where('pay_time', '<', $startTime + 86400)
  359. ->where('pay_status', '=', PayStatusEnum::SUCCESS)
  360. ->where('is_delete', '=', '0')
  361. ->group('user_id')
  362. ->count();
  363. }
  364. /**
  365. * 根据订单号获取ID集
  366. * @param array $orderNoArr
  367. * @return array
  368. * @throws \think\db\exception\DataNotFoundException
  369. * @throws \think\db\exception\DbException
  370. * @throws \think\db\exception\ModelNotFoundException
  371. */
  372. public static function getOrderIds(array $orderNoArr): array
  373. {
  374. $list = (new static)->where('order_no', 'in', $orderNoArr)->select();
  375. $data = [];
  376. foreach ($list as $item) {
  377. $data[$item['order_no']] = $item['order_id'];
  378. }
  379. return $data;
  380. }
  381. }