// +---------------------------------------------------------------------- declare (strict_types=1); namespace app\common\model; use app\common\enum\order\DeliveryStatus as DeliveryStatusEnum; use app\common\enum\order\DeliveryType; use app\common\enum\order\DeliveryType as DeliveryTypeEnum; use app\common\enum\order\OrderStatus as OrderStatusEnum; use app\common\enum\order\PayStatus as PayStatusEnum; use app\common\enum\order\ReceiptStatus as ReceiptStatusEnum; use app\common\enum\payment\Method; use app\common\library\helper; use app\common\model\store\shop\Order as ShopOrder; use app\common\service\Order as OrderService; use app\common\service\order\Complete as OrderCompleteService; use app\common\service\order\Shipping as ShippingService; use app\common\service\order\source\Factory as OrderSourceFactory; use cores\BaseModel; use think\model\relation\BelongsTo; use think\model\relation\HasMany; use think\model\relation\HasOne; /** * 订单模型 * Class Order * @package app\common\model */ class Order extends BaseModel { // 定义表名 protected $name = 'order'; // 定义表名(外部引用) public static string $tableName = 'order'; // 定义主键 protected $pk = 'order_id'; // 定义别名 protected string $alias = 'order'; /** * 追加字段 * @var array */ protected $append = [ 'state_text', // 售后单状态文字描述 'pay_method_text', //订单支付方式文字描述 'delivery_type_text', //配送方式文字描述 'time_text', //倒计时文字 'store_phone'//商家电话 ]; /** * 订单商品列表 * @return HasMany */ public function goods(): HasMany { $module = self::getCalledModule(); return $this->hasMany("app\\{$module}\\model\\OrderGoods")->withoutField('content'); } /** * 关联订单发货单 * @return hasMany */ public function delivery(): HasMany { $module = self::getCalledModule(); return $this->hasMany("app\\{$module}\\model\\order\\Delivery"); } /** * 关联订单收货地址表 * @return HasOne */ public function address(): HasOne { $module = self::getCalledModule(); return $this->hasOne("app\\{$module}\\model\\OrderAddress"); } /** * 关联订单收货地址表 * @return HasOne */ public function extract(): HasOne { $module = self::getCalledModule(); return $this->hasOne("app\\{$module}\\model\\OrderExtract"); } /** * 关联自提门店表 * @return BelongsTo */ public function extractShop(): BelongsTo { $module = self::getCalledModule(); return $this->belongsTo("app\\{$module}\\model\\store\\Shop", 'extract_shop_id'); } //TransferRecordModel public function transfer(): HasOne { return $this->hasOne(TransferRecord::class, 'order_id'); } /** * 关联门店店员表 * @return BelongsTo */ public function extractClerk(): BelongsTo { $module = self::getCalledModule(); return $this->belongsTo("app\\{$module}\\model\\store\\shop\\Clerk", 'extract_clerk_id'); } /** * 关联用户表 * @return BelongsTo */ public function user(): BelongsTo { $module = self::getCalledModule(); return $this->belongsTo("app\\{$module}\\model\\User"); } /** * 关联物流公司表 (仅用于兼容旧物流数据) * @return BelongsTo */ public function express(): BelongsTo { $module = self::getCalledModule(); return $this->belongsTo("app\\{$module}\\model\\Express"); } /** * 关联模型:第三方交易记录 * @return BelongsTo */ public function trade(): BelongsTo { $module = self::getCalledModule(); return $this->belongsTo("app\\{$module}\\model\\PaymentTrade", 'trade_id', 'trade_id'); } /** * 获取器:订单状态文字描述 * @param $value * @param $data * @return string */ public function getStateTextAttr($value, $data): string { // 订单状态 if ($data['order_status'] != OrderStatusEnum::NORMAL) { return OrderStatusEnum::data()[$data['order_status']]['name']; } // 付款状态 if ($data['pay_status'] == PayStatusEnum::PENDING) { return '待支付'; } // 发货状态 if ($data['delivery_status'] != DeliveryStatusEnum::DELIVERED) { $enum = [DeliveryStatusEnum::NOT_DELIVERED => '待发货', DeliveryStatusEnum::PART_DELIVERED => '部分发货']; return $enum[$data['delivery_status']]; } // 收货状态 if ($data['receipt_status'] == ReceiptStatusEnum::NOT_RECEIVED) { return '待收货'; } return empty($value)?'':$value; } /** * 获取器:订单金额(含优惠折扣) * @param $value * @param $data * @return string */ public function getOrderPriceAttr($value, $data): string { // 兼容旧数据:订单金额 if ($value == 0) { return helper::bcadd(helper::bcsub($data['total_price'], $data['coupon_money']), $data['update_price']); } return $value; } /** * 获取器:改价金额(差价) * @param $value * @return array */ public function getUpdatePriceAttr($value): array { return [ 'symbol' => $value < 0 ? '-' : '+', 'value' => sprintf('%.2f', abs((float)$value)) ]; } /** * 获取器:付款时间 * @param $value * @return false|string */ public function getPayTimeAttr($value) { return format_time($value); } /** * 获取器:发货时间 * @param $value * @return false|string */ public function getDeliveryTimeAttr($value) { return format_time($value); } /** * 获取器:收货时间 * @param $value * @return false|string */ public function getReceiptTimeAttr($value) { return format_time($value); } /** * 获取器:来源记录的参数 * @param $json * @return array */ public function getOrderSourceDataAttr($json): array { return $json ? helper::jsonDecode($json) : []; } /** * 修改器:来源记录的参数 * @param array $data * @return string */ public function setOrderSourceDataAttr(array $data): string { return helper::jsonEncode($data); } /** * 生成订单号 * @return string */ public function orderNo(): string { return OrderService::createOrderNo(); } /** * 订单详情 * @param $where * @param array $with * @return static|array|null */ public static function detail($where, array $with = []) { is_array($where) ? $filter = $where : $filter['order_id'] = (int)$where; return self::get($filter, $with); } /** * 批量获取订单列表 * @param $orderIds * @param array $with * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function getListByIds(array $orderIds, array $with = []) { $data = $this->getListByInArray('order_id', $orderIds, $with); return helper::arrayColumn2Key($data, 'order_id'); } /** * 批量获取订单列表 * @param $field * @param $data * @param array $with * @return \think\Collection * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ private function getListByInArray($field, $data, array $with = []): \think\Collection { return $this->with($with) ->where($field, 'in', $data) ->where('is_delete', '=', 0) ->select(); } /** * 根据订单号批量查询 * @param $orderNos * @param array $with * @return \think\Collection * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function getListByOrderNos($orderNos, array $with = []): \think\Collection { return $this->getListByInArray('order_no', $orderNos, $with); } /** * 批量更新订单 * @param $orderIds * @param $data * @return bool|false */ public function onBatchUpdate($orderIds, $data): bool { return static::updateBase($data, [['order_id', 'in', $orderIds]]); } /** * 确认核销(自提订单) * @param int $clerkId 门店店员ID * @param bool $syncMpWeixinShipping 同步至微信小程序 * @return bool|false|int */ public function confirmExtract(int $clerkId, bool $syncMpWeixinShipping = false) { if ( $this['pay_status'] != PayStatusEnum::SUCCESS || $this['delivery_type'] != DeliveryTypeEnum::EXTRACT || $this['delivery_status'] == DeliveryStatusEnum::DELIVERED || in_array($this['order_status'], [OrderStatusEnum::CANCELLED, OrderStatusEnum::APPLY_CANCEL]) ) { $this->error = '该订单不满足核销条件'; return false; } // 验证订单是否满足发货条件 if (!$this->verifyDeliveryForExtract($this)) { return false; } return $this->transaction(function () use ($clerkId, $syncMpWeixinShipping) { // 更新订单状态:已发货、已收货 $status = $this->save([ 'extract_clerk_id' => $clerkId, // 核销员 'delivery_status' => DeliveryStatusEnum::DELIVERED, 'delivery_time' => time(), 'receipt_status' => ReceiptStatusEnum::RECEIVED, 'receipt_time' => time(), 'order_status' => OrderStatusEnum::COMPLETED ]); // 新增订单核销记录 ShopOrder::add($this['order_id'], $this['extract_shop_id'], $this['extract_clerk_id']); // 执行订单完成后的操作 $OrderCompleteService = new OrderCompleteService(); $OrderCompleteService->complete([$this], static::$storeId); // 发货信息同步微信平台 (new ShippingService)->syncMpWeixinShipping($this, [ // 同步至微信小程序《发货信息录入》 'syncMpWeixinShipping' => (int)$syncMpWeixinShipping, // 物流模式:1物流配送 3虚拟商品 4用户自提 'logisticsType' => ShippingService::DELIVERY_EXTRACT, ]); return $status; }); } /** * 验证订单是否满足发货条件 * @param $order * @return bool */ private function verifyDeliveryForExtract($order): bool { $orderSource = OrderSourceFactory::getFactory($order['order_source']); if (!$orderSource->checkOrderByDelivery($order)) { $this->error = $orderSource->getError(); return false; } return true; } public function getPayMethodTextAttr($value, $data): string { return !empty(Method::data()[$data['pay_method']]) ? Method::data()[$data['pay_method']]['name'] : '';//支付方式 } public function getDeliveryTypeTextAttr($value, $data): string { return !empty(DeliveryType::data()[$data['delivery_type']]) ? DeliveryType::data()[$data['delivery_type']]['name'] : '';//配送方式 } public function getTimeTextAttr($value, $data): int { $diffTime = 60 * 60 * 24;//24小时倒计时 // 付款状态 if ($data['pay_status'] == PayStatusEnum::PENDING) { return (($data['create_time'] + $diffTime) - time()) * 1000; } // 收货状态 if ($data['receipt_status'] == ReceiptStatusEnum::NOT_RECEIVED) { return (($data['delivery_time'] + $diffTime) - time()) * 1000; } return 0; } public function getStorePhoneAttr($value, $data) { return Store::get($data['store_id'])->phone ?: ''; } }