OrderCode::ORDER_TYPE_GOOD_PREFIX . '_' .date("YmdHis") . $userId . mt_rand(10000000, 99999999), OrderCode::ORDER_TYPE_BALANCE => OrderCode::ORDER_TYPE_BALANCE_PREFIX. '_' .date("YmdHis"). $userId. mt_rand(10000000, 99999999), }; } /** * @param int $type * @param int $userId * @return string */ protected function generateRefundOrderNo(int $type,int $userId): string { return match ($type) { OrderCode::ORDER_TYPE_GOOD => RefundCode::ORDER_TYPE_GOOD_PREFIX . '_' .date("YmdHis") . $userId . mt_rand(10000000, 99999999), OrderCode::ORDER_TYPE_BALANCE => RefundCode::ORDER_TYPE_BALANCE_PREFIX. '_' .date("YmdHis"). $userId. mt_rand(10000000, 99999999), }; } /** * 生成购物车数据 * @param array $data * @return void */ protected function buildCartData(array $data): void { $copies = 0; foreach ($data as $oneCopies) { $one = []; foreach ($oneCopies as $oneGood) { $this->cartFirstData[$oneGood] = ($this->cartFirstData[$oneGood] ?? 0) + 1; $one[$oneGood] = ($one[$oneGood] ?? 0) + 1; } $this->cartSecondData[] = $one; $copies++; } $this->copies = $copies; } /** * 检测商品 * @return void * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ protected function checkGood(): void { foreach ($this->cartFirstData as $key => $one) { if (!in_array($key, $this->goodIds)) throw new ErrException('商品不存在',ApiCode::ORDER_GOOD_IN_EXISTENCE); if ($this->orderType == 0) $this->orderType = $this->skuArr[$key]['type']; if ($this->skuArr[$key]['type'] != $this->orderType) throw new ErrException('自选菜品跟套餐菜品请分开订单下单'); if ($this->orderType != OrderCode::ORDER_TYPE_MEAL) return; if ($this->isMealCateringByCache($this->siteId, $key, $this->cycleId)) throw new ErrException('该点位的套餐'.$this->skuArr[$key]['title'].'已配餐截单,请选择其他套餐'); } } /** * 检测库存 * @return void * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ protected function checkStock(): void { foreach ($this->cartFirstData as $key => $one) { if (($this->redis->zScore($this->stockKey,$key) ?? 0) >= $one) continue; throw new ErrException('商品库存不足',ApiCode::ORDER_GOOD_INSUFFICIENT_STOCK); } } /** * @return void * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ protected function checkTodayCutOffTime(): void { $todayCutOffTime = $this->configCache->getConfigValue(ConfigCode::TODAY_CUT_OFF_TIME_KEY); $newCycleTime = $this->configCache->getConfigValue(ConfigCode::START_OF_THE_NEW_CYCLE); if (date('H:i:s') >= $todayCutOffTime && date('H:i:s') < $newCycleTime) throw new ErrException('平台已全部截止下单哦'); } /** * 检测地点 * @param int $siteId * @return int * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ protected function checkSite(int $siteId): int { $siteInfo = $this->siteCache->getSiteInfo($siteId); if (empty($siteInfo)) throw new ErrException('该地点暂时不支持点餐'); $kitchenId = (int)($siteInfo['kitchen_id'] ?? 0); if ($kitchenId <= 0) throw new ErrException('该地点暂时不支持点餐'); $closeOrderFlag = match ($this->orderType) { OrderCode::ORDER_TYPE_OPTIONAL => $this->checkIsStopOrder($siteId, $this->cycleId), OrderCode::ORDER_TYPE_MEAL => $this->checkMealIsStopOrder($siteId, $this->cycleId), }; if ($closeOrderFlag) throw new ErrException('该点已经截单'); $this->orderRes['site_id'] = $siteId; $this->orderRes['site_info'] = $siteInfo; return $kitchenId; } /** * 获取商品信息 * @param int $kitchenId * @return void * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ protected function getGoodInfo(int $kitchenId): void { $this->stockKey = ApiRedisKey::goodStockKey($this->cycleId,$kitchenId); if (!$this->redis->exists($this->stockKey)) throw new ErrException('库存不足'); $skuArr = []; // $skuImageArr = []; switch ($this->orderType) { case OrderCode::ORDER_TYPE_OPTIONAL: $optionalGoodKey = ApiRedisKey::optionalGoodListKey($this->cycleId,$kitchenId); $optionalGood = $this->redis->get($optionalGoodKey); if (empty($optionalGood)) throw new ErrException('商品不存在'); $optionalGood = json_decode($optionalGood, true); foreach ($optionalGood as $one){ $newSkuList = array_map(function($sku) use($one) { $sku['spu_title'] = strtolower($one['title']); $sku['type'] = GoodCode::SPU_TYPE_OPTIONAL; return $sku; }, $one['sku_list']); // // $skuImageArr = array_merge($skuImageArr,[ // $one['id'] => $one['url'] // ]); $skuArr = array_merge($skuArr,$newSkuList); } break; case OrderCode::ORDER_TYPE_MEAL: $mealGoodKey = ApiRedisKey::mealGoodListKey($this->cycleId,$kitchenId); $mealGood = $this->redis->get($mealGoodKey); if (empty($mealGood)) throw new ErrException('商品不存在'); $mealGood = json_decode($mealGood, true); foreach ($mealGood as $one){ $newSkuList = array_map(function($sku) use($one) { $sku['spu_title'] = $one['title']; $sku['type'] = GoodCode::SPU_TYPE_MEAL; return $sku; }, $one['sku_list']); // $skuImageArr = array_merge($skuImageArr,[ // $one['id'] => $one['url'] // ]); // $skuImageArr = array_merge($skuImageArr,$one['image_list']); $skuArr = array_merge($skuArr,$newSkuList); } break; default: throw new ErrException('还不支持下单'); } $this->skuArr = array_column($skuArr,null,'id'); // $this->skuImageArr = array_column($skuArr,null,'id'); $this->goodIds = array_column($skuArr,'id'); unset($skuArr); } /** * @return int */ protected function getAutoCouponId(): int { return 0; } /** * 计算价格 * @return void */ protected function computePrice(): void { $this->orderRes['good_ids'] = $this->cartSecondData; foreach ($this->cartSecondData as $oneCopies) { $oneCopiesTotalPrice = '0.00'; // $copiesType = 1; $oneCopiesGoodInfo = []; foreach ($oneCopies as $key => $oneGood) { if (empty($oneCopiesGoodInfo[$key])) { $oneCopiesGoodInfo[$key] = [ 'num' => $oneGood, 'good_name' => $this->skuArr[$key]['spu_title'] ?? '' . $this->skuArr[$key]['title'] ?? '', 'good_url' => $this->skuArr[$key]['url'] ?? '', 'unit_price' => $this->skuArr[$key]['price'], 'type' => $this->skuArr[$key]['type'], 'id' => $key, 'spu_id' => $this->skuArr[$key]['spu_id'], 'is_add_staple_food' => $this->skuArr[$key]['is_add_staple_food'], 'meal_copies' => $this->skuArr[$key]['is_add_staple_food'] == GoodCode::IS_ADD_STAPLE_FOOD ? 0 : 1, ]; } else { $oneCopiesGoodInfo[$key]['num'] += $oneGood; } $oneCopiesTotalPrice = bcadd($oneCopiesTotalPrice, bcmul($this->skuArr[$key]['price'],(string)$oneGood,2),2); } $this->orderRes['good'][] = [ 'good_info' => array_values($oneCopiesGoodInfo), 'price' => $oneCopiesTotalPrice, ]; // 加一份米饭不算份数 switch ($this->orderType) { case OrderCode::ORDER_TYPE_OPTIONAL: $this->orderRes['copies']++; break; case OrderCode::ORDER_TYPE_MEAL: $this->orderRes['copies'] = $this->orderRes['copies'] + array_sum(array_column($oneCopiesGoodInfo,'meal_copies')); break; } // if ($this->skuArr[$key]['is_add_staple_food'] != GoodCode::IS_ADD_STAPLE_FOOD) $this->orderRes['copies']++; $this->orderRes['total_good_price'] = bcadd($this->orderRes['total_good_price'],$oneCopiesTotalPrice,2); } } /** * 计算服务费 * @return void * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ protected function computeSundryPrice(): void { $this->orderRes['sundry_num'] = match ((int)$this->configCache->getConfigValueByKey(ConfigCode::SUNDRY_PRICE_COMPUTE_TYPE)) { 1 => $this->orderType == OrderCode::ORDER_TYPE_OPTIONAL ? $this->copies : 0, 2 => $this->orderType == OrderCode::ORDER_TYPE_MEAL ? $this->copies : 0, 3 => $this->copies, }; $this->orderRes['sundry_price'] = $this->configCache->getConfigValueByKey(ConfigCode::SUNDRY_UNIT_PRICE); $this->orderRes['total_sundry_price'] = bcmul($this->orderRes['sundry_price'],(string)$this->orderRes['sundry_num'],2); } // /** // * 计算优惠 // * @return void // */ // protected function computeFavorable(): void // { // if ($this->couponId <= 0 && $this->isAutoSelectCoupon == 1) { // $this->couponId = $this->getAutoCouponId(); // } // // if ($this->couponId <= 0) { // $this->orderRes['coupon_id'] = 0; // $this->orderRes['coupon'] = []; // $this->orderRes['favorable_good_price'] = '0'; // $this->orderRes['favorable_sundry_price'] = '0'; // return; // } // // $couponInfo = []; // todo 优惠券信息 // // $this->orderRes['coupon_id'] = $this->couponId; // $this->orderRes['coupon'] = $couponInfo; // // //todo 优惠计算 // $this->orderRes['favorable_good_price'] = '1.00'; // $this->orderRes['favorable_sundry_price'] = '1.00'; // } /** * 计算最终价格 * @return void */ protected function computeFinallyPrice(): void { $this->orderRes['good_after_discount_price'] = bcsub($this->orderRes['total_good_price'],$this->orderRes['favorable_good_price'],2); $this->orderRes['sundry_after_discount_price'] = bcsub($this->orderRes['total_sundry_price'],$this->orderRes['favorable_sundry_price'],2); $this->orderRes['total_price'] = bcadd($this->orderRes['total_good_price'],$this->orderRes['total_sundry_price'],2); $this->orderRes['actual_price'] = bcadd($this->orderRes['good_after_discount_price'],$this->orderRes['sundry_after_discount_price'],2); } /** * @param int $orderId * @param int $orderStatus * @param array $refundGoodIds * @return void * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ protected function sendStockMq(int $orderId,int $orderStatus,array $refundGoodIds = []): void { $message = new OrderGoodStockProducer([ 'order_id' => $orderId, 'type' => $orderStatus, 'refund_goods' => $refundGoodIds ]); $producer = ApplicationContext::getContainer()->get(Producer::class); $producer->produce($message); } /** * 重载计算 * @return void */ protected function reloadCompute(): void { if ($this->couponId <= 0 || empty($this->orderRes['coupon']) || $this->orderRes['coupon_id'] <= 0) return; if ($this->orderRes['coupon']['amount'] <= 0 && $this->orderRes['coupon']['coupon_type'] != CouponCode::COUPON_TYPE_INSTANT_REDUCTION) { // $orderMaxPrice = max(array_column($this->orderRes['good'],'price')); $this->orderRes['coupon']['amount'] = match ($this->orderRes['coupon']['coupon_type']) { CouponCode::COUPON_TYPE_INSTANT_REDUCTION => $this->orderRes['coupon']['amount'], CouponCode::COUPON_TYPE_DISCOUNT => bcmul( bcdiv( bcsub( "100", (string)$this->orderRes['coupon']['ratio'], 2 ), "100", 2 ), max(array_column($this->orderRes['good'],'price')), 2 ), default => 0 }; } $this->orderRes['favorable_good_price'] = $this->orderRes['coupon']['coupon_type'] == CouponCode::COUPON_TYPE_INSTANT_REDUCTION ? min($this->orderRes['coupon']['amount'], $this->orderRes['good_after_discount_price']) : $this->orderRes['coupon']['amount']; $this->orderRes['good_after_discount_price'] = bcsub($this->orderRes['good_after_discount_price'],$this->orderRes['favorable_good_price'],2); $this->orderRes['actual_price'] = bcsub($this->orderRes['actual_price'],$this->orderRes['favorable_good_price'],2); } /** * @return void */ protected function getCouponInfo(): void { if ($this->couponId <= 0) return; $couponInfo = $this->userCouponModel->where('id', $this->couponId)->where('user_id',$this->userId)->first(); if (empty($couponInfo)) throw new ErrException('优惠券信息错误'); if (in_array($couponInfo->status,[CouponCode::COUPON_STATUS_USED,CouponCode::COUPON_STATUS_EXPIRE])) throw new ErrException('优惠券已经被使用'); $couponTemplateInfo = $this->couponTemplateModel->getInfoById($couponInfo->coupon_template_id); if (empty($couponTemplateInfo)) throw new ErrException('优惠券信息错误'); $this->couponId = $couponInfo->id; $this->orderRes['coupon'] = [ 'id' => $couponInfo->id, 'coupon_type' => $couponTemplateInfo->coupon_type, 'amount' => $couponTemplateInfo->amount, 'ratio' => $couponTemplateInfo->ratio, 'coupon_template_id' => $couponTemplateInfo->id, 'coupon_name' => $couponInfo->coupon_name, 'status' => $couponInfo->status, 'validity_start_time' => $couponInfo->validity_start_time, 'validity_end_time' => $couponInfo->validity_end_time, ]; $this->orderRes['coupon_id'] = $couponInfo->id; } }