| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | <?php | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | namespace app\repository; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | use app\exception\RepositoryException; | 
					
						
							|  |  |  |  | use app\model\Account; | 
					
						
							|  |  |  |  | use app\model\AccountAddress; | 
					
						
							|  |  |  |  | use app\model\AccountCoupon; | 
					
						
							|  |  |  |  | use app\model\AccountDataLog; | 
					
						
							|  |  |  |  | use app\model\Express; | 
					
						
							|  |  |  |  | use app\model\Order; | 
					
						
							|  |  |  |  | use app\model\OrderActivity; | 
					
						
							|  |  |  |  | use app\model\OrderAfterSale; | 
					
						
							|  |  |  |  | use app\model\OrderGroupList; | 
					
						
							|  |  |  |  | use app\model\OrderSku; | 
					
						
							|  |  |  |  | use app\model\PaymentLog; | 
					
						
							|  |  |  |  | use app\model\ShoppingCart; | 
					
						
							|  |  |  |  | use app\model\Sku; | 
					
						
							|  |  |  |  | use app\model\Spu; | 
					
						
							|  |  |  |  | use app\model\SpuActivity; | 
					
						
							|  |  |  |  | use app\service\Kd100; | 
					
						
							|  |  |  |  | use app\service\Math; | 
					
						
							|  |  |  |  | use app\service\Repository; | 
					
						
							|  |  |  |  | use app\service\wx\WechatPay; | 
					
						
							|  |  |  |  | use app\traits\order\ActivityTrait; | 
					
						
							|  |  |  |  | use app\traits\order\AfterSaleTrait; | 
					
						
							|  |  |  |  | use app\traits\order\ExpressLogTrait; | 
					
						
							|  |  |  |  | use app\traits\order\ExpressTrait; | 
					
						
							|  |  |  |  | use app\traits\order\ShoppingCartTrait; | 
					
						
							| 
									
										
										
										
											2022-06-10 17:41:56 +08:00
										 |  |  |  | use app\traits\spu\SkuTrait; | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; | 
					
						
							|  |  |  |  | use EasyWeChat\Kernel\Exceptions\InvalidConfigException; | 
					
						
							|  |  |  |  | use Exception; | 
					
						
							|  |  |  |  | use GuzzleHttp\Exception\GuzzleException; | 
					
						
							|  |  |  |  | use Psr\Http\Message\ResponseInterface; | 
					
						
							|  |  |  |  | use think\Collection; | 
					
						
							|  |  |  |  | use think\db\exception\DataNotFoundException; | 
					
						
							|  |  |  |  | use think\db\exception\DbException; | 
					
						
							|  |  |  |  | use think\db\exception\ModelNotFoundException; | 
					
						
							|  |  |  |  | use think\facade\Config as CConfig; | 
					
						
							|  |  |  |  | use think\facade\Db; | 
					
						
							|  |  |  |  | use think\facade\Log; | 
					
						
							|  |  |  |  | use think\Model; | 
					
						
							|  |  |  |  | use function EasyWeChat\Kernel\Support\generate_sign; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /** | 
					
						
							|  |  |  |  |  * 订单域 相关操作 | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Class OrderRepository | 
					
						
							|  |  |  |  |  * @package app\repository | 
					
						
							|  |  |  |  |  * @method self getInstance(Model $model = null) static | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | class OrderRepository extends Repository | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     use ShoppingCartTrait; | 
					
						
							|  |  |  |  |     use AfterSaleTrait; | 
					
						
							|  |  |  |  |     use ExpressTrait; | 
					
						
							|  |  |  |  |     use ExpressLogTrait; | 
					
						
							|  |  |  |  |     use ActivityTrait; | 
					
						
							| 
									
										
										
										
											2022-06-10 17:41:56 +08:00
										 |  |  |  |     use SkuTrait; | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** 订单状态 **/ | 
					
						
							|  |  |  |  |     public const STATUS_ORDER_PLACED        = Order::STATUS_ORDER_PLACED;//已下单  (已付款待发货)
 | 
					
						
							|  |  |  |  |     public const STATUS_MAKEING             = Order::STATUS_MAKEING;//制作中
 | 
					
						
							|  |  |  |  |     public const STATUS_SHIPPED             = Order::STATUS_SHIPPED;//已发货
 | 
					
						
							|  |  |  |  |     public const STATUS_ARRIVED             = Order::STATUS_ARRIVED;//已送达
 | 
					
						
							|  |  |  |  |     public const STATUS_COMPLETED           = Order::STATUS_COMPLETED;//已完成 确认收获 或者 到期自动确认
 | 
					
						
							|  |  |  |  |     public const STATUS_CANCEL              = Order::STATUS_CANCEL;//已取消
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     public const IS_EVALUATE_YES = 1; // is_evaluate 已评价(订单中的已评价指全部评价完)
 | 
					
						
							|  |  |  |  |     public const IS_EVALUATE_NO  = 0; // is_evaluate 未评价(订单中的已评价指全部评价完)
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** 订单状态文本描述 **/ | 
					
						
							|  |  |  |  |     public static function orderStatusTextList(): array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         return [ | 
					
						
							|  |  |  |  |             self::STATUS_ORDER_PLACED   => '已下单', | 
					
						
							|  |  |  |  |             self::STATUS_MAKEING        => '制作中', | 
					
						
							|  |  |  |  |             self::STATUS_SHIPPED        => '已发货', | 
					
						
							|  |  |  |  |             self::STATUS_ARRIVED        => '已送达', | 
					
						
							|  |  |  |  |             self::STATUS_COMPLETED      => '已完成', | 
					
						
							|  |  |  |  |             self::STATUS_CANCEL         => '已取消', | 
					
						
							|  |  |  |  |         ]; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 获取订单列表 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $accountId | 
					
						
							|  |  |  |  |      * @param  array  $fields | 
					
						
							|  |  |  |  |      * @return array | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function listByUid(int $accountId, array $fields = []): array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         return $this->findList(['account_id' => $accountId], $fields); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 获取指定sku库存 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  array  $codingIds | 
					
						
							|  |  |  |  |      * @return array | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function stock(array $codingIds): array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         return Sku::where('coding', 'in', $codingIds)->column('stock', 'coding'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 订单提交数据 校验+处理 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  array  $data | 
					
						
							|  |  |  |  |      * @return array | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function validateOrderData(array $data): array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         /** 订单提交的数据 必需按下列格式 | 
					
						
							|  |  |  |  |          * $data['sku_list']    = [ | 
					
						
							|  |  |  |  |          * [ | 
					
						
							|  |  |  |  |          * 'sku_coding' => '16261684919319972261', | 
					
						
							|  |  |  |  |          * 'group_id' => 1, | 
					
						
							|  |  |  |  |          * 'num'        => 1, | 
					
						
							|  |  |  |  |          * ], | 
					
						
							|  |  |  |  |          * [ | 
					
						
							|  |  |  |  |          * 'sku_coding' => '16261684169515092561', | 
					
						
							|  |  |  |  |          * 'group_id' => 0, | 
					
						
							|  |  |  |  |          * 'num'        => 1, | 
					
						
							|  |  |  |  |          * ], | 
					
						
							|  |  |  |  |          * [ | 
					
						
							|  |  |  |  |          * 'sku_coding' => '16261684169515092561', | 
					
						
							|  |  |  |  |          * 'group_id' => 1, | 
					
						
							|  |  |  |  |          * 'num'        => 1, | 
					
						
							|  |  |  |  |          * ], | 
					
						
							|  |  |  |  |          * ]; | 
					
						
							|  |  |  |  |          * $data['total']       = 950; //订单应付总金额(前端计算的结果)单位:元
 | 
					
						
							|  |  |  |  |          * $data['address_id']  = 26; //地址ID 0=自提
 | 
					
						
							|  |  |  |  |          * $data['express_code']  = ''; //快递公司代号
 | 
					
						
							|  |  |  |  |          * $data['pick_self']  = 0; //是否自提 0=否 1=是
 | 
					
						
							|  |  |  |  |          * $data['pick_self_phone']  = '13541194066'; //自提时必填 自提人联系方式
 | 
					
						
							|  |  |  |  |          * $data['original_total']  = 1000; //商品总价 单位元
 | 
					
						
							|  |  |  |  |          * $data['freight']  = 0; //运费 单位元
 | 
					
						
							|  |  |  |  |          * $data['remarks'] = '';//买家备注
 | 
					
						
							|  |  |  |  |          */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!isset($data['sku_list']) || empty($data['sku_list'])) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('商品不能为空'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-27 14:25:49 +08:00
										 |  |  |  |         if (!isset($data['address']) || empty($data['address'])) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('收货地址不能为空'); | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |         if (!isset($data['phone']) || empty($data['phone'])||!preg_match("/^1[3456789]{1}\d{9}$/",$data['phone'])) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('收货联系电话不能为空或格式不正确'); | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-05-27 14:25:49 +08:00
										 |  |  |  |         if (!isset($data['contacts']) || empty($data['contacts'])) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('收货联系人不能为空'); | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-27 14:25:49 +08:00
										 |  |  |  | //        if (!isset($data['pick_self']) ||
 | 
					
						
							|  |  |  |  | //            !isset($data['freight'])) {
 | 
					
						
							|  |  |  |  | //            throw new RepositoryException('订单参数错误');
 | 
					
						
							|  |  |  |  | //        }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | //        $data['coupon_id']    = $data['coupon_id'] ?? 0;
 | 
					
						
							|  |  |  |  | //        $data['coupon_price'] = $data['coupon_price'] ?? 0;
 | 
					
						
							|  |  |  |  | //        $data['is_score']     = $data['is_score'] ?? 0;
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | //        if ($data['pick_self'] == Order::COMMON_OFF && !isset($data['address_id'])) {
 | 
					
						
							|  |  |  |  | //            throw new RepositoryException('请选择收货地址');
 | 
					
						
							|  |  |  |  | //        }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | //        if ($data['pick_self'] == Order::COMMON_ON && !isset($data['pick_self_phone'])) {
 | 
					
						
							|  |  |  |  | //            throw new RepositoryException('自提时请填写联系人方式');
 | 
					
						
							|  |  |  |  | //        }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | //        if (isset($data['express_code']) && !empty($data['express_code'])) {
 | 
					
						
							|  |  |  |  | //            if (!$express = Express::where('code', $data['express_code'])->find()) {
 | 
					
						
							|  |  |  |  | //                throw new RepositoryException('快递公司不存在');
 | 
					
						
							|  |  |  |  | //            }
 | 
					
						
							|  |  |  |  | //            $data['express_name'] = $express['name'] ?? '';
 | 
					
						
							|  |  |  |  | //        }
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         $skuList   = $this->handleSku($data['sku_list']); | 
					
						
							| 
									
										
										
										
											2022-05-27 14:25:49 +08:00
										 |  |  |  |         //$groupList = $this->handleGroup($data['sku_list']);
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         $data['sku_list']   = $skuList; | 
					
						
							| 
									
										
										
										
											2022-05-27 14:25:49 +08:00
										 |  |  |  |         //$data['group_list'] = $groupList;
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         return $data; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * sku数据处理 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  array  $data | 
					
						
							|  |  |  |  |      * @return array | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     protected function handleSku(array $data): array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $skuList = []; | 
					
						
							|  |  |  |  |         foreach ($data as $sku) { | 
					
						
							|  |  |  |  |             if (!isset($sku['sku_coding']) || empty($sku['sku_coding'])) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('SKU编码不能为空'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             //多个相同sku_coding合并
 | 
					
						
							|  |  |  |  |             if (!empty($skuList[$sku['sku_coding']])) { | 
					
						
							|  |  |  |  |                 $skuList[$sku['sku_coding']] += $sku['num'] ?? 1; | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 $skuList[$sku['sku_coding']] = $sku['num'] ?? 1; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return $skuList; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 拼团数据处理 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  array  $data | 
					
						
							|  |  |  |  |      * @return array | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     protected function handleGroup(array $data): array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $list = []; | 
					
						
							|  |  |  |  |         foreach ($data as $sku) { | 
					
						
							|  |  |  |  |             if (!isset($sku['sku_coding']) || empty($sku['sku_coding'])) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('SKU编码不能为空'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $list[$sku['sku_coding']] = $sku['group_id'] ?? 0; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return $list; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 订单前置数据 校验+处理 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  array  $data | 
					
						
							|  |  |  |  |      * @return array | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function validatePrepareData(array $data): array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         /** 订单前置数据 必需按下列格式 | 
					
						
							|  |  |  |  |          * $data['sku_list']    = [ | 
					
						
							|  |  |  |  |          * [ | 
					
						
							|  |  |  |  |          * 'sku_coding' => '16261684919319972261', | 
					
						
							|  |  |  |  |          * 'num'        => 1, | 
					
						
							|  |  |  |  |          * ], | 
					
						
							|  |  |  |  |          * [ | 
					
						
							|  |  |  |  |          * 'sku_coding' => '16261684169515092561', | 
					
						
							|  |  |  |  |          * 'num'        => 1, | 
					
						
							|  |  |  |  |          * ], | 
					
						
							|  |  |  |  |          * [ | 
					
						
							|  |  |  |  |          * 'sku_coding' => '16261684169515092561', | 
					
						
							|  |  |  |  |          * 'num'        => 1, | 
					
						
							|  |  |  |  |          * ], | 
					
						
							|  |  |  |  |          * ]; | 
					
						
							|  |  |  |  |          */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!isset($data['sku_list']) || empty($data['sku_list'])) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('商品不能为空1'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $skuList = $this->handleSku($data['sku_list']); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $data['sku_list'] = $skuList; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return $data; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 创建订单 流程:1、参数完整性校验 2、参数正确性校验[收货地址、商品列表、商品价格等] 3、对比前端计算结果 4、创建订单 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $accountId  用户ID | 
					
						
							|  |  |  |  |      * @param  array  $data  订单数据 | 
					
						
							|  |  |  |  |      * @return Model | 
					
						
							|  |  |  |  |      * @throws RepositoryException|GuzzleException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function createOrder(int $accountId, array $data): Model | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         // 启动事务
 | 
					
						
							|  |  |  |  |         Db::startTrans(); | 
					
						
							|  |  |  |  |         try { | 
					
						
							|  |  |  |  |             $account = Account::where('id', $accountId)->lock(true)->find(); | 
					
						
							|  |  |  |  |             if (!$account) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('用户不存在'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $data      = $this->validateOrderData($data); | 
					
						
							|  |  |  |  |             $dataSku   = $data['sku_list'];//商品sku coding=>num 商品数量
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $skuList = SpuRepository::getInstance()->listBySkuCoding(array_keys($dataSku), true); | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |             $skuPriceList = $skuList->column('original_price', 'coding'); | 
					
						
							|  |  |  |  | //            if (isset($data['is_only']) && $data['is_only'] > Spu::COMMON_OFF) {
 | 
					
						
							|  |  |  |  | //                $skuPriceList = $skuList->column('original_price', 'coding');
 | 
					
						
							|  |  |  |  | //            } else {
 | 
					
						
							|  |  |  |  | //                $skuPriceList = $skuList->column('price', 'coding');
 | 
					
						
							|  |  |  |  | //            }
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             $skuScoreList = $skuList->column('score', 'coding');//商品规格=》积分
 | 
					
						
							|  |  |  |  |             $skuStockList = $skuList->column('stock', 'coding'); | 
					
						
							|  |  |  |  |             $totalPrice   = 0;//商品原总价 单位(元) 未做任何优惠
 | 
					
						
							|  |  |  |  |             $totalScore   = 0;//商品总积分
 | 
					
						
							|  |  |  |  |             foreach ($dataSku as $coding => $num) { | 
					
						
							|  |  |  |  |                 if (!isset($skuPriceList[$coding])) { | 
					
						
							|  |  |  |  |                     throw new RepositoryException('部分商品不存在或已下架 规格编码:'.$coding); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 $totalPrice += $skuPriceList[$coding] * $num; | 
					
						
							|  |  |  |  |                 $totalScore += $skuScoreList[$coding] * $num; | 
					
						
							|  |  |  |  |                 if ($skuStockList[$coding] < $num) { | 
					
						
							|  |  |  |  |                     throw new RepositoryException('有商品库存不足'); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $skuArr = $skuList->each(function ($item) use ($dataSku, $accountId) { | 
					
						
							|  |  |  |  |                 $item->num        = $dataSku[$item->coding] ?? 1; | 
					
						
							|  |  |  |  |                 $item->account_id = $accountId; | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 限购检查 包含活动商品和普通商品
 | 
					
						
							|  |  |  |  |             $this->skuCheck($skuArr->toArray()); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             //商品减库存
 | 
					
						
							|  |  |  |  |             $updateSkuStock = [];//规格库存
 | 
					
						
							| 
									
										
										
										
											2022-06-10 17:41:56 +08:00
										 |  |  |  |             $updateSpuStock = []; | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             foreach ($skuList as $sku) { | 
					
						
							|  |  |  |  |                 $arr          = []; | 
					
						
							|  |  |  |  |                 $arr['id']    = $sku['id']; | 
					
						
							|  |  |  |  |                 $arr['stock'] = Db::raw('`stock` - '.($dataSku[$sku['coding']] ?? 1));; | 
					
						
							|  |  |  |  |                 $updateSkuStock[] = $arr; | 
					
						
							| 
									
										
										
										
											2022-06-10 17:41:56 +08:00
										 |  |  |  |                 $updateSpuStock["spu_id"] = $sku['spu_id']; | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             (new Sku())->saveAll($updateSkuStock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-10 17:41:56 +08:00
										 |  |  |  |             foreach ($updateSpuStock as $spuItem) { | 
					
						
							|  |  |  |  |                 $this->updateStockById($spuItem); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |            // $freight = 0;//运费(元)
 | 
					
						
							|  |  |  |  | //            // 邮寄方式
 | 
					
						
							|  |  |  |  | //            if ($data['pick_self'] == Order::COMMON_OFF) {
 | 
					
						
							|  |  |  |  | //                // 快递公司默认运费
 | 
					
						
							|  |  |  |  | //                if (isset($data['express_code']) && !empty($data['express_code'])) {
 | 
					
						
							|  |  |  |  | //                    $freight = Express::getDefaultFreight($data['express_code']);
 | 
					
						
							|  |  |  |  | //                }
 | 
					
						
							|  |  |  |  | //
 | 
					
						
							|  |  |  |  | //                if (!$address = AccountAddress::findById($data['address_id'])) {
 | 
					
						
							|  |  |  |  | //                    throw new RepositoryException('收货地址不存在');
 | 
					
						
							|  |  |  |  | //                }
 | 
					
						
							|  |  |  |  | //
 | 
					
						
							|  |  |  |  | //                $addressInfo = sprintf("%s,%s,%s %s %s %s", $address['name'], $address['phone'],
 | 
					
						
							|  |  |  |  | //                    $address['province_str'], $address['city_str'], $address['county_str'], $address['address']);
 | 
					
						
							|  |  |  |  | //            } else {
 | 
					
						
							|  |  |  |  | //                $addressInfo = '自提';
 | 
					
						
							|  |  |  |  | //            }
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |             //$realTotalPrice = $totalPrice - $data['coupon_price'];//实际应支付=商品总价-优惠券金额
 | 
					
						
							|  |  |  |  |             $realTotalPrice = $totalPrice;//实际应支付=商品总价-优惠券金额
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             $realTotalPrice = $realTotalPrice <= 0 ? 0 : $realTotalPrice; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |            // $realTotalPrice += $freight;//加运费
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |             $insert = []; | 
					
						
							|  |  |  |  |             $time   = time(); | 
					
						
							|  |  |  |  |             $now    = date('Y-m-d H:i:s', $time); | 
					
						
							|  |  |  |  |             // 付款有效期
 | 
					
						
							|  |  |  |  |             $expired = date('Y-m-d H:i:s', $time + 15 * 60); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $payType = Order::PAY_TYPE_WECHAT; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 积分支付
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  | //            if ($data['is_score'] > 0) {
 | 
					
						
							|  |  |  |  | //                if ($account['score'] < $totalScore) {
 | 
					
						
							|  |  |  |  | //                    throw new RepositoryException('积分不足');
 | 
					
						
							|  |  |  |  | //                }
 | 
					
						
							|  |  |  |  | //                $payType = Order::PAY_TYPE_SCORE;
 | 
					
						
							|  |  |  |  | //            }
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |             $create = [ | 
					
						
							|  |  |  |  |                 'coding'         => generateCode(), | 
					
						
							|  |  |  |  |                 'account_id'     => $accountId, | 
					
						
							|  |  |  |  |                 'original_price' => $totalPrice, | 
					
						
							|  |  |  |  |                 'price'          => $realTotalPrice, | 
					
						
							|  |  |  |  |                 'pay_type'       => $payType,//支付方式
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |                 'status'         => self::STATUS_ORDER_PLACED, | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 'created_at'     => $now, | 
					
						
							|  |  |  |  |                 'score'          => $totalScore,//使用积分
 | 
					
						
							|  |  |  |  |                 'expired_at'     => $expired, | 
					
						
							|  |  |  |  |                 'address_id'     => $data['address_id'] ?? 0, | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |                 //'address'        => $addressInfo,
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 'remarks'        => $data['remarks'] ?? '', | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |                 'express_code'   => $data['express_code']??'', | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 'express_name'   => $data['express_name'] ?? '', | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |                 'pick_self'      => $data['pick_self'] ??0, | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 'coupon_id'      => $data['coupon_id'] ?? 0, | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |                 'freight'        => 0, | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 'coupon_price'   => $data['coupon_price'] ?? 0, | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |                 //'phone'          => $address['phone'] ?? $data['pick_self_phone'],
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 'is_only'        => isset($data['is_only']) && $data['is_only'] > 0 ? 1 : 0, | 
					
						
							|  |  |  |  |                 'is_score'       => $data['is_score'] ?? 0, | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |                 'wedding_date'                  => $data['wedding_date'] ?? null, | 
					
						
							|  |  |  |  |                 'expected_delivery_date'        => $data['expected_delivery_date'] ?? null, | 
					
						
							|  |  |  |  |                 'address'                       => $data['address'] ?? '', | 
					
						
							|  |  |  |  |                 'phone'                         => $data['phone'] ?? '', | 
					
						
							|  |  |  |  |                 'contacts'                      => $data['contacts'] ?? '', | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             ]; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if ($realTotalPrice == 0) { | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |                 $create['status']  = self::STATUS_ORDER_PLACED; | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 $create['paid_at'] = $now; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             //创建订单
 | 
					
						
							|  |  |  |  |             if (!$order = $this->create($create)) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('订单创建失败,请稍后重试'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  | //            // 优惠券状态变更
 | 
					
						
							|  |  |  |  | //            if ($data['coupon_id'] > 0 && $data['coupon_price'] > 0) {
 | 
					
						
							|  |  |  |  | //                AccountCoupon::use($accountId, $data['coupon_id'], $order['coding']);
 | 
					
						
							|  |  |  |  | //            }
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 创建活动商品订单
 | 
					
						
							|  |  |  |  |             //            OrderRepository::getInstance()->createActivityOrder($accountId, $order->coding, $skuArr->toArray());
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  | //            if ($realTotalPrice > 0) {
 | 
					
						
							|  |  |  |  | //                //创建支付记录
 | 
					
						
							|  |  |  |  | //                PaymentLog::create([
 | 
					
						
							|  |  |  |  | //                    'account_id'   => $accountId,
 | 
					
						
							|  |  |  |  | //                    'order_coding' => $order['coding'],
 | 
					
						
							|  |  |  |  | //                    'created_at'   => $now,
 | 
					
						
							|  |  |  |  | //                    'type'         => 'order',
 | 
					
						
							|  |  |  |  | //                    'amount'       => $order['price'],
 | 
					
						
							|  |  |  |  | //                ]);
 | 
					
						
							|  |  |  |  | //            }
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  | //            $order->needPay  = $realTotalPrice > 0;//是否需要付款
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             $orderHasVirtual = 0;//是否拥有虚拟商品
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $skuIds = [];//当前订单涉及到的skuID
 | 
					
						
							|  |  |  |  |             foreach ($skuList as $sku) { | 
					
						
							|  |  |  |  |                 $skuIds[] = $sku->id; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 $arr                    = []; | 
					
						
							| 
									
										
										
										
											2022-06-01 16:37:29 +08:00
										 |  |  |  |                 $arr['order_coding']    = $order->coding; | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 $arr['coding']          = $sku->coding; | 
					
						
							|  |  |  |  |                 $arr['spu_id']          = $sku->spu_id; | 
					
						
							|  |  |  |  |                 $arr['spu_activity_id'] = $sku->spu_activity_id; | 
					
						
							|  |  |  |  |                 $arr['sku_id']          = $sku->id; | 
					
						
							|  |  |  |  |                 $arr['account_id']      = $accountId; | 
					
						
							|  |  |  |  |                 $arr['price']           = (isset($data['is_only']) && $data['is_only'] > Spu::COMMON_OFF) ? $sku->original_price : $sku->price; | 
					
						
							|  |  |  |  |                 $arr['score']           = $sku->score; | 
					
						
							|  |  |  |  |                 $arr['num']             = $dataSku[$sku->coding]; | 
					
						
							|  |  |  |  |                 $arr['status']          = 'normal'; | 
					
						
							|  |  |  |  |                 $arr['created_at']      = $now; | 
					
						
							|  |  |  |  |                 $arr['spu_cover']       = $sku->spu_cover; | 
					
						
							|  |  |  |  |                 $arr['spu_name']        = $sku->spu_name; | 
					
						
							|  |  |  |  |                 $arr['sku_cover']       = $sku->sku_cover; | 
					
						
							|  |  |  |  |                 $arr['sku_name']        = $sku->sku_name; | 
					
						
							|  |  |  |  |                 $arr['is_virtual']      = $sku->is_virtual; | 
					
						
							|  |  |  |  |                 $arr['check_type']      = $sku->check_type; | 
					
						
							|  |  |  |  |                 $arr['spec_text']       = $sku->spec_text ? json_encode($sku->spec_text, JSON_UNESCAPED_UNICODE) : ''; | 
					
						
							|  |  |  |  |                 $arr['not_check_num']   = $dataSku[$sku->coding]; | 
					
						
							|  |  |  |  |                 $arr['has_comment']     = OrderSku::HAS_COMMENT_NO; | 
					
						
							|  |  |  |  |                 $arr['is_activity']     = $sku->is_activity; | 
					
						
							|  |  |  |  |                 $arr['activity_type']   = $sku->activity_type; | 
					
						
							| 
									
										
										
										
											2022-06-01 16:37:29 +08:00
										 |  |  |  |                 $arr['sku_unit']        = $sku->unit; | 
					
						
							| 
									
										
										
										
											2022-06-08 17:46:53 +08:00
										 |  |  |  |                 $arr['subtotal']        = $sku->original_price * $dataSku[$sku->coding]; | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 $insert[]               = $arr; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 if ($sku->is_virtual > 0) { | 
					
						
							|  |  |  |  |                     $orderHasVirtual = 1; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if ($orderHasVirtual > 0) { | 
					
						
							|  |  |  |  |                 $order->save(['has_virtual' => Order::COMMON_ON]); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 删除购物车中相关SKU
 | 
					
						
							|  |  |  |  |             ShoppingCart::whereIn('sku_id', $skuIds)->where('account_id', $accountId)->delete(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             //保存订单商品
 | 
					
						
							|  |  |  |  |             if (!(new OrderSku())->saveAll($insert)) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('订单商品保存失败'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  | //            if ($realTotalPrice > 0) {
 | 
					
						
							|  |  |  |  | //                //统一下单
 | 
					
						
							|  |  |  |  | //                $res = $this->wechatMiniPay($order->coding, $account->openid, Math::yuan2Fen($realTotalPrice));
 | 
					
						
							|  |  |  |  | //                $order->save(['prepay_id' => $res['prepay_id']]);
 | 
					
						
							|  |  |  |  | //
 | 
					
						
							|  |  |  |  | //                //生成小程序支付请求的参数
 | 
					
						
							|  |  |  |  | //                $order->payment_params = $this->miniPayReqParams($res['prepay_id']);
 | 
					
						
							|  |  |  |  | //            }
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 积分订单 扣减积分并记录
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  | //            if ($totalScore > 0) {
 | 
					
						
							|  |  |  |  | //                AccountDataLog::log($accountId,
 | 
					
						
							|  |  |  |  | //                    '积分商品下单', -$totalScore,
 | 
					
						
							|  |  |  |  | //                    AccountDataLog::TYPE_SCORE,
 | 
					
						
							|  |  |  |  | //                    AccountDataLog::ACTION_ORDER,
 | 
					
						
							|  |  |  |  | //                    $account['score'] - $totalScore);
 | 
					
						
							|  |  |  |  | //                $account->score = Db::raw('`score` - '.$totalScore);
 | 
					
						
							|  |  |  |  | //            }
 | 
					
						
							|  |  |  |  |             $account->mobile    = $data["phone"]; | 
					
						
							|  |  |  |  |             $account->address   = $data["address"]; | 
					
						
							|  |  |  |  |             $account->contacts  = $data["contacts"]; | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             $account->save(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  | //            if ($realTotalPrice == 0) {
 | 
					
						
							|  |  |  |  | //                // 设为已付款
 | 
					
						
							|  |  |  |  | //                $this->afterPaid($accountId, $order['coding']);
 | 
					
						
							|  |  |  |  | //            }
 | 
					
						
							|  |  |  |  |             // 设为已付款
 | 
					
						
							|  |  |  |  |             $this->afterPaid($accountId, $order['coding']); | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |             Db::commit(); | 
					
						
							|  |  |  |  |             return $order; | 
					
						
							|  |  |  |  |         } catch (RepositoryException $e) { | 
					
						
							|  |  |  |  |             Db::rollback(); | 
					
						
							|  |  |  |  |             throw new RepositoryException($e->getMessage(), $e->getCode()); | 
					
						
							|  |  |  |  |         } catch (Exception $e) { | 
					
						
							|  |  |  |  |             //回滚
 | 
					
						
							|  |  |  |  |             Db::rollback(); | 
					
						
							|  |  |  |  |             self::log('订单创建失败', $e, 'error', 'order'); | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |             throw new RepositoryException('订单创建失败'.$e->getMessage()); | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 根据统一下单返回的prepay_id 生成小程序支付请求参数 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $prepayId | 
					
						
							|  |  |  |  |      * @return array | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     protected function miniPayReqParams(string $prepayId): array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         CConfig::load('extra/wechat', 'wechat'); | 
					
						
							|  |  |  |  |         $config         = config('wechat'); | 
					
						
							|  |  |  |  |         $params         = [ | 
					
						
							|  |  |  |  |             'appId'     => $config['applets_appId'] ?? '', | 
					
						
							|  |  |  |  |             'timeStamp' => (string) time(), | 
					
						
							|  |  |  |  |             'nonceStr'  => uniqid(), | 
					
						
							|  |  |  |  |             'package'   => 'prepay_id='.$prepayId, | 
					
						
							|  |  |  |  |             'signType'  => 'MD5' | 
					
						
							|  |  |  |  |         ]; | 
					
						
							|  |  |  |  |         $params['sign'] = generate_sign($params, $config['key']); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return $params; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 微信支付 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderId | 
					
						
							|  |  |  |  |      * @param  string  $openid | 
					
						
							|  |  |  |  |      * @param  int  $price | 
					
						
							|  |  |  |  |      * @return array|\EasyWeChat\Kernel\Support\Collection|object|ResponseInterface|string | 
					
						
							|  |  |  |  |      * @throws GuzzleException | 
					
						
							|  |  |  |  |      * @throws InvalidArgumentException | 
					
						
							|  |  |  |  |      * @throws InvalidConfigException | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function wechatMiniPay(string $orderId, string $openid, int $price) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $res = WechatPay::getInstance()->order->unify([ | 
					
						
							|  |  |  |  |             'body'         => '商品购买', | 
					
						
							|  |  |  |  |             'out_trade_no' => $orderId, | 
					
						
							|  |  |  |  |             'total_fee'    => $price, | 
					
						
							|  |  |  |  |             'trade_type'   => 'JSAPI', | 
					
						
							|  |  |  |  |             'openid'       => $openid, | 
					
						
							|  |  |  |  |         ]); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $log = sprintf("[微信统一下单返回][订单号=%s]%s", $orderId, json_encode($res, JSON_UNESCAPED_UNICODE)); | 
					
						
							|  |  |  |  |         Log::info($log); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         //return_code仅是通信状态 非支付状态
 | 
					
						
							|  |  |  |  |         if (isset($res['return_code']) && $res['return_code'] == 'SUCCESS') { | 
					
						
							|  |  |  |  |             if (isset($res['result_code']) && $res['result_code'] == 'SUCCESS') { | 
					
						
							|  |  |  |  |                 return $res; | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('支付请求失败'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } else { | 
					
						
							|  |  |  |  |             throw new RepositoryException('请求微信接口失败'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 订单准备信息获取 | 
					
						
							|  |  |  |  |      * 即根据商品(sku)列表 收货地址 返回商品列表信息、运费、总价、可用分红额度等信息 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $accountId  用户ID | 
					
						
							|  |  |  |  |      * @param  array  $data  订单数据 | 
					
						
							|  |  |  |  |      * @return array | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function prepareInfo(int $accountId, array $data): array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $data    = $this->validateprepareData($data); | 
					
						
							|  |  |  |  |         $dataSku = $data['sku_list'];//商品sku coding=>num 商品数量
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         try { | 
					
						
							|  |  |  |  |             $res = [];//待返回数据
 | 
					
						
							|  |  |  |  |             if (!$account = Account::findById($accountId, ['id', 'score'])) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('读取用户信息失败'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $skuList      = SpuRepository::getInstance()->listBySkuCoding(array_keys($dataSku)); | 
					
						
							|  |  |  |  |             $skuPriceList = $skuList->column('price', 'coding'); | 
					
						
							|  |  |  |  |             $totalPrice   = 0;//商品原总价 单位(元) 未做任何优惠
 | 
					
						
							|  |  |  |  |             foreach ($dataSku as $coding => $num) { | 
					
						
							|  |  |  |  |                 $totalPrice += $skuPriceList[$coding] * $num; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $skuList->each(function ($item) use ($dataSku, $data) { | 
					
						
							|  |  |  |  |                 $item->num = $dataSku[$item->coding] ?? 1; | 
					
						
							|  |  |  |  |                 if (!empty($item->spu_cover) && !isHttpUrl($item->spu_cover)) { | 
					
						
							|  |  |  |  |                     $item->spu_cover = $data['domain'].$item->spu_cover; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 if (!empty($item->sku_cover) && !isHttpUrl($item->sku_cover)) { | 
					
						
							|  |  |  |  |                     $item->sku_cover = $data['domain'].$item->sku_cover; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $res['original_total'] = $totalPrice; | 
					
						
							|  |  |  |  |             $res['list']           = $skuList; | 
					
						
							|  |  |  |  |             $res['account']        = $account; | 
					
						
							|  |  |  |  |             $res['discount']       = 0; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             return $res; | 
					
						
							|  |  |  |  |         } catch (RepositoryException $e) { | 
					
						
							|  |  |  |  |             throw new RepositoryException($e->getMessage(), $e->getCode()); | 
					
						
							|  |  |  |  |         } catch (Exception $e) { | 
					
						
							|  |  |  |  |             self::log('订单准备信息获取失败', $e, 'error', 'order'); | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单数据错误'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 获取可以自动收货的订单列表 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $day | 
					
						
							|  |  |  |  |      * @return Collection | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function autoReceiptList(int $day = 20): Collection | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         //发货后day天 自动确认收货
 | 
					
						
							|  |  |  |  |         $shipped_at = date('Y-m-d H:i:s', time() - $day * 86400); | 
					
						
							|  |  |  |  |         return $this->model->where('status', self::STATUS_SHIPPED) | 
					
						
							|  |  |  |  |             ->field('status,id,coding') | 
					
						
							|  |  |  |  |             ->where('shipped_at', '<', $shipped_at) | 
					
						
							|  |  |  |  |             ->select(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 支付过期的订单列表 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @return Collection | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function expiredList(): Collection | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         //过期时间大于当前时间
 | 
					
						
							|  |  |  |  |         return $this->model->where('status', self::STATUS_WAITING) | 
					
						
							|  |  |  |  |             ->field('status,id') | 
					
						
							|  |  |  |  |             ->where('expired_at', '<', date('Y-m-d H:i:s')) | 
					
						
							|  |  |  |  |             ->select(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 订单状态改为已过期 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding | 
					
						
							|  |  |  |  |      * @return bool | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function setExpired(string $orderCoding): bool | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         return $this->setClosed($orderCoding, Order::STATUS_EXPIRED); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 检测用户所有已过期的订单 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $accountId | 
					
						
							|  |  |  |  |      * @return bool | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function checkAccountExpiredOrders(int $accountId = 0): bool | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if ($accountId <= 0) { | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         Db::startTrans(); | 
					
						
							|  |  |  |  |         try { | 
					
						
							|  |  |  |  |             if ($accountId > 0 && !Account::findById($accountId)) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('用户不存在'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $where   = []; | 
					
						
							|  |  |  |  |             $where[] = ['status', '=', self::STATUS_WAITING]; | 
					
						
							|  |  |  |  |             if ($accountId > 0) { | 
					
						
							|  |  |  |  |                 $where[] = ['account_id', '=', $accountId]; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $waitingOrders = $this->model->where($where)->select(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $toExpiredIds      = []; | 
					
						
							|  |  |  |  |             $toExpiredOrderIds = []; | 
					
						
							|  |  |  |  |             $nowTime           = time(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             foreach ($waitingOrders as $order) { | 
					
						
							|  |  |  |  |                 if (!empty($order['expired_at'])) { | 
					
						
							|  |  |  |  |                     $expireTime = strtotime($order['expired_at']); | 
					
						
							|  |  |  |  |                     if ($nowTime >= $expireTime) { | 
					
						
							|  |  |  |  |                         $toExpiredIds[]      = $order['id']; | 
					
						
							|  |  |  |  |                         $toExpiredOrderIds[] = $order['coding']; | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 订单状态变更
 | 
					
						
							|  |  |  |  |             if (count($toExpiredIds) > 0) { | 
					
						
							|  |  |  |  |                 $this->model->whereIn('id', $toExpiredIds) | 
					
						
							|  |  |  |  |                     ->update(['status' => OrderRepository::STATUS_EXPIRED]); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 商品库存量恢复
 | 
					
						
							|  |  |  |  |             if (count($toExpiredOrderIds) > 0) { | 
					
						
							|  |  |  |  |                 $this->backStock($toExpiredOrderIds); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             Db::commit(); | 
					
						
							|  |  |  |  |         } catch (RepositoryException | Exception $e) { | 
					
						
							|  |  |  |  |             Db::rollback(); | 
					
						
							|  |  |  |  |             self::log('订单已过期检测失败', $e, 'error', 'order'); | 
					
						
							|  |  |  |  |             return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 退还订单库存 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  array  $orderCoding  订单编号数组 | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function backStock(array $orderCoding) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $orderSkus = OrderSku::whereIn('coding', $orderCoding)->field('num, sku_id')->select(); | 
					
						
							|  |  |  |  |         if (!$orderSkus->isEmpty()) { | 
					
						
							|  |  |  |  |             $sku2Num = []; | 
					
						
							|  |  |  |  |             foreach ($orderSkus as $item) { | 
					
						
							|  |  |  |  |                 if (isset($sku2Num[$item['sku_id']])) { | 
					
						
							|  |  |  |  |                     $sku2Num[$item['sku_id']] += $item['num']; | 
					
						
							|  |  |  |  |                 } else { | 
					
						
							|  |  |  |  |                     $sku2Num[$item['sku_id']] = $item['num']; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $skuList = Sku::where('id', 'in', array_keys($sku2Num))->field('id,stock')->lock(true)->select(); | 
					
						
							|  |  |  |  |             $skuList->each(function ($item) use ($sku2Num) { | 
					
						
							|  |  |  |  |                 if (isset($sku2Num[$item->id])) { | 
					
						
							|  |  |  |  |                     $item->stock += $sku2Num[$item->id]; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |             $backSkuStocks = $skuList->toArray(); | 
					
						
							|  |  |  |  |             (new Sku())->saveAll($backSkuStocks); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 订单状态改为已支付 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding | 
					
						
							|  |  |  |  |      * @return bool | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function setPaid(string $orderCoding): bool | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if (!$order = $this->findOneByWhere(['coding' => $orderCoding])) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单不存在'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($order['status'] == OrderRepository::STATUS_PAID) { | 
					
						
							|  |  |  |  |             $this->afterPaid($order['account_id'], $orderCoding); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             return true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($order['status'] != OrderRepository::STATUS_PAID && $order['status'] != OrderRepository::STATUS_WAITING) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单状态异常,若您已支付,请联系管理员'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $now = date('Y-m-d H:i:s'); | 
					
						
							|  |  |  |  |         if ($order['status'] === OrderRepository::STATUS_WAITING) { | 
					
						
							|  |  |  |  |             Db::startTrans(); | 
					
						
							|  |  |  |  |             try { | 
					
						
							|  |  |  |  |                 $payment = PaymentLog::findOne(['account_id' => $order['account_id'], 'coding' => $orderCoding]); | 
					
						
							|  |  |  |  |                 if (!$payment) { | 
					
						
							|  |  |  |  |                     PaymentLog::create([ | 
					
						
							|  |  |  |  |                         'account_id' => $order['account_id'], | 
					
						
							|  |  |  |  |                         'coding'     => $orderCoding, | 
					
						
							|  |  |  |  |                         'created_at' => $order['created_at'], | 
					
						
							|  |  |  |  |                         'paid_at'    => $now, | 
					
						
							|  |  |  |  |                         'type'       => 'order', | 
					
						
							|  |  |  |  |                         'amount'     => $order['price'], | 
					
						
							|  |  |  |  |                     ]); | 
					
						
							|  |  |  |  |                 } else { | 
					
						
							|  |  |  |  |                     $payment->paid_at = $now; | 
					
						
							|  |  |  |  |                     $payment->status  = PaymentLog::COMMON_ON; | 
					
						
							|  |  |  |  |                     $payment->save(); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 $order->status = Order::STATUS_PAID; | 
					
						
							|  |  |  |  |                 if ($order['pick_self'] == Order::COMMON_ON) { | 
					
						
							|  |  |  |  |                     //自提 改为已发货
 | 
					
						
							|  |  |  |  |                     $order->status     = Order::STATUS_SHIPPED; | 
					
						
							|  |  |  |  |                     $order->shipped_at = $now; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 $order->paid_at = $now; | 
					
						
							|  |  |  |  |                 $res            = $order->save(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 $this->afterPaid($order['account_id'], $orderCoding); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 if ($res) { | 
					
						
							|  |  |  |  |                     Db::commit(); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 return $res; | 
					
						
							|  |  |  |  |             } catch (RepositoryException $e) { | 
					
						
							|  |  |  |  |                 Db::rollback(); | 
					
						
							|  |  |  |  |                 throw new RepositoryException($e->getMessage(), $e->getCode()); | 
					
						
							|  |  |  |  |             } catch (Exception $e) { | 
					
						
							|  |  |  |  |                 //回滚
 | 
					
						
							|  |  |  |  |                 Db::rollback(); | 
					
						
							|  |  |  |  |                 self::log('支付成功状态变更失败', $e, 'error', 'order'); | 
					
						
							|  |  |  |  |                 throw new RepositoryException('操作失败'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return false; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 支付后调用 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $accountId | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function afterPaid(int $accountId, string $orderCoding) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         OrderSku::setPaid($orderCoding);//订单商品
 | 
					
						
							| 
									
										
										
										
											2022-05-27 17:18:22 +08:00
										 |  |  |  |         //OrderActivity::setPaid($orderCoding);//活动订单
 | 
					
						
							|  |  |  |  |        // OrderGroupList::setPaid($orderCoding);//订单拼团列表
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 付款后 所有商品销量添加
 | 
					
						
							|  |  |  |  |         $this->updateAmount($orderCoding); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         //清理除购物车
 | 
					
						
							|  |  |  |  |         OrderRepository::getInstance()->delShoppingCartByOrder($accountId, $orderCoding); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 取消支付后调用 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $accountId | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function afterCancelPaid(int $accountId, string $orderCoding) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         //        OrderSku::setPaid($orderCoding);//订单商品
 | 
					
						
							|  |  |  |  |         //        OrderActivity::setPaid($orderCoding);//活动订单
 | 
					
						
							|  |  |  |  |         //        OrderGroupList::setPaid($orderCoding);//订单拼团列表
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 销量减少
 | 
					
						
							|  |  |  |  |         $this->updateAmount($orderCoding, 'reduce'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 订单验收 - 确认收货 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $orderId | 
					
						
							|  |  |  |  |      * @param  int  $accountId | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function orderAccepted(int $orderId, int $accountId = 0) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         Db::startTrans(); | 
					
						
							|  |  |  |  |         try { | 
					
						
							|  |  |  |  |             $order = OrderRepository::getInstance()->findById($orderId, []); | 
					
						
							|  |  |  |  |             if (empty($order)) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('没有相关的订单记录'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $accountId = $accountId == 0 ? $order['account_id'] : $accountId; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-02 16:11:55 +08:00
										 |  |  |  |             if (!in_array($order['status']  ,[self::STATUS_SHIPPED,self::STATUS_ARRIVED])) { | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 throw new RepositoryException('当前订单状态不支持收货操作'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $accountRepo = AccountRepository::getInstance(); | 
					
						
							|  |  |  |  |             $nowDateTime = date('Y-m-d H:i:s'); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $account = $accountRepo->findById($accountId, []); | 
					
						
							|  |  |  |  |             if ($order['account_id'] !== $accountId || empty($account)) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('用户不存在'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $this->update([ | 
					
						
							|  |  |  |  |                 'status'          => self::STATUS_COMPLETED, | 
					
						
							|  |  |  |  |                 'commission_give' => Order::COMMON_ON, | 
					
						
							|  |  |  |  |                 'accepted_at'     => $nowDateTime | 
					
						
							|  |  |  |  |             ], ['id' => $orderId]); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             /* | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             CConfig::load('extra/commission_withdrawal', 'commission'); | 
					
						
							|  |  |  |  |             $config = config('commission'); | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |              */ | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             // 一级佣金发放
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             /* | 
					
						
							|  |  |  |  |            if ($account['inviter_account_id'] > 0 && isset($config['commission_first']) && $config['commission_first'] > 0) { | 
					
						
							|  |  |  |  |                $firstRate       = Math::div($config['commission_first'], 100); | 
					
						
							|  |  |  |  |                $firstCommission = Math::mul($order['price'], $firstRate); | 
					
						
							|  |  |  |  |                $accountFirst    = Account::findById($account['inviter_account_id']); | 
					
						
							|  |  |  |  |                if ($accountFirst && $firstCommission > 0) { | 
					
						
							|  |  |  |  |                    AccountDataLog::log($account['inviter_account_id'], | 
					
						
							|  |  |  |  |                        '订单确认收货-一级分销佣金发放', | 
					
						
							|  |  |  |  |                        $firstCommission, | 
					
						
							|  |  |  |  |                        AccountDataLog::TYPE_COMMISSION, | 
					
						
							|  |  |  |  |                        AccountDataLog::ACTION_ORDER, | 
					
						
							|  |  |  |  |                        Math::add($accountFirst['commission'], $firstCommission) | 
					
						
							|  |  |  |  |                    ); | 
					
						
							|  |  |  |  |                    $accountFirst->save([ | 
					
						
							|  |  |  |  |                        'commission' => Db::raw('`commission` + '.$firstCommission) | 
					
						
							|  |  |  |  |                    ]); | 
					
						
							|  |  |  |  |                } | 
					
						
							|  |  |  |  |            } | 
					
						
							|  |  |  |  |            */ | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 二级分销发放佣金
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             /* | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             if ($account['inviter_parent_id'] > 0 && isset($config['commission_second']) && $config['commission_second'] > 0) { | 
					
						
							|  |  |  |  |                 $secondRate       = Math::div($config['commission_second'], 100); | 
					
						
							|  |  |  |  |                 $secondCommission = Math::mul($order['price'], $secondRate); | 
					
						
							|  |  |  |  |                 $accountSecond    = Account::findById($account['inviter_parent_id']); | 
					
						
							|  |  |  |  |                 if ($accountSecond && $secondCommission > 0) { | 
					
						
							|  |  |  |  |                     AccountDataLog::log($account['inviter_parent_id'], | 
					
						
							|  |  |  |  |                         '订单确认收货-二级分销佣金发放', | 
					
						
							|  |  |  |  |                         $secondCommission, | 
					
						
							|  |  |  |  |                         AccountDataLog::TYPE_COMMISSION, | 
					
						
							|  |  |  |  |                         AccountDataLog::ACTION_ORDER, | 
					
						
							|  |  |  |  |                         Math::add($accountSecond['commission'], $secondCommission) | 
					
						
							|  |  |  |  |                     ); | 
					
						
							|  |  |  |  |                     $accountSecond->save([ | 
					
						
							|  |  |  |  |                         'commission' => Db::raw('`commission` + '.$secondCommission) | 
					
						
							|  |  |  |  |                     ]); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             */ | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |             Db::commit(); | 
					
						
							|  |  |  |  |         } catch (RepositoryException $e) { | 
					
						
							|  |  |  |  |             Db::rollback(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             throw new RepositoryException($e->getMessage()); | 
					
						
							|  |  |  |  |         } catch (Exception $e) { | 
					
						
							|  |  |  |  |             Db::rollback(); | 
					
						
							|  |  |  |  |             self::log('订单确认收货失败', $e, 'error', 'order'); | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单数据错误'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 我的订单 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $accountId | 
					
						
							|  |  |  |  |      * @param  string  $tag  all=全部[待付款 已付款 待发货 已发货 已完成 已取消] after_sale=售后[已发货 已完成等] | 
					
						
							|  |  |  |  |      * @param  int  $page | 
					
						
							|  |  |  |  |      * @param  int  $size | 
					
						
							|  |  |  |  |      * @return array|null | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function mine(int $accountId, string $tag, int $page = 1, int $size = 20): ?array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $where   = []; | 
					
						
							|  |  |  |  |         $where[] = ['account_id', '=', $accountId]; | 
					
						
							|  |  |  |  |         event('OrderCheck'); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |         switch ($tag) { | 
					
						
							|  |  |  |  |             //待付款 已付款 已过期 待发货 待收货
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             case self::STATUS_ORDER_PLACED: | 
					
						
							|  |  |  |  |             case self::STATUS_MAKEING: | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             case self::STATUS_SHIPPED: | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             case self::STATUS_ARRIVED: | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             case self::STATUS_COMPLETED: | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             case self::STATUS_CANCEL: | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 $status = [$tag]; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							|  |  |  |  |             // 待评价 已确认收货 未评价
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |            /* | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             case 'waiting_comment': | 
					
						
							|  |  |  |  |                 $where[] = ['is_evaluate', '=', self::IS_EVALUATE_YES]; | 
					
						
							|  |  |  |  |                 $status  = [self::STATUS_COMPLETED]; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |            */ | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             // 待核验
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             /* | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             case 'check': | 
					
						
							|  |  |  |  |                 $where[] = ['has_virtual', '=', Order::COMMON_ON]; | 
					
						
							|  |  |  |  |                 $where[] = ['virtual_check', '=', Order::COMMON_OFF]; | 
					
						
							|  |  |  |  |                 $where[] = ['frontend_check', '=', Order::COMMON_OFF]; | 
					
						
							|  |  |  |  |                 $status  = [self::STATUS_PAID, self::STATUS_COMPLETED, self::STATUS_SHIPPED]; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             */ | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             //  售后记录
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             /* | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             case 'after_sale': | 
					
						
							|  |  |  |  |                 $status  = [self::STATUS_PAID, self::STATUS_SHIPPED, self::STATUS_COMPLETED]; | 
					
						
							|  |  |  |  |                 $where[] = ['is_after_sale', '=', self::BOOL_TRUE]; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             */ | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             default: | 
					
						
							|  |  |  |  |                 $status = [ | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |                     self::STATUS_ORDER_PLACED   , | 
					
						
							|  |  |  |  |                     self::STATUS_MAKEING     , | 
					
						
							|  |  |  |  |                     self::STATUS_SHIPPED       , | 
					
						
							|  |  |  |  |                     self::STATUS_ARRIVED       , | 
					
						
							|  |  |  |  |                     self::STATUS_COMPLETED     , | 
					
						
							|  |  |  |  |                     self::STATUS_CANCEL        , | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 ]; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!empty($status)) { | 
					
						
							|  |  |  |  |             $where[] = ['status', 'in', $status]; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $fields = []; | 
					
						
							|  |  |  |  |         return $this->findList($where, $fields, $page, $size, function ($q) use ($tag) { | 
					
						
							|  |  |  |  |             return $q->with(['skus'])->order('created_at', 'desc'); | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 立即免拼 单人开团 | 
					
						
							|  |  |  |  |      * 免拼逻辑 1. 直接将订单状态修改 2. 订单相关拼团列表的剩余数量 全部设为0 | 
					
						
							|  |  |  |  |      * is_only=0 is_group_make=1 open_one=1 open_one_success=0,group_make_end_at < 当前时间 订单列表才显示【立即免拼】,其他都不显示 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $accountId | 
					
						
							|  |  |  |  |      * @param  string  $coding | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function openOne(int $accountId, string $coding) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if (!$order = Order::findOne(['coding' => $coding])) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单不存在'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($order['is_group_make'] != Order::COMMON_ON) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('不是拼团订单'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (in_array($order['status'], [Order::STATUS_WAITING, Order::STATUS_CLOSED, Order::STATUS_EXPIRED])) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单状态错误'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($order['account_id'] != $accountId) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('不是您的订单'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $order->save(['open_one_success' => Order::COMMON_ON]); | 
					
						
							|  |  |  |  |         OrderGroupList::where('coding', $coding)->save(['surplus' => 0]); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 订单数量 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $accountId | 
					
						
							|  |  |  |  |      * @return array | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function orderCount(int $accountId): array | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-05-27 17:53:06 +08:00
										 |  |  |  |         $statusList = ['order_placed', 'makeing', 'shipped']; | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |         $data       = Order::where('account_id', $accountId) | 
					
						
							|  |  |  |  |             ->whereIn('status', $statusList) | 
					
						
							|  |  |  |  |             ->group('status') | 
					
						
							|  |  |  |  |             ->column('count(`id`) as count', 'status'); | 
					
						
							|  |  |  |  |         $list       = []; | 
					
						
							|  |  |  |  |         foreach ($statusList as $status) { | 
					
						
							|  |  |  |  |             $list[$status] = $data[$status] ?? 0; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return $list; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 订单详情 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $orderId | 
					
						
							|  |  |  |  |      * @return mixed|null | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function detail(int $orderId) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $fields = []; | 
					
						
							|  |  |  |  |         return $this->findById($orderId, $fields, function ($q) { | 
					
						
							|  |  |  |  |             return $q->with(['skus'])->order('created_at', 'desc'); | 
					
						
							|  |  |  |  |         }); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 获取订单物流信息 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding | 
					
						
							|  |  |  |  |      * @return array|Model | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function logistics(string $orderCoding) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $fields = ['id', 'status', 'coding', 'is_after_sale', 'prepay_id', 'original_price', 'price', 'express_number', 'express_code', 'express_name']; | 
					
						
							|  |  |  |  |         if (!$order = $this->model->with(['skus'])->field($fields)->where('coding', $orderCoding)->find()) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单不存在'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $expressInfo = []; | 
					
						
							|  |  |  |  |         if (!empty($order['express_code']) && !empty($order['express_number'])) { | 
					
						
							|  |  |  |  |             try { | 
					
						
							|  |  |  |  |                 if ($order['status'] == self::STATUS_COMPLETED) { | 
					
						
							|  |  |  |  |                     $exprLog = $this->findExpressLogByNu($order['coding'], $order['express_code'], $order['express_number']); | 
					
						
							|  |  |  |  |                     if (!empty($exprLog)) { | 
					
						
							|  |  |  |  |                         $expressInfo['status']     = 200; | 
					
						
							|  |  |  |  |                         $expressInfo['state']      = $exprLog['state']; | 
					
						
							|  |  |  |  |                         $expressInfo['state_desc'] = Kd100::state()[$exprLog['state']] ?? ''; | 
					
						
							|  |  |  |  |                         $expressInfo['com']        = $exprLog['com']; | 
					
						
							|  |  |  |  |                         $expressInfo['nu']         = $exprLog['nu']; | 
					
						
							|  |  |  |  |                         $expressInfo['data']       = $exprLog['content']; | 
					
						
							|  |  |  |  |                     } else { | 
					
						
							|  |  |  |  |                         $expressInfo = $this->handleOrderExpressLog($order['coding'], $order['express_code'], $order['express_number']); | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                 } else { | 
					
						
							|  |  |  |  |                     $expressInfo = $this->handleOrderExpressLog($order['coding'], $order['express_code'], $order['express_number']); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } catch (Exception $e) { | 
					
						
							|  |  |  |  |                 $expressInfo = []; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $order->express_info = $expressInfo; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return $order; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 订单发货 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  int  $orderId  订单ID | 
					
						
							|  |  |  |  |      * @param  int  $expressId  快递公司ID | 
					
						
							|  |  |  |  |      * @param  string  $expressNumber  快递单号 | 
					
						
							|  |  |  |  |      * @param  string  $businessRemarks  卖家备注 | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function orderShipping(int $orderId, int $expressId, string $expressNumber = '', string $businessRemarks = '') | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         Db::startTrans(); | 
					
						
							|  |  |  |  |         try { | 
					
						
							|  |  |  |  |             $order = $this->findById($orderId, []); | 
					
						
							|  |  |  |  |             if (empty($order)) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('没有相关的订单记录'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if ($order['status'] !== self::STATUS_PAID) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('当前订单状态不支持发货操作'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $express = $this->expressInfo($expressId); | 
					
						
							|  |  |  |  |             if (empty($express)) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('相关的快递公司不存在'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (empty($expressNumber) || strlen($expressNumber) > 100) { | 
					
						
							|  |  |  |  |                 throw new RepositoryException('请填写正确的快递单号'); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             $this->update([ | 
					
						
							|  |  |  |  |                 'shipped_at'       => date('Y-m-d H:i:s'), | 
					
						
							|  |  |  |  |                 'business_remarks' => $businessRemarks, | 
					
						
							|  |  |  |  |                 'express_code'     => $express['code'], | 
					
						
							|  |  |  |  |                 'express_name'     => $express['name'], | 
					
						
							|  |  |  |  |                 'express_number'   => $expressNumber, | 
					
						
							|  |  |  |  |                 'status'           => self::STATUS_SHIPPED, | 
					
						
							|  |  |  |  |             ], ['id' => $orderId]); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             Db::commit(); | 
					
						
							|  |  |  |  |         } catch (RepositoryException $e) { | 
					
						
							|  |  |  |  |             Db::rollback(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             throw new RepositoryException($e->getMessage()); | 
					
						
							|  |  |  |  |         } catch (Exception $e) { | 
					
						
							|  |  |  |  |             Db::rollback(); | 
					
						
							|  |  |  |  |             self::log('订单发货失败', $e, 'error', 'order'); | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单发货失败'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 更新商品库存 TODO | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  array  $spuIds | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function updateSpuStock(array $spuIds) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $skuList   = Sku::whereIn('id', $spuIds)->field('id,spu_id,stock')->select()->toArray(); | 
					
						
							|  |  |  |  |         $updateSpu = []; | 
					
						
							|  |  |  |  |         foreach ($skuList as $sku) { | 
					
						
							|  |  |  |  |             $arr = []; | 
					
						
							|  |  |  |  |             //            $arr['spu']
 | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 商品规格检查 1.限购检查 2.活动时间检查 3.团购、拼团数量检查 | 
					
						
							|  |  |  |  |      * 包含活动与普通商品 | 
					
						
							|  |  |  |  |      * 商品数量不多的情况下,循环内部执行检测 TODO 待优化 部分查询可拿到循环外部 | 
					
						
							|  |  |  |  |      * @param  array  $data | 
					
						
							|  |  |  |  |      * @return bool | 
					
						
							|  |  |  |  |      * @throws RepositoryException|Exception | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function skuCheck(array $data): bool | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $now = date('Y-m-d H:i:s'); | 
					
						
							|  |  |  |  |         foreach ($data as $item) { | 
					
						
							|  |  |  |  |             //限购检测
 | 
					
						
							|  |  |  |  |             if ($item['limit_num'] > 0) { | 
					
						
							|  |  |  |  |                 //存在限购数量
 | 
					
						
							|  |  |  |  |                 $where   = []; | 
					
						
							|  |  |  |  |                 $where[] = ['is_paid', '=', OrderSku::COMMON_ON]; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 if ($item['spu_id'] > 0) { | 
					
						
							|  |  |  |  |                     $where[] = ['spu_id', '=', $item['spu_id']]; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 if ($item['spu_activity_id'] > 0) { | 
					
						
							|  |  |  |  |                     $where[] = ['spu_activity_id', '=', $item['spu_activity_id']]; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 if ($item['limit_time'] > 0) { | 
					
						
							|  |  |  |  |                     $endAt   = date('Y-m-d 23:59:59');//结束时间
 | 
					
						
							|  |  |  |  |                     $day     = ($item['limit_time'] - 1) ?: 0; | 
					
						
							|  |  |  |  |                     $str     = '-'.$day.' days'; | 
					
						
							|  |  |  |  |                     $beginAt = date('Y-m-d 00:00:00', strtotime($str)); | 
					
						
							|  |  |  |  |                     $where[] = ['paid_at', '>', $beginAt]; | 
					
						
							|  |  |  |  |                     $where[] = ['paid_at', '<', $endAt]; | 
					
						
							|  |  |  |  |                     $where[] = ['account_id', '=', $item['account_id']]; | 
					
						
							|  |  |  |  |                     //存在限购时间 数字单位为天
 | 
					
						
							|  |  |  |  |                     //结合限购数量 生效规则:N天内 限购数量-已购买数量 >= 本次购买数量 否则无法购买
 | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 $history = OrderSku::history($where, ['id', 'spu_name']); | 
					
						
							|  |  |  |  |                 if ($item['limit_num'] - $history->count() < $item['num']) { | 
					
						
							|  |  |  |  |                     throw new RepositoryException(sprintf("商品[%s]%s仅限购买%d件", $item['goods_name'], | 
					
						
							|  |  |  |  |                             $item['limit_time'] > 0 ? $item['limit_time'].'天内' : '', $item['limit_num']).$item['coding']); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 活动时间检测
 | 
					
						
							|  |  |  |  |             if (!empty($item['begin_at'])) { | 
					
						
							|  |  |  |  |                 if ($now < $item['begin_at']) { | 
					
						
							|  |  |  |  |                     throw new RepositoryException('商品['.$item['goods_name'].']商品尚未开始'); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             // 活动时间检测
 | 
					
						
							|  |  |  |  |             if (!empty($item['end_at'])) { | 
					
						
							|  |  |  |  |                 if ($now > $item['end_at']) { | 
					
						
							|  |  |  |  |                     throw new RepositoryException('商品['.$item['goods_name'].']商品已结束'); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 更新订单销量 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding | 
					
						
							|  |  |  |  |      * @param  string  $type  add=添加 reduce=减少 | 
					
						
							|  |  |  |  |      * @return bool | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      * @throws Exception | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function updateAmount(string $orderCoding, string $type = 'add'): bool | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $op = '+'; | 
					
						
							|  |  |  |  |         if ($type != 'add') { | 
					
						
							|  |  |  |  |             $op = '-'; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         $list = OrderSku::where('coding', $orderCoding)->select(); | 
					
						
							|  |  |  |  |         if ($list->isEmpty()) { | 
					
						
							|  |  |  |  |             return true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $spuList      = $list->where('spu_id', '>', 0)->toArray(); | 
					
						
							|  |  |  |  |         $activityList = $list->where('spu_activity_id', '>', 0)->toArray(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $spuUpdate = []; | 
					
						
							|  |  |  |  |         foreach ($spuList as $spu) { | 
					
						
							|  |  |  |  |             if (!isset($spuUpdate[$spu['spu_id']])) { | 
					
						
							|  |  |  |  |                 $spuUpdate[$spu['spu_id']]           = []; | 
					
						
							|  |  |  |  |                 $spuUpdate[$spu['spu_id']]['id']     = $spu['spu_id']; | 
					
						
							|  |  |  |  |                 $spuUpdate[$spu['spu_id']]['amount'] = $spu['num']; | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 $spuUpdate[$spu['spu_id']]['amount'] += $spu['num']; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         foreach ($spuUpdate as &$spu) { | 
					
						
							|  |  |  |  |             $spu['amount'] = Db::raw('`amount` '.$op.' '.$spu['amount']); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $activityUpdate = []; | 
					
						
							|  |  |  |  |         foreach ($activityList as $activity) { | 
					
						
							|  |  |  |  |             if (!isset($spuUpdate[$activity['spu_activity_id']])) { | 
					
						
							|  |  |  |  |                 $activityUpdate[$activity['spu_activity_id']]           = []; | 
					
						
							|  |  |  |  |                 $activityUpdate[$activity['spu_activity_id']]['id']     = $activity['spu_activity_id']; | 
					
						
							|  |  |  |  |                 $activityUpdate[$activity['spu_activity_id']]['amount'] = $activity['num']; | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 $activityUpdate[$activity['spu_activity_id']]['amount'] += $activity['num']; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         foreach ($activityUpdate as &$activity) { | 
					
						
							|  |  |  |  |             $activity['amount'] = Db::raw('`amount` '.$op.' '.$activity['amount']); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!empty($spuUpdate)) { | 
					
						
							|  |  |  |  |             (new Spu())->saveAll($spuUpdate); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!empty($activityUpdate)) { | 
					
						
							|  |  |  |  |             (new SpuActivity())->saveAll($activityUpdate); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 取消订单或设置过期 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding | 
					
						
							|  |  |  |  |      * @param  string  $status  操作类型 默认为取消 | 
					
						
							|  |  |  |  |      * @param  string  $reason  取消原因 | 
					
						
							|  |  |  |  |      * @return bool | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |     public function setClosed(string $orderCoding, string $status = Order::STATUS_CANCEL, string $reason = ''): bool | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |     { | 
					
						
							|  |  |  |  |         if (!$order = Order::findOne(['coding' => $orderCoding])) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单不存在'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |         if (!in_array($order['status'], [Order::STATUS_ORDER_PLACED])) { | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             throw new RepositoryException('订单状态不允许此操作'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 启动事务
 | 
					
						
							|  |  |  |  |         Db::startTrans(); | 
					
						
							|  |  |  |  |         try { | 
					
						
							|  |  |  |  |             //库存还原
 | 
					
						
							|  |  |  |  |             $this->backStock([$orderCoding]); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             // 取消拼团 拼团数量未恢复,因拼团是绝对成功。即便此拼团名额满 也可以自行发起
 | 
					
						
							|  |  |  |  |             //            OrderGroupList::cancel($orderCoding);
 | 
					
						
							|  |  |  |  |             // 活动订单取消
 | 
					
						
							|  |  |  |  |             OrderActivity::cancel($orderCoding); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             //$account             = Account::findById($order['account_id']);
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |             $order->close_reason = $reason; | 
					
						
							|  |  |  |  |             //待付款订单
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |            // if ($order['status'] == Order::STATUS_ORDER_PLACED) {
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 $order->status = $status; | 
					
						
							|  |  |  |  |                 $order->save(); | 
					
						
							|  |  |  |  |                 //积分日志
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |                 /* | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 if ($order['score'] > 0) { | 
					
						
							|  |  |  |  |                     AccountDataLog::log($order['account_id'], '取消订单退回', $order['score'], AccountDataLog::TYPE_SCORE, | 
					
						
							|  |  |  |  |                         AccountDataLog::ACTION_ORDER, $account['score'] + $order['score']); | 
					
						
							|  |  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |                 */ | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 //待付款时 积分才退回
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |                 /* | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 $account->save([ | 
					
						
							|  |  |  |  |                     'score' => Db::raw('`score` + '.$order['score']) | 
					
						
							|  |  |  |  |                 ]); | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |                 */ | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |                 // 优惠券退回
 | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |                 /* | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 AccountCoupon::where('order_coding', $orderCoding)->where('account_id', $order['account_id']) | 
					
						
							|  |  |  |  |                     ->where('coupon_id', $order['coupon_id']) | 
					
						
							|  |  |  |  |                     ->where('status', AccountCoupon::STATUS_USED) | 
					
						
							|  |  |  |  |                     ->update(['status' => AccountCoupon::STATUS_NORMAL]); | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |                 */ | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 Db::commit(); | 
					
						
							|  |  |  |  |                 return true; | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             //}
 | 
					
						
							|  |  |  |  |             /* | 
					
						
							|  |  |  |  |             if ($order['status'] == Order::STATUS_PAID && $status == Order::STATUS_CANCEL) { | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |                 //已付款订单 取消
 | 
					
						
							|  |  |  |  |                 //若已有虚拟商品被核销 则订单不允许退回 积分不退回
 | 
					
						
							|  |  |  |  |                 //                $hasCheckSku = OrderSku::where('coding', $orderCoding)
 | 
					
						
							|  |  |  |  |                 //                    ->where('is_virtual', OrderSku::COMMON_ON)
 | 
					
						
							|  |  |  |  |                 //                    ->whereRaw('`num` > `not_check_num`')
 | 
					
						
							|  |  |  |  |                 //                    ->count();
 | 
					
						
							|  |  |  |  |                 //                if ($hasCheckSku > 0) {
 | 
					
						
							|  |  |  |  |                 //                    throw new RepositoryException('订单部分商品已核销,无法进行此操作');
 | 
					
						
							|  |  |  |  |                 //                }
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 $refundCoding = generateCode(); | 
					
						
							|  |  |  |  |                 $now          = date('Y-m-d H:i:s'); | 
					
						
							|  |  |  |  |                 //售后记录
 | 
					
						
							|  |  |  |  |                 OrderAfterSale::create([ | 
					
						
							|  |  |  |  |                     'coding'      => $orderCoding, | 
					
						
							|  |  |  |  |                     'account_id'  => $order['account_id'], | 
					
						
							|  |  |  |  |                     'description' => '取消订单并退款', | 
					
						
							|  |  |  |  |                     'created_at'  => $now, | 
					
						
							|  |  |  |  |                     'status'      => OrderAfterSale::STATUS_DONE, | 
					
						
							|  |  |  |  |                 ]); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 //积分日志
 | 
					
						
							|  |  |  |  |                 if ($order['score'] > 0) { | 
					
						
							|  |  |  |  |                     AccountDataLog::log($order['account_id'], '取消订单退回', $order['score'], AccountDataLog::TYPE_SCORE, | 
					
						
							|  |  |  |  |                         AccountDataLog::ACTION_ORDER, $account['score'] + $order['score']); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 //待付款时 积分才退回
 | 
					
						
							|  |  |  |  |                 $account->save([ | 
					
						
							|  |  |  |  |                     'score' => Db::raw('`score` + '.$order['score']) | 
					
						
							|  |  |  |  |                 ]); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 // 订单金额大于0 退回
 | 
					
						
							|  |  |  |  |                 if ($order['price'] > 0) { | 
					
						
							|  |  |  |  |                     $order->is_after_sale     = Order::COMMON_ON; | 
					
						
							|  |  |  |  |                     $order->after_sale_at     = $now; | 
					
						
							|  |  |  |  |                     $order->after_sale_end_at = $now; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                     $result = WechatPay::getInstance()->refund->byOutTradeNumber($orderCoding, $refundCoding, $order['price'] * 100, $order['price'] * 100, [ | 
					
						
							|  |  |  |  |                         'refund_desc' => '【'.$orderCoding.'】订单退款', | 
					
						
							|  |  |  |  |                     ]); | 
					
						
							|  |  |  |  |                     if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'FAIL') { | 
					
						
							|  |  |  |  |                         //退款不成功
 | 
					
						
							|  |  |  |  |                         self::log('订单退款不成功['.$orderCoding.']'.$result['err_code_des'].'all_msg:'.json_encode($result), null); | 
					
						
							|  |  |  |  |                         $order->need_refund = Order::COMMON_ON;//需要退款 但未成功
 | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                     if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') { | 
					
						
							|  |  |  |  |                         self::log('订单退款成功['.$orderCoding.']'.'all_msg:'.json_encode($result), null); | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |                 $order->refund_coding = $refundCoding; | 
					
						
							|  |  |  |  |                 $order->status        = self::STATUS_CLOSED; | 
					
						
							|  |  |  |  |                 $order->save(); | 
					
						
							|  |  |  |  |                 Db::commit(); | 
					
						
							|  |  |  |  |                 return true; | 
					
						
							|  |  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-06-01 16:18:39 +08:00
										 |  |  |  |             */ | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |  |         } catch (RepositoryException $e) { | 
					
						
							|  |  |  |  |             Db::rollback(); | 
					
						
							|  |  |  |  |             throw $e; | 
					
						
							|  |  |  |  |         } catch (Exception $e) { | 
					
						
							|  |  |  |  |             Db::rollback(); | 
					
						
							|  |  |  |  |             throw new RepositoryException($e->getMessage()); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 购物车数量 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $type  类型 spu=商品购物车 score=积分商品购物车 | 
					
						
							|  |  |  |  |      * @param  int  $accountId  用户ID | 
					
						
							|  |  |  |  |      * @throws Exception | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function shoppingCartCount(int $accountId, string $type = 'spu'): int | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $isScore = (int) ($type == 'score'); | 
					
						
							|  |  |  |  |         event('CheckShoppingCart', $accountId); | 
					
						
							|  |  |  |  |         return ShoppingCart::where('is_score', $isScore)->where('account_id', $accountId)->count(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 订单付款 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding  订单编号 | 
					
						
							|  |  |  |  |      * @param  int  $accountId  用户ID | 
					
						
							|  |  |  |  |      * @throws RepositoryException|Exception | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function pay(string $orderCoding, int $accountId): array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $order = $this->findOneByWhere(['coding' => $orderCoding]); | 
					
						
							|  |  |  |  |         if (empty($order)) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('没有相关的订单记录'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($order['status'] !== self::STATUS_WAITING) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单状态已非待付款'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($order['account_id'] != $accountId) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('非本人订单'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         //统一下单
 | 
					
						
							|  |  |  |  |         //            $res = $this->wechatMiniPay($order->coding, $account->openid, $order->price);
 | 
					
						
							|  |  |  |  |         $prepayId = $order['prepay_id']; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         //生成小程序支付请求的参数
 | 
					
						
							|  |  |  |  |         $paymentParams = $this->miniPayReqParams($prepayId); | 
					
						
							|  |  |  |  |         return [ | 
					
						
							|  |  |  |  |             'prepay_id'      => $prepayId, | 
					
						
							|  |  |  |  |             'payment_params' => $paymentParams, | 
					
						
							|  |  |  |  |         ]; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 商品sku核验 线下核验 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding  订单编号 | 
					
						
							|  |  |  |  |      * @param  int  $id  订单商品ID =0则核验该订单下所有虚拟商品  >0核验具体记录 | 
					
						
							|  |  |  |  |      * @param  int  $num  核验数量 仅当$id>0时生效 | 
					
						
							|  |  |  |  |      * @param  int  $checkBy  核验人account_id  =0则后台无account用户 | 
					
						
							|  |  |  |  |      * @param  string  $checkType | 
					
						
							|  |  |  |  |      * @return bool | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      * @throws Exception | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function check(string $orderCoding, int $id = 0, int $num = 1, int $checkBy = 0, string $checkType = Order::CHECK_TYPE_FRONTEND): bool | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if (!$checkUser = Account::findById($checkBy)) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('核验人信息不存在'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($checkUser['is_staff'] != Account::COMMON_ON) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('此操作仅限员工'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $checkUserInfo = sprintf("ID:%d 昵称:%s", $checkUser['id'], $checkUser['nickname']); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return $this->checkBase($orderCoding, $id, $num, $checkUserInfo, $checkType); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 商品sku核验 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding  订单编号 | 
					
						
							|  |  |  |  |      * @param  int  $id  订单商品ID =0则核验该订单下所有虚拟商品  >0核验具体记录 | 
					
						
							|  |  |  |  |      * @param  int  $num  核验数量 仅当$id>0时生效 | 
					
						
							|  |  |  |  |      * @param  string  $checkBy  核验人信息 | 
					
						
							|  |  |  |  |      * @param  string  $checkType | 
					
						
							|  |  |  |  |      * @return bool | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      * @throws Exception | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function checkBase(string $orderCoding, int $id = 0, int $num = 1, string $checkBy = '', string $checkType = Order::CHECK_TYPE_FRONTEND): bool | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if (!$order = Order::findOne(['coding' => $orderCoding])) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单不存在'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (in_array($order['status'], [Order::STATUS_CLOSED, Order::STATUS_WAITING])) { | 
					
						
							|  |  |  |  |             // 订单关闭或未付款
 | 
					
						
							|  |  |  |  |             throw new RepositoryException('当前订单状态无法核验'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $where   = []; | 
					
						
							|  |  |  |  |         $where[] = ['coding', '=', $orderCoding]; | 
					
						
							|  |  |  |  |         $where[] = ['check_type', '=', $checkType]; | 
					
						
							|  |  |  |  |         $where[] = ['is_virtual', '=', Order::COMMON_ON];//虚拟商品 才能核验
 | 
					
						
							|  |  |  |  |         $where[] = ['is_check', '=', Order::COMMON_OFF];// 非核验完成商品 才能核验
 | 
					
						
							|  |  |  |  |         $where[] = ['not_check_num', '>', Order::COMMON_OFF];// 未核验数量大于0 才能核验
 | 
					
						
							|  |  |  |  |         if ($id > 0) { | 
					
						
							|  |  |  |  |             $where[] = ['id', '=', $id]; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $skuList = OrderSku::where($where)->select(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($skuList->isEmpty()) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('当前订单无可核验商品'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $update = []; | 
					
						
							|  |  |  |  |         foreach ($skuList as $sku) { | 
					
						
							|  |  |  |  |             $arr             = []; | 
					
						
							|  |  |  |  |             $arr['id']       = $sku['id']; | 
					
						
							|  |  |  |  |             $arr['check_by'] = $checkBy; | 
					
						
							|  |  |  |  |             if ($id > 0) { | 
					
						
							|  |  |  |  |                 // 指定订单商品核验
 | 
					
						
							|  |  |  |  |                 if ($id == $sku['id']) { | 
					
						
							|  |  |  |  |                     if ($sku['not_check_num'] < $num) { | 
					
						
							|  |  |  |  |                         throw new RepositoryException('核验商品数量不足'); | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                     if ($sku['not_check_num'] == $num) { | 
					
						
							|  |  |  |  |                         $arr['is_check'] = OrderSku::COMMON_ON; | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                     $arr['not_check_num'] = Db::raw('`not_check_num` - '.$num); | 
					
						
							|  |  |  |  |                 } else { | 
					
						
							|  |  |  |  |                     unset($arr); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 //订单下所有商品全部核验完
 | 
					
						
							|  |  |  |  |                 $arr['is_check']      = OrderSku::COMMON_ON; | 
					
						
							|  |  |  |  |                 $arr['not_check_num'] = OrderSku::COMMON_OFF; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (isset($arr)) { | 
					
						
							|  |  |  |  |                 $update[] = $arr; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 更新订单商品状态
 | 
					
						
							|  |  |  |  |         (new OrderSku())->saveAll($update); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 检测订单是否已完成所有核验
 | 
					
						
							|  |  |  |  |         $notCheckNumList = $this->checkAllVirtual($orderCoding); | 
					
						
							|  |  |  |  |         $orderUpdate     = []; | 
					
						
							|  |  |  |  |         if ($notCheckNumList['total'] == 0) { | 
					
						
							|  |  |  |  |             $orderUpdate['virtual_check'] = Order::COMMON_ON; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($notCheckNumList['frontend'] == 0) { | 
					
						
							|  |  |  |  |             $orderUpdate['frontend_check'] = Order::COMMON_ON; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($notCheckNumList['backend'] == 0) { | 
					
						
							|  |  |  |  |             $orderUpdate['backend_check'] = Order::COMMON_ON; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!empty($orderUpdate)) { | 
					
						
							|  |  |  |  |             $order->save($orderUpdate); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 商品sku核验检测 | 
					
						
							|  |  |  |  |      * 检测逻辑:打开商品二维码时,待核验的数量发生变更或为0时 标识本次核验成功 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding  订单编号 | 
					
						
							|  |  |  |  |      * @param  int  $id  订单商品ID =0则核验该订单下所有虚拟商品  >0核验具体记录 | 
					
						
							|  |  |  |  |      * @param  int  $notCheckNum  未核验的数量 | 
					
						
							|  |  |  |  |      * @return bool | 
					
						
							|  |  |  |  |      * @throws DataNotFoundException | 
					
						
							|  |  |  |  |      * @throws DbException | 
					
						
							|  |  |  |  |      * @throws ModelNotFoundException | 
					
						
							|  |  |  |  |      * @throws RepositoryException | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function checkResult(string $orderCoding, int $id, int $notCheckNum): bool | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if (!$order = Order::findOne(['coding' => $orderCoding])) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('订单不存在'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (in_array($order['status'], [Order::STATUS_CLOSED, Order::STATUS_WAITING])) { | 
					
						
							|  |  |  |  |             // 订单关闭或未付款
 | 
					
						
							|  |  |  |  |             throw new RepositoryException('当前订单状态无法核验'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (!$item = OrderSku::findById($id)) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('该商品不存在'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($item['coding'] != $orderCoding) { | 
					
						
							|  |  |  |  |             throw new RepositoryException('该商品不属于此订单'); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if ($item['not_check_num'] == 0 || $item['not_check_num'] != $notCheckNum) { | 
					
						
							|  |  |  |  |             return true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return false; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 获取订单虚拟商品未核验数量 | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding | 
					
						
							|  |  |  |  |      * @return array ['total'=所有类型未核验的数量] | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function checkAllVirtual(string $orderCoding): array | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         $where   = []; | 
					
						
							|  |  |  |  |         $where[] = ['coding', '=', $orderCoding]; | 
					
						
							|  |  |  |  |         $where[] = ['is_virtual', '=', Order::COMMON_ON];// 虚拟商品
 | 
					
						
							|  |  |  |  |         $where[] = ['is_check', '=', Order::COMMON_OFF];// 未核验完成
 | 
					
						
							|  |  |  |  |         $where[] = ['not_check_num', '>', Order::COMMON_OFF];// 未核验数量大于0
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         $res          = []; | 
					
						
							|  |  |  |  |         $res['total'] = 0; | 
					
						
							|  |  |  |  |         $countList    = OrderSku::where($where)->group('check_type')->column('count(`id`) as count', 'check_type'); | 
					
						
							|  |  |  |  |         foreach (Order::checkTypeList() as $type) { | 
					
						
							|  |  |  |  |             $res[$type]   = $countList[$type] ?? 0; | 
					
						
							|  |  |  |  |             $res['total'] += $res[$type]; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return $res; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     public function userOrderList(int $accountId, array $where = [], int $page = 1, int $size = 0, array $statusArray = []) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         return Order::when(!empty($statusArray), function ($q) use ($statusArray) { | 
					
						
							|  |  |  |  |             $q->whereIn('status', $statusArray); | 
					
						
							|  |  |  |  |         })->where($where) | 
					
						
							|  |  |  |  |             ->when($size > 0, function ($q) use ($page, $size) { | 
					
						
							|  |  |  |  |                 $q->page($page, $size); | 
					
						
							|  |  |  |  |             }) | 
					
						
							|  |  |  |  |             ->order('id', 'desc') | 
					
						
							|  |  |  |  |             ->where('account_id', $accountId) | 
					
						
							|  |  |  |  |             ->select(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /** | 
					
						
							|  |  |  |  |      * 获取订单的拼团ID | 
					
						
							|  |  |  |  |      * | 
					
						
							|  |  |  |  |      * @param  string  $orderCoding | 
					
						
							|  |  |  |  |      * @return mixed | 
					
						
							|  |  |  |  |      */ | 
					
						
							|  |  |  |  |     public function groupId(string $orderCoding) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         return OrderGroupList::where('coding', $orderCoding) | 
					
						
							|  |  |  |  |             ->where('is_paid', OrderGroupList::COMMON_ON) | 
					
						
							|  |  |  |  |             ->value('group_id', 0); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     public function getOrderSku($id) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         return OrderSku::findById($id); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     public function getOrderOriginalPrice($orderCodeing,$skuCoding) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         return OrderSku::where("order_coding",$orderCodeing)->where("coding","<>",$skuCoding)->sum("subtotal"); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } |