// +---------------------------------------------------------------------- declare (strict_types=1); namespace app\api\service\order; use app\api\model\card\UserRiceCard as UserRiceCardModel; use app\api\model\card\UserRiceCardConsume as UserRiceCardConsumeModel; use app\api\model\fullsend\FullSendActivity; use app\api\model\GoodsCategoryRel as GoodsCategoryRelModel; use app\api\model\GoodsPackage as GoodsPackageModel; use app\api\model\member\DeductionLimit as DeductionLimitModel; use app\api\model\member\MemberGoods; use app\api\model\mj\MjSendActivity; use app\api\model\OrderGoodsTaocan as OrderGoodsTaocanModel; use app\api\model\Order as OrderModel; use app\api\model\qc\QcMjSendActivity; use app\api\model\User as UserModel; use app\api\model\Goods as GoodsModel; use app\api\model\Setting as SettingModel; use app\api\model\shop\Shops; use app\api\model\UserAddress; use app\api\model\UserCoupon as UserCouponModel; use app\api\model\member\GoldRice as GoldRiceModel; use app\api\service\User as UserService; use app\api\service\Payment as PaymentService; use app\api\service\coupon\GoodsDeduct as GoodsDeductService; use app\api\service\ricecard\GoodsDeduct as RiceDeductService; use app\api\service\points\GoodsDeduct as PointsDeductService; use app\api\service\order\source\checkout\Factory as CheckoutFactory; use app\common\enum\Setting as SettingEnum; use app\common\enum\order\PayType as OrderPayTypeEnum; use app\common\enum\order\OrderStatus as OrderStatusEnum; use app\common\enum\order\OrderSource as OrderSourceEnum; use app\common\enum\order\DeliveryType as DeliveryTypeEnum; use app\common\service\BaseService; use app\common\service\card\UserRiceCard as UserRiceCardService; use app\common\service\commission\RecordWaitCommission; use app\common\service\delivery\Express as ExpressService; use app\common\service\goods\source\Factory as StockFactory; use app\common\library\helper; use app\common\exception\BaseException; use app\common\enum\order\PayStatus as PayStatusEnum; use app\common\model\ShopGoodsSku; use app\common\model\User; /** * 订单结算台服务类 * Class Checkout * @package app\api\service\order */ class CheckoutExchange extends BaseService { /* $model OrderModel 订单模型 */ public $model; /* @var UserModel $user 当前用户信息 */ private $user; // 订单结算商品列表 private $goodsList = []; private $invalidGoodsList = []; private $shopInfo = []; // 错误信息 protected $error; // 错误信息状态 protected $errorStatus; /** * 订单结算api参数 * @var array */ private $param = [ 'delivery' => DeliveryTypeEnum::EXPRESS, // 配送方式 默认:快递配送 'couponId' => 0, // 优惠券id 'riceCardId' => 0, // 现金米卡id 'isUsePoints' => 0, // 是否使用积分抵扣 'isUseGoldRice' => 0, // 默认使用金米粒 'remark' => '', // 买家留言 'payType' => OrderPayTypeEnum::EXCHANGE, // 支付方式 'addressId' => 0, //地址ID 'staffUserId' => 0, //分享链接用户ID ]; /** * 订单结算的规则 * @var array */ private $checkoutRule = [ 'isUserGrade' => false, // 会员等级折扣 'isCoupon' => false, // 优惠券抵扣 'isRiceCard' => false, // 现金米卡抵扣 'isUsePoints' => false, // 是否使用积分抵扣 ]; /** * 订单来源 * @var array */ private $orderSource = [ 'source' => OrderSourceEnum::MASTER, 'source_id' => 0, ]; /** * 订单结算数据 * @var array */ private $orderData = []; /** * 构造函数 * Checkout constructor. * @throws BaseException */ public function __construct() { parent::__construct(); $this->user = UserService::getCurrentLoginUser(true); $this->model = new OrderModel; $this->storeId = $this->getStoreId(); } /** * 设置结算台请求的参数 * @param $param * @return array */ public function setParam($param) { $this->param = array_merge($this->param, $param); return $this->getParam(); } /** * 获取结算台请求的参数 * @return array */ public function getParam() { return $this->param; } /** * 订单结算的规则 * @param $data * @return $this */ public function setCheckoutRule($data) { $this->checkoutRule = array_merge($this->checkoutRule, $data); return $this; } /** * 设置订单来源(普通订单) * @param $data * @return $this */ public function setOrderSource($data) { $this->orderSource = array_merge($this->orderSource, $data); return $this; } /** * 订单确认-结算台 * @param $goodsList * @return array * @throws BaseException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function onCheckout($goodsList) { // 订单确认-立即购买 $this->goodsList = $goodsList; return $this->checkout(); } //积分兑换商品 public function onCheckoutExchange($goodsList) { $this->goodsList = $goodsList; $this->orderData = $this->getOrderData(); $this->validateGoodsList(); $this->orderData['distributorTotalMoney'] = 0; $this->orderData['activityDiscountTotalPrice'] = 0; $this->orderData['memberTotalMoney'] = 0; // 设置订单商品总金额(不含优惠折扣,不含会员折扣,不含金米粒抵扣,不含专属优惠) $this->setOrderTotalPrice(); // 计算优惠券抵扣 $this->setOrderCouponMoney([], (int)$this->param['couponId']); //订单总运费金额 $this->setOrderExpress(); //金米粒抵扣-V1.4.0版本添加2022年6月1日,运费不能抵扣金米粒 $this->setOrderGolRiceAmount(); //金米粒获取-V1.4.0版本添加2022年6月7日,运费不获取金米粒 $this->setOrderInputGolRiceAmount(); $this->setOrderRiceCardMoney([],-1); // 计算订单最终金额+运费 $this->setOrderPayPrice(); //设置满件送活动是否有赠送商品--一定要放在满就送后面来处理,不然会报错 $this->setMjGoodsList(); // 订单商品总数量 $orderTotalNum = helper::getArrayColumnSum($this->goodsList, 'total_num') + helper::getArrayColumnSum($this->invalidGoodsList, 'total_num'); return array_merge([ 'goodsList' => $this->goodsList, // 商品信息 'invalidGoodsList' => $this->invalidGoodsList, // 无效商品信息(门店无库存) 'shopInfo' => $this->shopInfo, // 门店信息 'isPickup' => false, // 是否支持门店自提 true-支持 false-不支持 'orderTotalNum' => $orderTotalNum, // 商品总数量 // 'couponList' => array_values($couponList), // 优惠券列表 'hasError' => $this->hasError(), 'errorMsg' => $this->getError(), 'errorStatus' => $this->getErrorStatus(), ], $this->orderData); } /** * 订单结算台 * @return array * @throws BaseException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ private function checkout() { // 整理订单数据 $this->orderData = $this->getOrderData(); // 门店自提处理 $this->setShopPickupData(); // 验证商品状态, 是否允许购买 $this->validateGoodsList(); // 设置订单商品会员折扣价 $this->setOrderGoodsGradeMoney(); //活动使用排序:N件X折活动 > 会员折扣 > 优惠券 > 推荐官专属折扣 > 金米粒抵扣 > 满就赠 > 全场满件送 > 满件送 //设置N件X折活动优惠-v1.3.6版本添加2022年3月11日 $this->setActivityDiscountMoney(); // 设置订单商品总金额(不含优惠折扣,不含会员折扣,不含金米粒抵扣,不含专属优惠) $this->setOrderTotalPrice(); //会员折扣-V1.4.0版本添加2022年6月1日 $this->setOrderGoodsMemberMoney(); // 当前用户可用的优惠券列表 // $couponList = $this->getUserCouponList((float)$this->orderData['orderTotalPrice']); $couponList = $this->getUserCouponList(); // 计算优惠券抵扣 $this->setOrderCouponMoney($couponList, (int)$this->param['couponId']); //设置分销员购物或分享后用户购买的折扣价-V1.2.2.2版本添加2021年11月18日 $this->setOrderGoodsDistributorMoney(); // 计算可用积分抵扣 $this->setOrderPoints(); //订单总运费金额 $this->setOrderExpress(); //金米粒抵扣-V1.4.0版本添加2022年6月1日,运费不能抵扣金米粒 $this->setOrderGolRiceAmount(); //金米粒获取-V1.4.0版本添加2022年6月7日,运费不获取金米粒 $this->setOrderInputGolRiceAmount(); //获取当前可用的现金卡列表 $userRiceCardList = $this->getUserRiceCardList(); //计算使用米卡现金券抵扣后的金额-start $this->setOrderRiceCardMoney($userRiceCardList,(int)$this->param['riceCardId']); //计算使用米卡现金券抵扣后的金额-end // 计算订单商品的实际付款金额 $this->setOrderGoodsPayPrice(); // 计算订单最终金额+运费 $this->setOrderPayPrice(); // 计算订单积分赠送数量 $this->setOrderPointsBonus(); //订单商品的所有店铺集合2021年9月28日 10:56:45 $this->setOrderProviderIds(); // 无效商品信息处理 $this->setInvalidGoods(); // 订单商品总数量 $orderTotalNum = helper::getArrayColumnSum($this->goodsList, 'total_num') + helper::getArrayColumnSum($this->invalidGoodsList, 'total_num'); //设置满就送活动是否有赠送商品--一定要放在所有优惠后面最后面来处理,不然会报错 $this->setFullGoodsList(); //设置全场满件送活动是否有赠送商品--一定要放在满就送后面来处理,不然会报错 $this->setQcMjGoodsList(); //设置满件送活动是否有赠送商品--一定要放在满就送后面来处理,不然会报错 $this->setMjGoodsList(); // 验证商品状态, 是否允许购买 // $this->validateGoodsList(); // 返回订单数据 return array_merge([ 'goodsList' => $this->goodsList, // 商品信息 'invalidGoodsList' => $this->invalidGoodsList, // 无效商品信息(门店无库存) 'shopInfo' => $this->shopInfo, // 门店信息 'isPickup' => $this->isPickup, // 是否支持门店自提 true-支持 false-不支持 'orderTotalNum' => $orderTotalNum, // 商品总数量 // 'couponList' => array_values($couponList), // 优惠券列表 'hasError' => $this->hasError(), 'errorMsg' => $this->getError(), 'errorStatus' => $this->getErrorStatus(), ], $this->orderData); } /** * 设置N件X折活动优惠设置 * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException * @author: zjwhust * @Time: 2022/3/11 11:28 */ public function setActivityDiscountMoney(){ // 设置默认数据:订单信息 helper::setDataAttribute($this->orderData, [ 'activityDiscountList' => [], // N件X折优惠列表 'activityDiscountTotalPrice' => 0.00, // N件X折优惠总金额 ], false); // 设置默认数据 helper::setDataAttribute($this->goodsList, [ // 是否参与N件X折活动 0否 1是 'is_activity_discount' => 0, // N件X折活动ID 'activity_discount_id' => 0, // N件X折活动折扣金额 'activity_discount_total_price' => 0.00,//N件活动折扣金额 // N件X折活动描述 'activity_discount_desc' => '', // N件X折活动叠加优惠 1-优惠券 2-满就送 3-满件送 多个以逗号分隔 'activity_discount_overlay' => '', 'activity_discount_count' => '',//数量 ], true); $i = 0; foreach ($this->goodsList as $item){ (new GoodsModel)->getActivityDiscountDetail($item,2); if($item['is_activity_discount']){ $this->orderData['activityDiscountList'][$i]['goods_id'] = $item['goods_id']; $this->orderData['activityDiscountList'][$i]['goods_image'] = $item['goods_image']; $this->orderData['activityDiscountList'][$i]['activity_discount_total_price'] = $item['activity_discount_total_price']; $this->orderData['activityDiscountList'][$i]['activity_discount_desc'] = $item['activity_discount_desc']; $this->orderData['activityDiscountList'][$i]['total_price'] = $item['total_price']; $i++; $this->orderData['activityDiscountTotalPrice'] += $item['activity_discount_total_price']; } } $this->orderData['activityDiscountTotalPrice'] = helper::number2($this->orderData['activityDiscountTotalPrice']);//设置订单优惠合计 } /** * 判断满就送商品是否需要添加 */ public function setFullGoodsList() { $isFull = FullSendActivity::validActivityList($this->goodsList,$this->orderData); } /** * 判断全场满件送商品是否需要添加 */ public function setQcMjGoodsList() { $isMj = QcMjSendActivity::validActivityList($this->goodsList,$this->orderData); if($isMj){ foreach ($this->goodsList as $good){ foreach ($isMj as $key=>$num){ if($num>0 && $good['goods_id']==$key && ($good['total_num']+$num)>$good['skuInfo']['stock_num']){ // dd($good['total_num']+$num-$good['skuInfo']['stock_num']); $this->setError("很抱歉,赠品 [".limit_str((string)$good['goods_name'])."] 库存不足"); $this->setErrorStatus(424); } } } } } /** * 判断满件送商品是否需要添加 */ public function setMjGoodsList() { $isMj = MjSendActivity::validActivityList($this->goodsList,$this->orderData); // dd($isMj); if($isMj){ foreach ($this->goodsList as $good){ foreach ($isMj as $key=>$num){ if($num>0 && $good['goods_id']==$key && ($good['total_num']+$num)>$good['skuInfo']['stock_num']){ // dd($good['total_num']+$num-$good['skuInfo']['stock_num']); $this->setError("很抱歉,赠品 [".limit_str((string)$good['goods_name'])."] 库存不足"); $this->setErrorStatus(424); } } } } // return $status; } /** * 门店自提处理 */ public function setShopPickupData() { $deliveryType = $this->param['delivery']; // 返回商品处理 $normalGoodsList = []; // 正常状态商品 $invalidGoodsList = []; // 无货状态商品 // 门店信息 $userStaff = User::detail($this->param['staffUserId']); $shopInfo = []; $isPickup = false; if (!empty($userStaff) && $userStaff['role'] == User::SHOP_SELLER) { $shopInfo = Shops::find($userStaff['shop_id']); if ($shopInfo['is_pickup']) { $isPickup = true; } } if ($deliveryType == DeliveryTypeEnum::SHOPS_DELIVERY) { if (empty($shopInfo)) { // 门店自提方式 且门店不存在 throwError("不支持门店自提方式"); } if (!$shopInfo['is_pickup']) { // 门店自提开关 throwError("不支持门店自提方式"); } } // 门店库存总和 $shopStockTotal = 0; foreach($this->goodsList as &$item) { // 获取商品门店库存 if ($shopInfo) { $shopGoodsSku = ShopGoodsSku::with('shopGoods')->where(['shop_id' => $shopInfo['shop_id'], 'goods_id' => $item['goods_id'], 'goods_sku_id' => $item['goods_sku_id']])->find(); if (!empty($shopGoodsSku) && $shopGoodsSku['stock_num'] > 0) { $shopStockTotal += $shopGoodsSku['stock_num']; } } // 判断配送方式 if ($deliveryType == DeliveryTypeEnum::EXPRESS) { // 快递配送 $normalGoodsList[] = $item; // 判断库存 todo 购买数量大于实际库存 取实际库存 // 有库存 if ($item['skuInfo']['stock_num'] >= $item['total_num']) { $item['stock_enough'] = true; } else { $item['stock_enough'] = false; $item['total_num'] = $item['skuInfo']['stock_num']; // 库存不够时,取最大库存 $item['total_price'] = helper::bcmul($item['goods_price'], $item['total_num']); } $item['is_pickup_invalid'] = false; } elseif ($deliveryType == DeliveryTypeEnum::SHOPS_DELIVERY) { // 门店自提 // 判断有无库存 if (!empty($shopGoodsSku)) { $item['stock_total'] = $shopGoodsSku['shopGoods']['stock_total']; $item['alarm_stock_total'] = $shopGoodsSku['shopGoods']['alarm_stock_total']; $item['skuInfo']['stock_num'] = $shopGoodsSku['stock_num']; $item['skuInfo']['alarm_stock_num'] = $shopGoodsSku['alarm_stock_num']; if ($shopGoodsSku['stock_num'] > 0) { // 有库存 if ($shopGoodsSku['stock_num'] >= $item['total_num']) { $item['stock_enough'] = true; } else { $item['stock_enough'] = false; $item['total_num'] = $shopGoodsSku['stock_num']; // 库存不够时,取最大库存 $item['total_price'] = helper::bcmul($item['goods_price'], $item['total_num']); } $normalGoodsList[] = $item; } else { // 没有库存 $item['stock_enough'] = false; $item['is_pickup_invalid'] = true; $invalidGoodsList[] = $item; } } else { // 无库存 // $item['stock_total'] = 0; // $item['alarm_stock_total'] = 0; // $item['skuInfo']['stock_num'] = 0; // $item['skuInfo']['alarm_stock_num'] = 0; $item['stock_enough'] = false; // $item['total_num'] = 0; // 无门店库存 // $item['total_price'] = 0; $item['is_pickup_invalid'] = true; $invalidGoodsList[] = $item; } } } if ($shopStockTotal <= 0) { // 门店总库存不大于0 $isPickup = false; } $this->shopInfo = $shopInfo; // 门店信息 $this->isPickup = $isPickup; // 是否支持门店自提 $this->orderData['shopInfo'] = $shopInfo; // $this->goodsList = $normalGoodsList; // $this->invalidGoodsList = $invalidGoodsList; } /** * 无效商品信息处理 */ public function setInvalidGoods() { $normalGoodsList = []; // 正常状态商品 $invalidGoodsList = []; // 无货状态商品 foreach($this->goodsList as $item) { if (!$item['is_pickup_invalid']) { // 快递配送 $normalGoodsList[] = $item; } else { $invalidGoodsList[] = $item; } } $this->goodsList = $normalGoodsList; $this->invalidGoodsList = $invalidGoodsList; } //我的可用现金卡 public function getUserRiceCardList(){ $user = UserService::getCurrentLoginUser(true); $list = UserRiceCardModel::getUserRiceCardList($user['user_id'])->toArray(); $data = []; foreach ($list as $key=>&$item){ $i = 0; $exceptGoodsId = helper::getArrayColumn($item['riceCardGoodsExcept'],'goods_id'); foreach ($this->goodsList as $good) { if(!empty($item['dk_cat_ids']) && strpos((string)$item['dk_cat_ids'],(string)$good['category']['category_id']) === false){ unset($list[$key]); $i = 1; } if(!empty($exceptGoodsId) && in_array($good['goods_id'],$exceptGoodsId)){ unset($list[$key]); $i = 1; } } if(!$i){ unset($item['riceCardGoodsExcept']); $data[$item['id']] = $item; } } if($this->param['riceCardId']==0){ //-1表示不使用米卡 $this->param['riceCardId'] = key($data)??0;//若果没有选择米卡,默认使用第一张 } return $data; } /** * 计算订单可用积分抵扣 * @return bool * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ private function setOrderPoints() { // 设置默认的商品积分抵扣信息 $this->setDefaultGoodsPoints(); // 积分设置 $setting = SettingModel::getItem('points'); // 条件:后台开启下单使用积分抵扣 if (!$setting['is_shopping_discount'] || !$this->checkoutRule['isUsePoints']) { return false; } // 条件:订单金额满足[?]元 if (helper::bccomp($setting['discount']['full_order_price'], $this->orderData['orderTotalPrice']) === 1) { return false; } // 计算订单商品最多可抵扣的积分数量 $this->setOrderGoodsMaxPointsNum(); // 订单最多可抵扣的积分总数量 $maxPointsNumCount = helper::getArrayColumnSum($this->goodsList, 'max_points_num'); // 实际可抵扣的积分数量 $actualPointsNum = min($maxPointsNumCount, $this->user['points']); if ($actualPointsNum < 1) { return false; } // 计算订单商品实际抵扣的积分数量和金额 $GoodsDeduct = new PointsDeductService($this->goodsList); $GoodsDeduct->setGoodsPoints($maxPointsNumCount, $actualPointsNum); // 积分抵扣总金额 $orderPointsMoney = helper::getArrayColumnSum($this->goodsList, 'points_money'); $this->orderData['pointsMoney'] = helper::number2($orderPointsMoney); // 积分抵扣总数量 $this->orderData['pointsNum'] = $actualPointsNum; // 允许积分抵扣 $this->orderData['isAllowPoints'] = true; return true; } /** * 计算订单商品最多可抵扣的积分数量 * @return bool * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ private function setOrderGoodsMaxPointsNum() { // 积分设置 $setting = SettingModel::getItem('points'); foreach ($this->goodsList as &$goods) { // 商品不允许积分抵扣 if (!$goods['is_points_discount']) continue; // 积分抵扣比例 $deductionRatio = helper::bcdiv($setting['discount']['max_money_ratio'], 100); // 最多可抵扣的金额 $totalPayPrice = helper::bcsub($goods['total_price'], $goods['coupon_money']); $maxPointsMoney = helper::bcmul($totalPayPrice, $deductionRatio); // 最多可抵扣的积分数量 $goods['max_points_num'] = helper::bcdiv($maxPointsMoney, $setting['discount']['discount_ratio'], 0); } return true; } /** * 设置默认的商品积分抵扣信息 * @return bool */ private function setDefaultGoodsPoints() { foreach ($this->goodsList as &$goods) { // 最多可抵扣的积分数量 $goods['max_points_num'] = 0; // 实际抵扣的积分数量 $goods['pointsNum'] = 0; // 实际抵扣的金额 $goods['points_money'] = 0.00; } return true; } /** * 整理订单数据(结算台初始化) * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ private function getOrderData() { // 系统支持的配送方式 (后台设置) $deliveryType = SettingModel::getItem(SettingEnum::DELIVERY)['delivery_type']; return [ // 当前配送类型 'delivery' => $this->param['delivery'] > 0 ? $this->param['delivery'] : $deliveryType[0], // 默认地址 'address' => '', // 是否存在收货地址 'existAddress' => $this->user['address_id'] > 0, // 配送费用 'expressPrice' => 0.00, //是否使用了金米粒 'isUseGoldRice' => $this->param['isUseGoldRice'], //金米粒数量 'userGoldRiceNum' => $this->user['gold_rice']??0, // 当前用户收货城市是否存在配送规则中 'isIntraRegion' => true, // 是否允许使用积分抵扣 'isAllowPoints' => false, // 是否使用积分抵扣 'isUsePoints' => $this->param['isUsePoints'], // 积分抵扣金额 'pointsMoney' => 0.00, // 赠送的积分数量 'pointsBonus' => 0, // 支付方式 'payType' => $this->param['payType'], // 系统设置 'setting' => $this->getSetting(), // 推广监控ID "promotionMonitorId" => $this->param['promotionMonitorId'] ?? 0 ]; } /** * 获取订单页面中使用到的系统设置 * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ private function getSetting() { // 系统支持的配送方式 (后台设置) $deliveryType = SettingModel::getItem(SettingEnum::DELIVERY)['delivery_type']; // 积分设置 $pointsSetting = SettingModel::getItem(SettingEnum::POINTS); return [ 'deliveryType' => $deliveryType, // 支持的配送方式 'points_name' => $pointsSetting['points_name'], // 积分名称 'points_describe' => $pointsSetting['describe'], // 积分说明 ]; } /** * 当前用户可用的优惠券列表 * @param $goodsList 确认订单商品列表 * @return array|mixed * @throws \think\db\exception\DbException */ private function getUserCouponList() { // 是否开启优惠券折扣 if (!$this->checkoutRule['isCoupon']) { return []; } // 整理当前订单所有商品ID集 $orderGoodsIds = helper::getArrayColumn($this->goodsList, 'goods_id'); // 当前用户可用的优惠券列表(筛选了除外商品) // if($orderTotalPrice<=0){ // $couponList = []; // }else{ $couponList = UserCouponModel::getUserCouponList($this->user['user_id'], $this->goodsList, $orderGoodsIds); // } // // 判断当前优惠券是否满足订单使用条件 (优惠券适用范围) // $couponList = UserCouponModel::couponListApplyRange($couponList, $orderGoodsIds); if($this->param['couponId']==0){//-1不使用优惠券 $this->param['couponId'] = key($couponList)??0;//若果没有选择优惠券,默认使用第一张优惠券 } return $couponList; } /** * 验证订单商品的状态 * @return bool */ private function validateGoodsList() { $Checkout = CheckoutFactory::getFactory( $this->user, $this->goodsList, $this->orderData['delivery'], $this->shopInfo['shop_id'] ?? 0, $this->orderSource['source'] ); $status = $Checkout->validateGoodsList(); if(!$status){ $this->setError($Checkout->getError()); $this->setErrorStatus(422); } return $status; } /** * 设置订单的商品总金额(不含优惠折扣) */ private function setOrderTotalPrice() { // 订单商品的总金额(不含优惠券折扣,不含N件X折优惠券) $this->orderData['orderTotalPrice'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_price')); } /** * 订单商品的所有店铺集合 */ private function setOrderProviderIds() { // 订单商品的所有店铺集合 $this->orderData['orderProviderIds'] = implode(',',array_values(array_unique(helper::getArrayColumn($this->goodsList, 'provider_id')))); } /** * 设置订单的实际支付金额(含配送费) */ private function setOrderPayPrice() { // 订单金额(含优惠折扣) //(商品总价 - N件X折 - 优惠券 - 分销员)+ 运费 = 微信支付+米卡抵扣+米卡抵扣运费 //(total_price-coupon_money-distrbutor_total_money)+express_price = pay_price+rice_card_money+rice_card_express_money $this->orderData['orderPrice'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_pay_price')); // 订单实付款金额(订单金额 + 运费 - 现金卡运费抵扣金额) $this->orderData['orderPayPrice'] = helper::number2(helper::bcadd($this->orderData['orderPrice'], $this->orderData['expressPrice']-$this->orderData['riceCardExpressMoney'])); } /** * 计算订单积分赠送数量 * @return bool * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ private function setOrderPointsBonus() { // 初始化商品积分赠送数量 foreach ($this->goodsList as &$goods) { $goods['points_bonus'] = 0; } // 积分设置 $setting = SettingModel::getItem('points'); // 条件:后台开启开启购物送积分 if (!$setting['is_shopping_gift']) { return false; } // 设置商品积分赠送数量 foreach ($this->goodsList as &$goods) { // 积分赠送比例 $ratio = $setting['gift_ratio'] / 100; // 计算抵扣积分数量 $goods['points_bonus'] = !$goods['is_points_gift'] ? 0 : helper::bcmul($goods['total_pay_price'], $ratio, 0); } // 订单积分赠送数量 $this->orderData['pointsBonus'] = helper::getArrayColumnSum($this->goodsList, 'points_bonus'); return true; } /** * 设置金稻会员折扣价 * @return bool */ private function setOrderGoodsMemberMoney() { // 设置默认数据 helper::setDataAttribute($this->goodsList, [ // 标记金稻会员是否参与购物折扣 'is_user_member' => false, // 金稻会员购物抵扣的比例 'member_radio' => 0, // 金稻会员购物减去的折扣优惠总额差 'member_total_money' => 0.00, ], true); // 设置默认数据:订单信息 helper::setDataAttribute($this->orderData, [ 'memberTotalMoney' => 0, // 抵扣金额 'isUserMember' => false, // 是否有商品使用了会员折扣 ], false); //如果不是会员,或者会员已过期 if($this->user['member_expire_time']goodsList as &$goods) { //判断当前商品是否能使用会员折扣 $memberGoods = MemberGoods::where('goods_id',$goods['goods_id'])->where('status',0)->find(); if ($memberGoods && $memberGoods['discount']<100) { $memberRatio = helper::bcdiv(100-$memberGoods['discount'], 100);//换算成百分比 helper::setDataAttribute($goods, [ 'is_user_member' => true, 'member_radio' => $memberRatio, 'member_total_money' => helper::number2(helper::bcmul(($goods['total_price']-$goods['activity_discount_total_price']), $memberRatio)), // 'total_price' => $gradeTotalPrice, ], false); $this->orderData['isUserMember'] = true; } $member_total_money += $goods['member_total_money']; } $this->orderData['memberTotalMoney'] = helper::number2($member_total_money);//设置订单优惠合计 return true; } /** * 计算订单商品的实际付款金额 * @return bool */ private function setOrderGoodsPayPrice() { // 商品总价 - 优惠抵扣 foreach ($this->goodsList as &$goods) { //减去金稻会员抵扣的金额 $value = helper::bcsub($goods['total_price'], $goods['member_total_money']); // 减去N件X折抵扣金额 $value = helper::bcsub($value, $goods['activity_discount_total_price']); //减去分销员购物的优惠金额 $value = helper::bcsub($value, $goods['distributor_total_money']); // 减去优惠券抵扣金额 $value = helper::bcsub($value, $goods['coupon_money']); // 减去积分抵扣金额 if ($this->orderData['isAllowPoints'] && $this->orderData['isUsePoints']) { $value = helper::bcsub($value, $goods['points_money']); } //减去金米粒抵扣的金额 $value = helper::bcsub($value, $goods['gold_rice_money']); $goods['totalPayPrice'] = helper::number2($value); //减去现金米卡抵扣的金额 $value = helper::bcsub($value, $goods['rice_card_money']); $goods['total_pay_price'] = helper::number2($value); } return true; } /** * 设置订单商品会员折扣价 * @return bool */ private function setOrderGoodsGradeMoney() { // 设置默认数据 helper::setDataAttribute($this->goodsList, [ // 标记参与会员折扣 'is_user_grade' => false, // 会员等级抵扣的金额 'grade_ratio' => 0, // 会员折扣的商品单价 'grade_goods_price' => 0.00, // 会员折扣的总额差 'grade_total_money' => 0.00, ], true); // 是否开启会员等级折扣 if (!$this->checkoutRule['isUserGrade']) { return false; } // 会员等级状态 if (!( $this->user['grade_id'] > 0 && !empty($this->user['grade']) && !$this->user['grade']['is_delete'] && $this->user['grade']['status'] )) { return false; } // 计算抵扣金额 foreach ($this->goodsList as &$goods) { // 判断商品是否参与会员折扣 if (!$goods['is_enable_grade']) { continue; } // 商品单独设置了会员折扣 if ($goods['is_alone_grade'] && isset($goods['alone_grade_equity'][$this->user['grade_id']])) { // 折扣比例 $discountRatio = helper::bcdiv($goods['alone_grade_equity'][$this->user['grade_id']], 10); } else { // 折扣比例 $discountRatio = helper::bcdiv($this->user['grade']['equity']['discount'], 10); } if ($discountRatio > 0) { // 会员折扣后的商品总金额 $gradeTotalPrice = max(0.01, helper::bcmul($goods['total_price'], $discountRatio)); helper::setDataAttribute($goods, [ 'is_user_grade' => true, 'grade_ratio' => $discountRatio, 'grade_goods_price' => helper::number2(helper::bcmul($goods['goods_price'], $discountRatio), true), 'grade_total_money' => helper::number2(helper::bcsub($goods['total_price'], $gradeTotalPrice)), 'total_price' => $gradeTotalPrice, ], false); } } return true; } /** * 设置分销员购物折扣价 * @return bool */ private function setOrderGoodsDistributorMoney() { // 设置默认数据 helper::setDataAttribute($this->goodsList, [ // 标记参与顾客购物折扣 'is_user_distributor' => false, // 顾客购物抵扣的比例 'distributor_radio' => 0, // 顾客购物减去的折扣优惠价格 'distributor_goods_price' => 0.00, // 顾客购物减去的折扣优惠总额差 'distributor_total_money' => 0.00, ], true); // 设置默认数据:订单信息 helper::setDataAttribute($this->orderData, [ 'distributorTotalMoney' => 0, // 优惠券抵扣金额 'isUserDistributor' => false, // 是否有商品使用了推荐官专属折扣 ], false); //使用了优惠券并且优惠券没有勾选使用分销员优惠 if($this->orderData['couponId']>0 && stripos($this->orderData['couponOverlayDiscount'],'1') === false){ return true; } $distributor_total_money = 0; // 计算抵扣金额 foreach ($this->goodsList as &$goods) { $discountRatio = helper::bcdiv($goods['distributorRadio'], 100);//换算成百分比 if ($discountRatio > 0) { // 顾客购物折扣的优惠价格 // $gradeTotalPrice = max(0.01, helper::bcmul($goods['total_price'], (1-$discountRatio))); helper::setDataAttribute($goods, [ 'is_user_distributor' => true, 'distributor_radio' => $discountRatio, 'distributor_goods_price' => $goods['total_num']>0 ? helper::number2(helper::bcmul($goods['goods_price']-($goods['coupon_money']+$goods['activity_discount_total_price']+$goods['member_total_money'])/$goods['total_num'], $discountRatio), true):0, 'distributor_total_money' => helper::number2(helper::bcmul(($goods['total_price']-$goods['coupon_money']-$goods['activity_discount_total_price']-$goods['member_total_money']), $discountRatio)), // 'total_price' => $gradeTotalPrice, ], false); $this->orderData['isUserDistributor'] = true; } $distributor_total_money += $goods['distributor_total_money']; } $this->orderData['distributorTotalMoney'] = helper::number2($distributor_total_money);//设置订单优惠合计 return true; } /** * 设置订单优惠券抵扣信息 * @param array $couponList 当前用户可用的优惠券列表 * @param int $couponId 当前选择的优惠券id * @return bool * @throws BaseException */ private function setOrderCouponMoney(array $couponList, int $couponId) { // 设置默认数据:订单信息 helper::setDataAttribute($this->orderData, [ 'couponId' => $couponId, // 用户优惠券id 'couponMoney' => 0, // 优惠券抵扣金额 'couponName' => '', // 优惠券抵扣名称 'couponOverlayDiscount' => '', // 叠加字段 'couponList' => [], ], false); // 设置默认数据:订单商品列表 helper::setDataAttribute($this->goodsList, [ 'coupon_money' => 0, // 优惠券抵扣金额 'coupon_id' => 0, // 优惠券ID ], true); if($couponId<0){//如果米卡ID小于0表示不使用,但是也要返回可使用列表 $this->orderData['couponList'] = array_values($couponList); return true; } // 验证选择的优惠券ID是否合法 if (!$this->verifyOrderCouponId($couponId, $couponList)) { return false; } // 获取优惠券信息 $couponInfo = $this->getCouponInfo($couponId, $couponList); // 整理当前订单所有商品ID集 // $orderGoodsIds = helper::getArrayColumn($this->goodsList, 'goods_id'); // 获取当前参与商品分佣的ID集 // $diffGoodsIds = array_diff($orderGoodsIds,$couponInfo['except_goods_id']); $diffGoodsIds = $couponInfo['new_good_ids'];//在获取可用优惠券列表时就已经计算出哪些商品可以使用优惠券了 $goodsListTemp = []; foreach ($this->goodsList as $key=> $good){ $goodsListTemp[$key]['total_price'] = helper::bcsub($good['total_price'],$good['activity_discount_total_price']+$good['member_total_money']); if(!in_array($good['goods_id'],$diffGoodsIds)){ $goodsListTemp[$key]['total_price'] = 0; } } $CouponMoney = new GoodsDeductService; $completed = $CouponMoney->setGoodsCouponMoney($goodsListTemp, $couponInfo['reduced_price']); // 分配订单商品优惠券抵扣金额 foreach ($this->goodsList as $key => &$goods) { $goods['coupon_money'] = isset($completed[$key]['coupon_money']) ? $completed[$key]['coupon_money'] / 100 : 0; $goods['coupon_id'] = $couponId; if(!in_array($goods['goods_id'],$diffGoodsIds)){ $goods['coupon_id'] = 0; } } // 记录订单优惠券信息 $this->orderData['couponId'] = $couponId; $this->orderData['couponOverlayDiscount'] = $couponInfo['overlay_discount']; $this->orderData['couponMoney'] = helper::number2($CouponMoney->getActualReducedMoney() / 100); $this->orderData['couponName'] = $couponInfo['name']; $this->orderData['couponList'] = array_values($couponList); return true; } /** * 设置订单使用金米粒抵扣信息 * @return bool * @throws BaseException */ private function setOrderGolRiceAmount() { // 设置默认数据:订单信息 helper::setDataAttribute($this->orderData, [ 'goldRiceAmount' => 0, // 金米粒抵扣总数量 1金米粒=0.01元 'goldRiceMoney' => 0.00, // 金米粒抵扣总金额 ], false); // 设置默认数据:订单商品列表 helper::setDataAttribute($this->goodsList, [ 'gold_rice_amount' => 0, // 金米粒抵扣数量 'gold_rice_money' => 0, // 金米粒抵扣金额 ], true); if($this->orderData['isUseGoldRice']<1){//没有使用金米粒 return false; } $orderTotalPrice = $this->orderData['orderTotalPrice']-$this->orderData['distributorTotalMoney']-$this->orderData['couponMoney']-$this->orderData['activityDiscountTotalPrice']-$this->orderData['memberTotalMoney']; //实际支付金额-N件X折活动优惠-分销员优惠-优惠券优惠-金稻会员优惠 // 如果没有可用的现金米卡,直接返回 $DeductionLimit = DeductionLimitModel::where('id','>',0)->find(); $score = helper::bcmul($orderTotalPrice,$DeductionLimit['discount'],0); //不够起用数量 if($score<$DeductionLimit['score']){ $this->orderData['isUseGoldRice'] = -1; return false; } //用户可用金米粒数量不够起用数量 if($this->user['gold_rice']<$DeductionLimit['score']){ $this->orderData['isUseGoldRice'] = -1; return false; } if($score>$this->user['gold_rice']){ $score = $this->user['gold_rice']; } // 获取优惠券信息 $goodsListTemp = []; foreach ($this->goodsList as $key=> $good){ $goodsListTemp[$key]['total_price'] = helper::bcsub($good['total_price'],$good['distributor_total_money']+$good['coupon_money']+$good['activity_discount_total_price']+$good['member_total_money']); } $RiceMoney = new RiceDeductService; $gold_rice_money = helper::bcdiv($score,100); $completed = $RiceMoney->setGoodsCouponMoney($goodsListTemp, $gold_rice_money); // 分配订单商品抵扣的金米粒数量 foreach ($this->goodsList as $key => &$goods) { $goods['gold_rice_amount'] = isset($completed[$key]['rice_card_money']) ? $completed[$key]['rice_card_money'] : 0; $goods['gold_rice_money'] = helper::bcdiv($goods['gold_rice_amount'],100); } // 记录订单抵扣的金米粒数量 $this->orderData['goldRiceAmount'] = $score; $this->orderData['goldRiceMoney'] = $gold_rice_money; return true; } /** * 设置订单使用金米粒获取信息 * @return bool * @throws BaseException */ private function setOrderInputGolRiceAmount() { // 设置默认数据:订单信息 helper::setDataAttribute($this->orderData, [ 'goldRiceAmountInput' => 0, // 金米粒获取总数量 累加商品金额 ], false); // 设置默认数据:订单商品列表 helper::setDataAttribute($this->goodsList, [ 'gold_rice_amount_input' => 0, // 金米粒获取数量,1元可以获取1金米粒,只舍不入 ], true); //如果不是会员,或者会员已过期 if($this->user['member_expire_time']goodsList as $key => &$goods) { //获取商品需要实付的金额 $good_total_price = helper::bcsub($goods['total_price'],$goods['distributor_total_money']+$goods['coupon_money']+$goods['activity_discount_total_price']+$goods['member_total_money']+$goods['gold_rice_money']); $goods['gold_rice_amount_input'] = floor($good_total_price);//金米粒获取数量,1元可以获取1金米粒,只舍不入 $score += $goods['gold_rice_amount_input']; } // 记录订单获得的金米粒数量 $this->orderData['goldRiceAmountInput'] = $score; return true; } /** * 设置订单现金米卡抵扣信息 * @param int $riceCardId 可使用米卡列表 * @param int $riceCardId 当前选择的现金米卡id * @return bool * @throws BaseException */ private function setOrderRiceCardMoney($userRiceCardList,int $riceCardId) { // 设置默认数据:订单信息 helper::setDataAttribute($this->orderData, [ 'riceCardId' => $riceCardId, // 用户现金米卡id 'riceCardMoney' => 0, // 现金米卡抵扣总金额 'riceCardExpressMoney' => 0, // 现金米卡抵扣运费 'userRiceCardList' => [], // 米卡列表 'userRiceCard' => [], // 已选择的米卡 ], false); // 设置默认数据:订单商品列表 helper::setDataAttribute($this->goodsList, [ 'rice_card_id' => 0, // 用户现金米卡id 'rice_card_money' => 0, // 金米卡抵扣金额 ], true); if($riceCardId<0){//如果米卡ID小于0表示不使用,但是也要返回可使用列表 $this->orderData['userRiceCardList'] = array_values($userRiceCardList); return true; } // 验证选择的优惠券ID是否合法 if (!$this->verifyUserRiceCard($riceCardId, $userRiceCardList)) { return false; } // 获取优惠券信息 $riceCard = $this->getRiceCardInfo($riceCardId, $userRiceCardList); $goodsListTemp = []; foreach ($this->goodsList as $key=> $good){ $goodsListTemp[$key]['total_price'] = helper::bcsub($good['total_price'],$good['distributor_total_money']+$good['coupon_money']+$good['activity_discount_total_price']+$good['gold_rice_money']+$good['member_total_money']); } $RiceMoney = new RiceDeductService; $completed = $RiceMoney->setGoodsCouponMoney($goodsListTemp, $riceCard['balance']); // 分配订单商品优惠券抵扣金额 $rice_card_money = 0; foreach ($this->goodsList as $key => &$goods) { $goods['rice_card_money'] = isset($completed[$key]['rice_card_money']) ? $completed[$key]['rice_card_money'] / 100 : 0; $goods['rice_card_id'] = $riceCardId; $rice_card_money += $goods['rice_card_money']; } $orderTotalPrice = $this->orderData['orderTotalPrice']-$this->orderData['distributorTotalMoney']-$this->orderData['couponMoney']-$this->orderData['activityDiscountTotalPrice']-$this->orderData['goldRiceMoney']-$this->orderData['memberTotalMoney']; //实际支付金额-N件X折活动优惠-分销员优惠-优惠券优惠-金米粒抵扣金额 //有运费,并且现金米卡可用的金额大于商品总价 $rice_card_express_money = 0; if($riceCard['balance']>$orderTotalPrice && $this->orderData['expressPrice']>0){ $residueMoney = $riceCard['balance']-$orderTotalPrice; if($residueMoney-$this->orderData['expressPrice']>0){ $rice_card_express_money += $this->orderData['expressPrice']; }else{ $rice_card_express_money += $residueMoney; } } // 记录订单现金米卡信息 $this->orderData['userRiceCard'] = $userRiceCardList[$riceCardId]; $this->orderData['riceCardId'] = $riceCardId; $this->orderData['riceCardMoney'] = helper::bcmul($rice_card_money+$rice_card_express_money,1); $this->orderData['riceCardExpressMoney'] = helper::bcmul($rice_card_express_money,1); $this->orderData['userRiceCardList'] = array_values($userRiceCardList); return true; } /** * 验证用户选择的现金米卡 * @param $riceCard * @return bool * @throws BaseException */ private function verifyUserRiceCard($riceCardId,$userRiceCardList) { // 是否开启现金米卡抵扣 if (!$this->checkoutRule['isRiceCard']) { return false; } // 如果没有可用的现金米卡,直接返回 if ($riceCardId <= 0) { return false; } // 判断优惠券是否存在 $riceCard = $this->getRiceCardInfo($riceCardId, $userRiceCardList); // 如果没有现金米卡,直接返回 if (empty($riceCard)) { throwError('未找到米卡信息'); } // $UserRiceCardService = new UserRiceCardService($this->goodsList); // $isExceptGoods = $UserRiceCardService->isIncludeGoods($riceCard); // if ($isExceptGoods == false) { // $notExceptGoodsName = $UserRiceCardService->getExceptGoodsName(); // $this->setError("很抱歉,商品 [".limit_str((string)$notExceptGoodsName)."] 不可使用该米卡"); // $this->setErrorStatus(422); // }else{ // $isExceptGoods = $UserRiceCardService->isExceptGoods($riceCard); // if ($isExceptGoods == false) { // $notExceptGoodsName = $UserRiceCardService->getExceptGoodsName(); // $this->setError("很抱歉,商品 [".limit_str((string)$notExceptGoodsName)."] 不可使用该米卡"); // $this->setErrorStatus(422); // } // } return true; } /** * 验证用户选择的优惠券ID是否合法 * @param $couponId * @param $couponList * @return bool * @throws BaseException */ private function verifyOrderCouponId($couponId, $couponList) { // 是否开启优惠券折扣 if (!$this->checkoutRule['isCoupon']) { return false; } // 如果没有可用的优惠券,直接返回 if ($couponId <= 0 || empty($couponList)) { return false; } // 判断优惠券是否存在 $couponInfo = $this->getCouponInfo($couponId, $couponList); if (!$couponInfo) { // throwError('未找到优惠券信息'); $this->param['couponId'] = key($couponList)??0;//若果没有选择优惠券,默认使用第一张优惠券 $this->orderData['couponList'] = array_values($couponList); return false; } // 判断优惠券适用范围是否合法 // if (!$couponInfo['is_apply']) { // throwError($couponInfo['not_apply_info']); // } return true; } /** * 查找指定的优惠券信息 * @param int $couponId 优惠券ID * @param array $couponList 优惠券列表 * @return false|mixed */ private function getCouponInfo(int $couponId, array $couponList) { return helper::getArrayItemByColumn($couponList, 'user_coupon_id', $couponId); } /** * 查找指定的优惠券信息 * @param int $couponId 优惠券ID * @param array $couponList 优惠券列表 * @return false|mixed */ private function getRiceCardInfo(int $riceCardId, array $userRiceCardList) { return helper::getArrayItemByColumn($userRiceCardList, 'id', $riceCardId); } /** * 订单配送-快递配送 * @return bool * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ private function setOrderExpress() { // 设置默认数据:配送费用 helper::setDataAttribute($this->goodsList, [ 'expressPrice' => 0, ], true); // 当前用户收货城市id if($this->param['addressId']){ //有传参 $addredd = UserAddress::get(['user_id' => $this->user['user_id'], 'address_id' => $this->param['addressId']]); $cityId = $addredd ? (int)$addredd['city_id'] : 0; $this->orderData['address'] = $addredd; }else{ //没有传参读默认地址 $cityId = $this->user['address_default'] ? (int)$this->user['address_default']['city_id'] : 0; $this->orderData['address'] = $this->user['address_default']; } if ($this->param['delivery'] == DeliveryTypeEnum::EXPRESS) { // 普通快递 // 初始化配送服务类 $ExpressService = new ExpressService($cityId, $this->goodsList); // 验证商品是否在限购配送范围 $isDeliveryLimit = $ExpressService->isDeliveryLimit(); if($cityId > 0){ if ($isDeliveryLimit == false) { $this->setError("很抱歉,您的收货地址在限购地区的配送范围内"); $this->setErrorStatus(423); $this->orderData['isIntraRegion'] = $isDeliveryLimit; }else{ // 验证商品是否在配送范围 $isIntraRegion = $ExpressService->isIntraRegion(); if ($isIntraRegion == false) { $notInRuleGoodsName = $ExpressService->getNotInRuleGoodsName(); $this->setError("很抱歉,您的收货地址不在商品 [".limit_str((string)$notInRuleGoodsName)."] 的配送范围内"); $this->setErrorStatus(423); } $this->orderData['isIntraRegion'] = $isIntraRegion; } } // 订单总运费金额 $this->orderData['expressPrice'] = $ExpressService->getDeliveryFee(); } else { // 门店自提 $this->orderData['expressPrice'] = "0.00"; } return true; } /** * 创建新订单 * @param array $order 订单信息 * @return bool */ public function createOrder(array $order) { // 表单验证 if (!$this->validateOrderForm($order)) { return false; } // 创建新的订单 $status = $this->model->transaction(function () use ($order) { // 创建订单事件 return $this->createOrderEvent($order); }); if ($status && $order['payType'] == OrderPayTypeEnum::EXCHANGE) { return $this->model->onPaymentByAccumulatePoints($this->model['order_no']); } return $status; } /** * 创建订单事件 * @param $order * @return bool * @throws BaseException * @throws \Exception */ private function createOrderEvent($order) { // 门店自提 if ($order['delivery'] == DeliveryTypeEnum::SHOPS_DELIVERY) { $order['hx_code'] = $this->model->hxCode(); $order['pickup_deadline'] = time() + OrderModel::getPickupDeadline() * 60; // 提货截止时间:提交订单2天内 $order['shop_id'] = $order['shopInfo']['shop_id']; // 订单自提门店id } // 新增订单记录 $status = $this->add($order, $this->param['remark']); if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { // 记录收货地址 $this->saveOrderAddress($order['address']); } // 保存订单商品信息 $this->saveOrderGoods($order); //保存满件送商品信息 $this->saveOrderGoodsMj($order); // 保存订单套餐商品信息 $this->saveOrderGoodsTaocan($order); // 更新商品库存 (针对下单减库存的商品) $this->updateGoodsStockNum($order); // 更新多个活动的活动库存 $this->updateActivityStock($order); // 设置优惠券使用状态 $order['couponId'] > 0 && UserCouponModel::setIsUse((int)$order['couponId']); //设置福利状态zq if ($order['couponId'] > 0)UserCouponModel::setWelfareStatus((int)$order['couponId'],1); // 获取订单详情 // $detail = OrderModel::getUserOrderDetail((int)$this->model['order_id']); return $status; } /** * 构建支付请求的参数 * @return array * @throws BaseException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function onOrderPayment() { return PaymentService::orderPayment($this->model, $this->param['payType']); } /** * 表单验证 (订单提交) * @param array $order 订单信息 * @return bool */ private function validateOrderForm(array $order) { if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { if (empty($order['address'])) { $this->error = '您还没有选择配送地址'; return false; } } // 余额支付时判断用户余额是否足够 if ($order['payType'] == OrderPayTypeEnum::BALANCE) { if ($this->user['balance'] < $order['orderPayPrice']) { $this->error = '您的余额不足,无法使用余额支付'; return false; } } return true; } /** * 当前订单是否存在和使用积分抵扣 * @param $order * @return bool */ private function isExistPointsDeduction($order) { return $order['isAllowPoints'] && $order['isUsePoints']; } /** * 新增订单记录 * @param $order * @param string $remark * @return false|int */ private function add($order, $remark = '') { // 当前订单是否存在和使用积分抵扣 $isExistPointsDeduction = $this->isExistPointsDeduction($order); // 订单数据 $data = [ 'user_id' => $this->user['user_id'], 'order_no' => $this->model->orderNo(), 'total_price' => $order['orderTotalPrice'], 'order_price' => $order['orderPrice'], 'coupon_id' => $order['couponId']>0?$order['couponId']:0, 'coupon_money' => $order['couponMoney'], 'points_money' => $isExistPointsDeduction ? $order['pointsMoney'] : 0.00, 'points_num' => $isExistPointsDeduction ? $order['pointsNum'] : 0, 'pay_price' => $order['orderPayPrice'], 'delivery_type' => $order['delivery'], 'pay_type' => $order['orderPayPrice'] > 0 ? $order['payType'] : OrderPayTypeEnum::MICAH_EXCHANGE, 'buyer_remark' => trim($remark), 'order_source' => $this->orderSource['source'], 'order_source_id' => $this->orderSource['source_id'], 'points_bonus' => $order['pointsBonus'], 'order_status' => OrderStatusEnum::NORMAL, 'store_id' => $this->storeId, 'provider_ids' => $order['orderProviderIds']??0, 'distributor_total_money' => $order['distributorTotalMoney']??0, 'member_total_money' => $order['memberTotalMoney']??0, 'gold_rice_amount' => $order['goldRiceAmount']??0, 'gold_rice_money' => $order['goldRiceMoney']??0, 'gold_rice_amount_input' => $order['goldRiceAmountInput']??0, 'rice_card_id' => $order['riceCardId']>0?$order['riceCardId']:0, 'rice_card_money' => $order['riceCardMoney']??0, 'rice_card_express_money' => $order['riceCardExpressMoney']??0, 'hx_code' => $order['hx_code'] ?? '', 'pickup_deadline' => $order['pickup_deadline'] ?? 0, 'shop_id' => $order['shop_id'] ?? 0, 'invoice_deadline' => $order['invoice_deadline'] ?? 0, 'is_full_send' => $order['is_full_send'] ?? 0, 'full_send_activity_id' => $order['full_send_activity_id'] ?? 0, 'is_qc_send_send' => $order['is_qc_send_send'] ?? 0,//是否参与全场满件送活动 'qc_send_activity_id' => $order['qc_send_activity_id'] ?? 0,//全场满件送活动ID 'activity_discount_total_price' => $order['activityDiscountTotalPrice'] ?? 0, 'staff_user_id' => $order['goodsList'][0]['staffUserId'] ?? 0, 'staff_shop_id' => $order['goodsList'][0]['shopId'] ?? 0, 'promotion_monitor_id' => $order['promotionMonitorId'] ?? 0, ]; //米卡兑换直接成功 if ($order['orderPayPrice']<=0 && $order['payType']==OrderPayTypeEnum::EXCHANGE){ $data['pay_status'] = PayStatusEnum::PENDING; }else{ //米卡兑换直接成功 if($order['orderPayPrice']<=0 || $order['payType']==OrderPayTypeEnum::MICAH_EXCHANGE){ $data['pay_status'] = PayStatusEnum::SUCCESS; $data['pay_time'] = time(); $data['invoice_deadline'] = time() + OrderModel::getInvoiceDeadline() * 60; // 申请开票截止时间:订单付款后的40天内可以申请开票 } } if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { $data['express_price'] = $order['expressPrice']; } // 保存订单记录 return $this->model->save($data); } /** * 保存订单商品信息 * @param $order * @return int */ private function saveOrderGoods($order) { // 当前订单是否存在和使用积分抵扣 $isExistPointsDeduction = $this->isExistPointsDeduction($order); // 订单商品列表 $goodsList = []; foreach ($order['goodsList'] as $key=> $goods) { // dd($goods['total_pay_price']); /* @var GoodsModel $goods */ $item = [ 'user_id' => $this->user['user_id'], 'store_id' => $this->storeId, 'goods_id' => $goods['goods_id'], 'goods_name' => $goods['goods_name'], 'goods_no' => $goods['goods_no'] ?: '', 'image_id' => (int)current($goods['goods_images'])['file_id'], 'deduct_stock_type' => $goods['deduct_stock_type'], 'spec_type' => $goods['spec_type'], 'goods_sku_id' => $goods['skuInfo']['goods_sku_id'], 'goods_props' => $goods['skuInfo']['goods_props'] ?: '', 'content' => $goods['content'] ?? '', 'goods_sku_no' => $goods['skuInfo']['goods_sku_no'] ?: '', 'goods_price' => $goods['skuInfo']['goods_price'], 'specs' => $goods['skuInfo']['specs'], 'supplier' => $goods['supplier'], 'line_price' => $goods['skuInfo']['line_price'], 'goods_weight' => $goods['skuInfo']['goods_weight'], 'is_user_grade' => (int)$goods['is_user_grade'], 'grade_ratio' => $goods['grade_ratio']??0, 'grade_goods_price' => $goods['grade_goods_price']??0, 'grade_total_money' => $goods['grade_total_money']??0, 'coupon_id' => $goods['coupon_id']??0, 'coupon_money' => $goods['coupon_money']??0, 'points_money' => $isExistPointsDeduction ? $goods['points_money'] : 0.00, 'points_num' => $isExistPointsDeduction ? $goods['points_num'] : 0, 'points_bonus' => $goods['points_bonus']??0, 'total_num' => $goods['total_num'], 'total_price' => $goods['total_price'], 'total_pay_price' => $goods['total_pay_price']??0, 'provider_id' => $goods['provider_id'], 'brand' => $goods['brand'], 'province_id' => $goods['province_id'], 'city_id' => $goods['city_id'], 'storage' => $goods['storage'], 'unit' => $goods['unit'], 'clearing_price' => $goods['skuInfo']['clearing_price']??'0.00', 'platform_rate' => $goods['skuInfo']['platform_rate']??'0.00', 'staff_user_id' => $goods['staffUserId'], 'shop_id' => $goods['shopId'], 'distributor_radio' => $goods['distributor_radio']??0, 'distributor_goods_price' => $goods['distributor_goods_price']??0, 'distributor_total_money' => $goods['distributor_total_money']??0, 'member_radio' => $goods['member_radio']??0, 'member_total_money' => $goods['member_total_money']??0, 'gold_rice_amount' => $goods['gold_rice_amount']??0, 'gold_rice_money' => $goods['gold_rice_money']??0, 'gold_rice_amount_input' => $goods['gold_rice_amount_input']??0, 'rice_card_id' => $goods['rice_card_id']??0, 'rice_card_money' => $goods['rice_card_money']??0, 'goods_type' => $goods['goods_type']??10, // 'has_refund_full' => $goods['goods_type']==20? 1 : 0,//赠品直接默认为全额退款状态 'is_full_send' => $goods['is_full_send'] ?? 0, 'full_send_activity_id' => $goods['full_send_activity_id'] ?? 0, 'full_send_count' => $goods['full_send_count'] ?? 0,//满就送活动实际参与活动数量 'is_qc_send_send' => $goods['is_qc_send_send'] ?? 0,//是否参与全场满件送活动 'qc_send_activity_id' => $goods['qc_send_activity_id'] ?? 0,//全场满件送活动ID 'qc_send_count' => $goods['qc_send_count'] ?? 0,//全场满件送活动赠品的数量 'qc_send_use_count' => $goods['qc_send_use_count'] ?? 0,//全场满件送活动实际参与活动数量 'is_activity_discount' => $goods['is_activity_discount'] ?? 0,//是否参与了N件X折活动 0否 1是 'activity_discount_id' => $goods['activity_discount_id'] ?? 0,//N件X折活动ID 'activity_discount_total_price' => $goods['activity_discount_total_price'] ?? 0,//N件X折活动折扣金额 'activity_discount_desc' => $goods['activity_discount_desc'] ?? 0,//N件X折活动描述 'activity_discount_count' => $goods['activity_discount_count'] ?? 0,//N件X折活动实际参与活动数量 'is_mj_send' => $goods['is_mj_send'] ?? 0, 'mj_send_activity_id' => $goods['mj_send_activity_id'] ?? 0, 'mj_send_num' => $goods['mj_send_num'] ?? 0, 'mj_send_count' => $goods['mj_send_count'] ?? 0,//满件送活动赠品的数量 'mj_send_use_count' => $goods['mj_send_use_count'] ?? 0,//满件送活动实际参与活动数量 // 'promotion_monitor_id' => $goods['promotion_monitor_id'] ?? 0, // 推广监控ID ]; // 记录订单商品来源id $item['goods_source_id'] = isset($goods['goods_source_id']) ? $goods['goods_source_id'] : 0; $goodsList[] = $item; } return $this->model->goods()->saveAll($goodsList) !== false; } /** * 保存订单套餐商品信息 * @param $order * @return int */ private function saveOrderGoodsMj($order) { // 订单商品列表 $goodsList = []; foreach ($order['goodsList'] as $key=> $goods) { //如果存在满减商品也保存起来 foreach ($goods['mj_send_goods_list'] as $mj_send_goods){ $mj_item = [ 'user_id' => $this->user['user_id'], 'store_id' => $this->storeId, 'goods_id' => $mj_send_goods['goods_id'], 'goods_name' => $mj_send_goods['goods_name'], 'goods_no' => $mj_send_goods['goods_no'] ?: '', 'image_id' => (int)current($mj_send_goods['goods_images'])['file_id'], 'deduct_stock_type' => $mj_send_goods['deduct_stock_type'], 'spec_type' => $mj_send_goods['spec_type'], 'goods_sku_id' => $mj_send_goods['skuInfo']['goods_sku_id'], 'goods_props' => $mj_send_goods['skuInfo']['goods_props'] ?: '', 'content' => $mj_send_goods['content'] ?? '', 'goods_sku_no' => $mj_send_goods['skuInfo']['goods_sku_no'] ?: '', 'goods_price' => $mj_send_goods['skuInfo']['goods_price'], 'line_price' => $mj_send_goods['skuInfo']['line_price'], 'goods_weight' => $mj_send_goods['skuInfo']['goods_weight'], 'is_user_grade' => (int)$mj_send_goods['is_user_grade'], 'grade_ratio' => $mj_send_goods['grade_ratio']??0, 'grade_goods_price' => $mj_send_goods['grade_goods_price']??0, 'grade_total_money' => $mj_send_goods['grade_total_money']??0, 'coupon_id' => $mj_send_goods['coupon_id']??0, 'coupon_money' => $mj_send_goods['coupon_money']??0, 'points_bonus' => $mj_send_goods['points_bonus']??0, 'total_num' => $mj_send_goods['total_num'], 'total_price' => $mj_send_goods['total_price'], 'total_pay_price' => $mj_send_goods['total_pay_price']??0, 'provider_id' => $mj_send_goods['provider_id'], 'brand' => $mj_send_goods['brand'], 'province_id' => $mj_send_goods['province_id'], 'city_id' => $mj_send_goods['city_id'], 'storage' => $mj_send_goods['storage'], 'unit' => $mj_send_goods['unit'], 'clearing_price' => $mj_send_goods['skuInfo']['clearing_price']??'0.00', 'platform_rate' => $mj_send_goods['skuInfo']['platform_rate']??'0.00', 'staff_user_id' => $mj_send_goods['staffUserId'], 'shop_id' => $mj_send_goods['shopId'], 'rice_card_id' => $mj_send_goods['rice_card_id']??0, 'rice_card_money' => $mj_send_goods['rice_card_money']??0, 'goods_type' => $mj_send_goods['goods_type']??20, //默认赠品 'is_mj_send' => $goods['is_mj_send'] ?? 0, 'mj_send_activity_id' => $goods['mj_send_activity_id'] ?? 0, 'master_order_goods_id' => $this->model->goods[$key]['order_goods_id'], ]; // 记录订单商品来源id $mj_item['goods_source_id'] = isset($goods['goods_source_id']) ? $goods['goods_source_id'] : 0; $goodsList[] = $mj_item; } } return $this->model->goods()->saveAll($goodsList) !== false; } /** * 保存订单套餐商品信息 * @param $order * @return int */ private function saveOrderGoodsTaocan($order) { // 当前订单是否存在和使用积分抵扣 $isExistPointsDeduction = $this->isExistPointsDeduction($order); // 订单商品列表 $goodsList = []; foreach ($order['goodsList'] as $key=> $goods) { if($goods['goods_type']!=30){//是套餐商品 continue; } $relGoodList = GoodsPackageModel::with(['relGood'=>['images','skuList']])->where('goods_id',$goods['goods_id'])->select(); // dd( $relGoodList->toArray()); foreach ($relGoodList as $relGood){ $relGood['skuList'] = []; foreach ($relGood['relGood']['skuList'] as $sku){ if($sku['goods_sku_id']==$relGood['rel_goods_sku_id']){ $relGood['skuList'] = $sku; } } $item = [ 'user_id' => $this->user['user_id'], 'order_id' => $this->model['order_id'], 'order_goods_id' => $this->model->goods[$key]['order_goods_id'], 'store_id' => $this->storeId, 'goods_id' => $relGood['relGood']['goods_id'], 'goods_name' => $relGood['relGood']['goods_name'], 'goods_no' => $relGood['relGood']['goods_no'] ?: '', 'image_id' => (int)$relGood['relGood']['images'][0]['image_id']??0, 'deduct_stock_type' => $relGood['relGood']['deduct_stock_type'], 'spec_type' => $relGood['relGood']['spec_type'], 'goods_sku_id' => $relGood['skuList']['goods_sku_id']??0, 'goods_props' => $relGood['skuList']['goods_props'] ?? '', 'content' => $relGood['relGood']['content'] ?? '', 'goods_sku_no' => $relGood['skuList']['goods_sku_no'] ?? '', 'goods_price' => $relGood['skuList']['goods_price']??'0.00', 'line_price' => $relGood['skuList']['line_price']??'0.00', 'goods_weight' => $relGood['skuList']['goods_weight']??'0.00', 'is_user_grade' => (int)$relGood['relGood']['is_user_grade'], 'grade_ratio' => $relGood['relGood']['grade_ratio']??0, 'grade_goods_price' => $relGood['relGood']['grade_goods_price']??0, 'grade_total_money' => $relGood['relGood']['grade_total_money']??0, 'coupon_id' => $relGood['relGood']['coupon_id']??0, 'coupon_money' => $relGood['relGood']['coupon_money']??0, 'points_money' => $isExistPointsDeduction ? $relGood['relGood']['points_money'] : 0.00, 'points_num' => $isExistPointsDeduction ? $relGood['relGood']['points_num'] : 0, 'points_bonus' => $relGood['relGood']['points_bonus']??0, 'total_num' => 1, 'total_price' => $relGood['relGood']['total_price']??0, 'total_pay_price' => $relGood['relGood']['total_pay_price']??0, 'provider_id' => $relGood['relGood']['provider_id'], 'brand' => $relGood['relGood']['brand'], 'province_id' => $goods['province_id'], 'city_id' => $relGood['relGood']['city_id'], 'storage' => $relGood['relGood']['storage'], 'unit' => $relGood['relGood']['unit'], 'clearing_price' => $relGood['skuList']['clearing_price']??'0.00', 'platform_rate' => $relGood['skuList']['platform_rate']??'0.00', 'goods_type' => 30, ]; // 记录订单商品来源id $item['goods_source_id'] = isset($relGood['goods_source_id']) ? $relGood['goods_source_id'] : 0; $goodsList[] = $item; } } return (new OrderGoodsTaocanModel())->saveAll($goodsList) !== false; } /** * 更新商品库存 (针对下单减库存的商品) * 普通快递、门店自提 分开扣库存 * @param $order * @return mixed */ private function updateGoodsStockNum($order) { return StockFactory::getFactory($this->model['order_source'])->updateGoodsStock($order); } /** * 更新商品库存 (针对下单减库存的商品) * 普通快递、门店自提 分开扣库存 * @param $order * @return mixed */ private function updateActivityStock($order) { return StockFactory::getFactory($this->model['order_source'])->updateActivityStock($order); } /** * 记录收货地址 * @param $address * @return false|\think\Model */ private function saveOrderAddress($address) { return $this->model->address()->save([ 'user_id' => $this->user['user_id'], 'store_id' => $this->storeId, 'name' => $address['name'], 'phone' => $address['phone'], 'province_id' => $address['province_id'], 'city_id' => $address['city_id'], 'region_id' => $address['region_id'], 'detail' => $address['detail'], ]); } /** * 设置错误信息 * @param $error */ protected function setError($error) { empty($this->error) && $this->error = $error; } /** * 获取错误信息 * @return mixed */ public function getError() { return $this->error ?: ''; } /** * 设置错误状态 * @param $errorStatus */ protected function setErrorStatus($errorStatus) { empty($this->errorStatus) && $this->errorStatus = $errorStatus; } /** * 获取错误信息 * @return mixed */ public function getErrorStatus() { return $this->errorStatus ?: 0; } /** * 是否存在错误 * @return bool */ public function hasError() { return !empty($this->error); } }