// +---------------------------------------------------------------------- declare (strict_types=1); namespace app\store\model; use app\api\service\User as UserService; use app\common\enum\payment\Method; use app\common\model\Order as OrderModel; use app\common\service\Order as OrderService; use app\common\service\order\Refund as RefundService; use app\common\service\order\Printer as PrinterService; use app\common\enum\order\{DataType as DataTypeEnum, DeliveryType, PayStatus as PayStatusEnum, OrderStatus as OrderStatusEnum, ReceiptStatus as ReceiptStatusEnum, DeliveryStatus as DeliveryStatusEnum}; use app\common\library\helper; use cores\exception\BaseException; /** * 订单管理 * Class Order * @package app\store\model */ class Order extends OrderModel { /** * 订单详情页数据 * @param int $orderId * @return Order|array|null */ public function getDetail(int $orderId) { $order = static::detail($orderId, [ 'goods.image', 'delivery' => ['goods', 'express'], 'extract_shop.logoImage', 'extract_clerk', 'trade', ]); // 附加数据 static::related($order, ['user', 'address', 'express', 'extract']); return $order; } /** * 订单列表 * @param array $param * @return mixed */ public function getList(array $param = []) { // 检索查询条件 $filter = $this->getQueryFilter($param); $filterOr = []; if (!empty($param['searchValue']) && $param['searchType'] == 'all') { $filterOr = [ ['order.order_no', 'like', "%{$param['searchValue']}%"], ['user.nick_name', 'like', "%{$param['searchValue']}%"], ['address.name', 'like', "%{$param['searchValue']}%"], ['address.phone', 'like', "%{$param['searchValue']}%"], ]; } // 设置订单类型条件 $dataTypeFilter = $this->getFilterDataType($param['dataType']); // 获取数据列表 $query = $this->with(['goods.image', 'user.avatar', 'address']) ->alias('order') ->field('order.*') ->leftJoin('user', 'user.user_id = order.user_id') ->leftJoin('order_address address', 'address.order_id = order.order_id') ->where($dataTypeFilter) ->where($filter) ->where('order.is_delete', '=', 0); if (!empty($filterOr)) { $query = $query->whereOr($filterOr); } $list = $query->order(['order.create_time' => 'desc']) ->paginate(10); return $list; } /** * 订单列表 (API调用) * @param array $param * @return mixed */ public function getNewList(array $param = []) { // 检索查询条件 $filter = $this->getQueryFilter($param); //不是店长查询当前用户订单 if(!UserService::isStore()) { $filter[] = ['user.user_id' ,'=', UserService::getCurrentLoginUserId() ]; } $filterOr = []; if (!empty($param['searchValue']) && $param['searchType'] == 'all') { // $filterOr = [ // ['order.order_no', 'like', "%{$param['searchValue']}%"], // ['user.nick_name', 'like', "%{$param['searchValue']}%"], // ['address.name', 'like', "%{$param['searchValue']}%"], // ['address.phone', 'like', "%{$param['searchValue']}%"], // ]; $filterOr = [ ['order.order_no|user.nick_name|address.name|address.phone', 'like', "%{$param['searchValue']}%"] ]; } // 设置订单类型条件 $dataTypeFilter = $this->getFilterDataType($param['dataType']); // 获取数据列表 $query = $this ->alias('order') ->field('order.*') ->leftJoin('user', 'user.user_id = order.user_id') ->leftJoin('order_address address', 'address.order_id = order.order_id') ->where($dataTypeFilter) ->where($filter) ->where('order.is_delete', '=', 0); if (!empty($filterOr)) { // $query = $query->whereOr($filterOr); $query = $query->where($filterOr); } // 加载关联订单数据 $list = $query->order(['order.create_time' => 'desc']) ->paginate(10); $list = static::preload($list, ['goods.image', 'user.avatar', 'address', 'delivery'], true); return $list; } /** * 订单列表(全部) * @param array $param * @return iterable|\think\model\Collection|\think\Paginator */ public function getListAll(array $param = []) { // 检索查询条件 $queryFilter = $this->getQueryFilter($param); // 设置订单类型条件 $dataTypeFilter = $this->getFilterDataType($param['dataType']); // 获取数据列表 $orderList = $this->alias('order') ->field('order.*') ->join('user', 'user.user_id = order.user_id') ->where($dataTypeFilter) ->where($queryFilter) ->where('order.is_delete', '=', 0) ->order(['order.create_time' => 'desc']) ->select(); // 加载订单关联数据 return static::preload($orderList, ['goods.image', 'address', 'user.avatar', 'express', 'extract', 'extract_shop']); } /** * 设置检索查询条件 * @param array $param * @return array */ private function getQueryFilter(array $param): array { // 默认参数 $params = $this->setQueryDefaultValue($param, [ 'searchType' => '', // 关键词类型 (10订单号 20会员昵称 30会员ID 40收货人姓名 50收货人电话) 'searchValue' => '', // 关键词内容 'orderSource' => -1, // 订单来源 'payMethod' => '', // 支付方式 'deliveryType' => -1, // 配送方式 'extractShopId' => 0, // 自提门店ID 'betweenTime' => [], // 起止时间 'userId' => 0, // 会员ID ]); // 检索查询条件 $filter = []; // 关键词 if (!empty($params['searchValue'])) { if ($params['searchType'] != 'all') { $searchWhere = [ 10 => ['order.order_no', 'like', "%{$params['searchValue']}%"], 20 => ['user.nick_name', 'like', "%{$params['searchValue']}%"], 30 => ['order.user_id', '=', (int)$params['searchValue']], 40 => ['address.name', 'like', "%{$params['searchValue']}%"], 50 => ['address.phone', 'like', "%{$params['searchValue']}%"], ]; array_key_exists($params['searchType'], $searchWhere) && $filter[] = $searchWhere[$params['searchType']]; } } // 起止时间 if (!empty($params['betweenTime'])) { $betweenTime = explode(',', $params['betweenTime']); $times = between_time($betweenTime); $filter[] = ['order.create_time', '>=', $times['start_time']]; $filter[] = ['order.create_time', '<', $times['end_time'] + 86400]; } // 订单来源 $params['orderSource'] > -1 && $filter[] = ['order_source', '=', (int)$params['orderSource']]; // 支付方式 !empty($params['payMethod']) && $filter[] = ['pay_method', '=', $params['payMethod']]; // 配送方式 $params['deliveryType'] > -1 && $filter[] = ['delivery_type', '=', (int)$params['deliveryType']]; // 自提门店id $params['extractShopId'] > 0 && $filter[] = ['extract_shop_id', '=', (int)$params['extractShopId']]; // 会员ID $params['userId'] > 0 && $filter[] = ['order.user_id', '=', (int)$params['userId']]; return $filter; } /** * 设置订单类型条件 * @param string $dataType * @return array */ private function getFilterDataType(string $dataType): array { // 数据类型 $filter = []; switch ($dataType) { case DataTypeEnum::ALL: break; case DataTypeEnum::PAY: $filter[] = ['pay_status', '=', PayStatusEnum::PENDING]; $filter[] = ['order_status', '=', OrderStatusEnum::NORMAL]; break; case DataTypeEnum::DELIVERY: $filter = [ ['pay_status', '=', PayStatusEnum::SUCCESS], ['delivery_status', '<>', DeliveryStatusEnum::DELIVERED], // ['order_status', 'in', [OrderStatusEnum::NORMAL, OrderStatusEnum::APPLY_CANCEL]] ['order_status', 'in', [OrderStatusEnum::NORMAL]] ]; break; case DataTypeEnum::RECEIPT: $filter = [ ['pay_status', '=', PayStatusEnum::SUCCESS], ['delivery_status', '=', DeliveryStatusEnum::DELIVERED], ['receipt_status', '=', ReceiptStatusEnum::NOT_RECEIVED] ]; break; case DataTypeEnum::COMPLETE: $filter[] = ['order_status', '=', OrderStatusEnum::COMPLETED]; break; case DataTypeEnum::APPLY_CANCEL: $filter[] = ['order_status', '=', OrderStatusEnum::APPLY_CANCEL]; break; case DataTypeEnum::CANCEL: $filter[] = ['order_status', '=', OrderStatusEnum::CANCELLED]; break; } return $filter; } /** * 修改订单价格 * @param array $data * @return bool */ public function updatePrice(array $data): bool { if ($this['pay_status'] != PayStatusEnum::PENDING) { // $this->error = '该订单不合法'; $this->error = '该订单已支付,无法修改价格'; return false; } // 实际付款金额 $payPrice = helper::bcadd($data['order_price'], $data['express_price']); if ($payPrice <= 0) { $this->error = '订单实付款价格不能为0.00元'; return false; } // 改价的金额差价 $updatePrice = helper::bcsub($data['order_price'], $this['order_price']); // 更新订单记录 return $this->save([ 'order_no' => $this->orderNo(), // 修改订单号, 否则微信支付提示重复 'pay_price' => $payPrice, 'update_price' => $updatePrice, 'express_price' => $data['express_price'] ]) !== false; } /** * 修改收货地址 * @param array $data * @return bool */ public function updateAddress(array $data): bool { if ($this['pay_status'] != PayStatusEnum::SUCCESS || $this['delivery_status'] == DeliveryStatusEnum::DELIVERED || $this['delivery_type'] != 10) { $this->error = "订单号[{$this['order_no']}]不满足修改条件!"; return false; } if (empty($data['region']) || empty($data['name']) || empty($data['phone'])) { $this->error = "请补全地址信息!"; return false; } $update = [ 'name' => $data['name'], 'phone' => $data['phone'], 'province_id' => $data['region'][0]['value'], 'city_id' => $data['region'][1]['value'], 'region_id' => $data['region'][2]['value'], 'detail' => $data['detail'], ]; return (bool)OrderAddress::where(['order_id' => $this['order_id']])->update($update); } /** * 修改物流信息 * @param array $data * @return bool */ public function updateDelivery(array $data): bool { if ($this['pay_status'] != PayStatusEnum::SUCCESS || $this['delivery_status'] == DeliveryStatusEnum::DELIVERED || $this['delivery_type'] != 10) { $this->error = "订单号[{$this['order_no']}]不满足修改条件!"; return false; } if (empty($data['express_id']) || empty($data['express_no'])) { $this->error = "请补全物流信息!"; return false; } $update = [ 'express_id' => $data['express_id'], 'express_no' => $data['express_no'], ]; return (bool)\app\common\model\order\Delivery::where(['order_id' => $this['order_id']])->update($update); } /** * 修改商家备注 * @param array $data * @return bool */ public function updateRemark(array $data): bool { return $this->save(['merchant_remark' => $data['content'] ?? '']); } /** * 小票打印 * @param array $data * @return bool * @throws BaseException */ public function printer(array $data): bool { // 实例化打印机驱动 $Printer = new PrinterService; // 手动打印小票 $status = $Printer->printEvent($this, $data['printerId']); if ($status === false) { $this->error = $Printer->getError(); } return $status; } /** * 审核:用户取消订单 * @param array $data * @return bool|mixed */ public function confirmCancel(array $data) { // 判断订单是否有效 if ( $this['pay_status'] != PayStatusEnum::SUCCESS || $this['order_status'] != OrderStatusEnum::APPLY_CANCEL ) { $this->error = '该订单不合法'; return false; } // 订单取消事件 return $this->transaction(function () use ($data) { if ($data['status']) { // 执行退款操作 if (!(new RefundService)->handle($this)) { throwError('执行订单退款失败'); } // 订单取消事件 OrderService::cancelEvent($this); } // 更新订单状态 return $this->save([ 'order_status' => $data['status'] ? OrderStatusEnum::CANCELLED : OrderStatusEnum::NORMAL, 'remark' => $data['remark'] ?? '', ]); }); } /** * 自提核销事件 (管理员) * @param array $param * @return bool|int */ public function extractEvent(array $param) { // 设置默认参数 $param = $this->setQueryDefaultValue($param, [ 'clerkId' => null, 'syncMpWeixinShipping' => 1, ]); return $this->confirmExtract((int)$param['clerkId'], (bool)$param['syncMpWeixinShipping']); } /** * 将订单记录设置为已删除 * @return bool */ public function setDelete(): bool { return $this->save(['is_delete' => 1]); } /** * 获取已付款订单总数 (可指定某天) * @param null $startDate * @param null $endDate * @return int */ public function getPayOrderTotal($startDate = null, $endDate = null): int { $filter = [ ['pay_status', '=', PayStatusEnum::SUCCESS], ['order_status', '<>', OrderStatusEnum::CANCELLED] ]; if (!is_null($startDate) && !is_null($endDate)) { $filter[] = ['pay_time', '>=', strtotime($startDate)]; $filter[] = ['pay_time', '<', strtotime($endDate) + 86400]; } return $this->getOrderTotal($filter); } /** * 获取未发货订单数量 * @return int */ public function getNotDeliveredOrderTotal(): int { $filter = [ ['pay_status', '=', PayStatusEnum::SUCCESS], ['delivery_status', '<>', DeliveryStatusEnum::DELIVERED], ['order_status', 'in', [OrderStatusEnum::NORMAL, OrderStatusEnum::APPLY_CANCEL]] ]; return $this->getOrderTotal($filter); } /** * 获取未付款订单数量 * @return int */ public function getNotPayOrderTotal(): int { $filter = [ ['pay_status', '=', PayStatusEnum::PENDING], ['order_status', '=', OrderStatusEnum::NORMAL] ]; return $this->getOrderTotal($filter); } /** * 获取订单总数 * @param array $filter * @return int */ private function getOrderTotal(array $filter = []): int { // 获取订单总数量 return $this->where($filter) ->where('is_delete', '=', 0) ->count(); } /** * 获取某天的总销售额 * @param null $startDate * @param null $endDate * @return float */ public function getOrderTotalPrice($startDate = null, $endDate = null): float { // 查询对象 $query = $this->getNewQuery(); // 设置查询条件 if (!is_null($startDate) && !is_null($endDate)) { $query->where('pay_time', '>=', strtotime($startDate)) ->where('pay_time', '<', strtotime($endDate) + 86400); } // 总销售额 return $query->where('pay_status', '=', PayStatusEnum::SUCCESS) ->where('order_status', '<>', OrderStatusEnum::CANCELLED) ->where('is_delete', '=', 0) ->sum('pay_price'); } /** * 获取某天的下单用户数 * @param string $day * @return float|int */ public function getPayOrderUserTotal(string $day) { $startTime = strtotime($day); return $this->field('user_id') ->where('pay_time', '>=', $startTime) ->where('pay_time', '<', $startTime + 86400) ->where('pay_status', '=', PayStatusEnum::SUCCESS) ->where('is_delete', '=', '0') ->group('user_id') ->count(); } /** * 根据订单号获取ID集 * @param array $orderNoArr * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public static function getOrderIds(array $orderNoArr): array { $list = (new static)->where('order_no', 'in', $orderNoArr)->select(); $data = []; foreach ($list as $item) { $data[$item['order_no']] = $item['order_id']; } return $data; } }