150], ['give_time', 'default', 'value' => '0'], [['pic_url', 'desc', 'qrcode_url'], 'string', 'max' => 255], ['discount', 'default', 'value' => '0'], ['discount', 'check_discount', 'when' => function ($model) { return $model->type == 1; }], ['sub_price', 'compare', 'compareAttribute' => 'min_price', 'operator' => '<=', 'when' => function ($model) { return $model->type == 2; }, 'message' => '优惠金额不能大于满减金额'], ['expire_day', 'required', 'when' => function ($model) { return $model->type == 1 || $model->type == 3; }], ['effect_days', 'required', 'when' => function ($model) { return $model->type == 3; }], ['begin_at', 'required', 'when' => function ($model) { return $model->type == 2; }], ['end_at', 'required', 'when' => function ($model) { return $model->type == 2; }], ['remind_days', 'required', 'when' => function ($model) { return $model->is_remind == 1; }], ['receive_count', 'required', 'when' => function ($model) { return $model->is_receive_limit == 1; }], ['begin_at', 'compare', 'compareAttribute' => 'end_at', 'operator' => '<', 'when' => function ($model) { return $model->expire_type == 2; }, 'message' => '优惠券开始时间必须小于结束时间'], ['begin_at', function ($attribute, $params) { if ($this->$attribute <= time() && $this->expire_type == 2) { $this->addError($attribute, '优惠券开始时间不能小于现在时间'); } }], ]; } /** * {@inheritdoc} */ public function attributeLabels() { return [ 'id' => 'ID', 'mall_id' => '商城ID', 'store_id' => '门店ID', 'name' => '优惠券名称', 'type' => '优惠券类型', 'discount' => '优惠折扣', 'discount_limit' => '折扣金额上限', 'pic_url' => 'Pic Url', 'desc' => 'Desc', 'min_price' => '满减券最低消费金额', 'sub_price' => '优惠金额', 'total_count' => '优惠券可发放数量', 'sort' => '优惠券排序', 'expire_type' => '优惠券过期类型', 'expire_day' => '优惠券有效天数', 'effect_days' => '优惠券领取到生效之间间隔的天数', 'begin_at' => '优惠券有效期开始时间', 'end_at' => '优惠券有效期结束时间', 'appoint_type' => '优惠券可用场景', 'rule' => '使用规则(说明)', 'is_remind' => '是否发送过期提醒', 'remind_days' => '提前提醒天数', 'is_receive_limit' => '是否限制领取数量', 'receive_count' => '每个会员可以领取的数量', 'is_member' => '是否限制会员等级', 'is_original_use' => '是否必须原价购买可用', 'is_public_receive' => '是否公开领取', 'is_giving' => '是否允许转赠', 'giving_expire' => '赠送有效期,单位天,0不限制', 'status' => 'Status', 'coupon_status' => '优惠券状态', 'give_time'=>'可转赠次数', 'is_giving_reward' => '是否开启转赠奖励', 'is_consume_reward' => '是否开启使用奖励', 'qrcode_url' => '优惠券二维码', 'poster_url' => '优惠券海报', 'created_at' => 'Created At', 'updated_at' => 'Updated At', 'deleted_at' => 'Deleted At', ]; } public function scenarios() { return [ 'create' => ['name', 'type', 'discount', 'discount_limit', 'min_price', 'sub_price', 'total_count', 'sort', 'expire_type', 'expire_day', 'begin_at', 'end_at', 'appoint_type', 'rule', 'is_remind', 'remind_days', 'effect_days', 'is_receive_limit', 'receive_count', 'is_member', 'is_original_use', 'is_public_receive', 'is_giving', 'status', 'is_giving_reward', 'is_consume_reward', 'qrcode_url'], 'update' => ['name', 'type', 'discount', 'discount_limit', 'min_price', 'sub_price', 'total_count', 'sort', 'expire_type', 'expire_day', 'appoint_type', 'rule', 'is_remind', 'remind_days', 'effect_days', 'is_receive_limit', 'receive_count', 'is_member', 'is_original_use', 'is_public_receive', 'is_giving', 'status', 'is_giving_reward', 'is_consume_reward', 'qrcode_url'], 'default' => [], ]; } public function check_discount($attribute, $params) { if ($this->$attribute < 0 || $this->$attribute > 9.9) { $this->addError($attribute, '折扣率必须在 1~9.9 之间'); } } /** * 商品关系 * @return \yii\db\ActiveQuery */ public function getGoodsRelate() { return $this->hasMany(AddonsCouponGoodsRelate::class, ['coupon_id' => 'id']); } /** * 商品关系 * @return \yii\db\ActiveQuery */ public function getStoreGoodsRelate() { return $this ->hasMany(CouponStoreGoodsRelate::class, ['coupon_id' => 'id']) ->where(['status' => StatusEnum::ENABLED]); } /** * 分类关系 * @return \yii\db\ActiveQuery */ public function getCateRelate() { return $this->hasMany(AddonsCouponCatRelate::class, ['coupon_id' => 'id']); } /** * 等级关系 * @return \yii\db\ActiveQuery */ public function getMemberRelate() { return $this->hasMany(AddonsCouponMemberRelate::class, ['coupon_id' => 'id']); } /** * 会员关系 * @return \yii\db\ActiveQuery */ public function getUserRelate() { return $this->hasMany(AddonsCouponUserRelate::class, ['coupon_id' => 'id']); } /** * 会员关系 * @return \yii\db\ActiveQuery */ public function getUserRelateOne() { return $this->hasOne(AddonsCouponUserRelate::class, ['coupon_id' => 'id']); } /** * 商品 * @return \yii\db\ActiveQuery */ public function getGoods() { return $this->hasMany(Goods::class, ['id' => 'goods_id']) ->where(['mch_id' => 0]) ->via('goodsRelate'); } /** * 商品 * @return \yii\db\ActiveQuery */ public function getStoreGoods() { return $this->hasMany(StoreGoods::class, ['id' => 'goods_id']) ->where(['status' => StatusEnum::ENABLED, 'is_on_sale' => StatusEnum::ENABLED]) ->via('storeGoodsRelate'); } /** * 分类 * @return \yii\db\ActiveQuery */ public function getCat() { return $this->hasMany(GoodsCate::class, ['id' => 'cate_id']) ->where(['mch_id' => 0]) ->via('cateRelate'); } public function getStore() { $is_install = MallAddons::isInstall($this->mall_id, AddonsEnum::ADDONS_NAME_STORE); if (empty($is_install)) { return []; } return $this->hasMany(Store::class, ['id' => 'store_id']) ->select('id,store_name,logo_img,shop_owner,shop_mobile') ->where(['status' => StatusEnum::ENABLED, 'check_status' => 1]); } public static function deleteCoupon(int $coupon_id, int $mall_id) { $transaction = \Yii::$app->db->beginTransaction(); try { $model = AddonsCoupon::findOne(['mall_id' => $mall_id, 'id' => $coupon_id, 'status' => StatusEnum::ENABLED]); if (empty($model)) { throw new \Exception('优惠券不存在或已删除'); } $model->status = StatusEnum::DELETE; $model->coupon_status = AddonsCouponEnum::STATUS_FAILURE; $model->updated_at = time(); $res_coupon = $model->save(); $res_user_coupon = AddonsCouponUserRelate::updateAll(['status' => StatusEnum::DISABLED, 'coupon_status' => AddonsCouponEnum::STATUS_FAILURE], ['mall_id' => $mall_id, 'id' => $coupon_id, 'status' => StatusEnum::ENABLED]); if ($res_coupon === false || $res_user_coupon === false) { throw new \Exception('删除失败: res_coupon => ' . $model->getErrorMessage() . ', res_user_coupon => ' . AddonsCouponUserRelate::getStaticError()); } $transaction->commit(); return true; } catch (\Exception $e) { $transaction->rollBack(); self::$static_error = $e->getMessage(); return false; } } /** * 保存数据 * @param array $params * @return AddonsCoupon|bool * @throws \yii\db\Exception */ public static function setData(array $params, string $scenarios = 'create') { $transaction = \Yii::$app->db->beginTransaction(); try { $coupon_info = $params['coupon_info'] ?? []; unset($coupon_info['effect_expire_days']); $member_level_limits = $params['member_level_limits'] ?? []; $goods_id_list = $params['goods_id_list'] ?? []; $store_goods_id_list = $params['store_goods_id_list'] ?? []; $giving_rewards = $params['giving_reward'] ?? []; $consume_rewards = $params['consume_reward'] ?? []; $category_ids = $params['category_ids'] ?? []; $time = time(); if (empty($coupon_info)) throw new Exception('优惠券数据为空'); $model = new self(['scenario' => $scenarios]); if (!$model->load($coupon_info, '') || false === $model->validate()) { $errors = $model->errors; $error_str = ''; foreach ($errors as $error) { $error_str .= implode(',', $error) . ','; } $error_str = trim($error_str, ','); throw new \Exception($error_str); } // 检查优惠券使用场景 self::checkUseScene($params); if (isset($coupon_info['type']) && $coupon_info['type'] == AddonsCouponEnum::EXCHANGE) { $coupon_info['min_price'] = $coupon_info['sub_price'] = 0; } unset($model); if (!empty($coupon_info['id'])) { // 更新 $model = self::findOne(['id' => $coupon_info['id'], 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED], 'mall_id' => $coupon_info['mall_id']]); if (empty($model)) throw new Exception('优惠券不存在或已删除'); if ($coupon_info['total_count'] < 1) { //禅道优惠1458 调整优惠券编辑发放数量 throw new \Exception('优惠券发放数量不能小于1'); } } else { // 添加 $model = new self(); $model->loadDefaultValues(); // 计算优惠券 有效期起止时间 if (AddonsCouponEnum::EXPIRE_TYPE1 == $coupon_info['expire_type'] || AddonsCouponEnum::EXPIRE_TYPE3 == $coupon_info['expire_type']) { // 领取后立即生效,n天过期 // 领取后n天生效,m天过期 $begin_at = $time; $end_at = 0; $coupon_status = 2; } else { $begin_at = $coupon_info['begin_at']; $end_at = $coupon_info['end_at']; if ($begin_at <= $time) { $coupon_status = 2; } else { $coupon_status = 1; } } $coupon_info['begin_at'] = $begin_at; $coupon_info['end_at'] = $end_at; $coupon_info['coupon_status'] = $coupon_status; } foreach ($coupon_info as $key => $val) { $model->$key = $val; } // 指定门店商品,查询出商品的门店 if ($coupon_info['appoint_type'] == AddonsCouponEnum::APPOINT_TYPE6 && !empty($store_goods_id_list)) { // 查询门店 $model->store_id = implode(',', array_unique(StoreGoods::find() ->select('store_id') ->where(['id' => $store_goods_id_list]) ->column())); } // dd($model); if (!$model->save()) throw new Exception($model->getErrorMessage()); if (!empty($category_ids)) { $res = AddonsCouponCatRelate::setData($model->id, $category_ids); if (!$res) throw new Exception(AddonsCouponCatRelate::getStaticError()); } if (!empty($goods_id_list)) { $res = AddonsCouponGoodsRelate::setData($model->id, $goods_id_list); if (!$res) throw new Exception(AddonsCouponGoodsRelate::getStaticError()); } if (!empty($store_goods_id_list)) { $res = CouponStoreGoodsRelate::setData($model->id, $coupon_info['mall_id'], $store_goods_id_list); if (!$res) throw new Exception(CouponStoreGoodsRelate::getStaticError()); } if (1 == $coupon_info['is_member'] && !empty($member_level_limits)) { $res = AddonsCouponMemberRelate::setData($model->mall_id, $model->id, $member_level_limits); if (!$res) throw new Exception(AddonsCouponMemberRelate::getStaticError()); } if ( 1 == $coupon_info['is_giving'] && 1 == $coupon_info['is_giving_reward'] && !empty($giving_rewards) ) { $res = AddonsCouponReward::setData($model->mall_id, $model->id, AddonsCouponEnum::REWARD_TYPE_GIVING, $giving_rewards); if (!$res) throw new Exception(AddonsCouponReward::getStaticError()); } if (1 == $coupon_info['is_consume_reward'] && !empty($consume_rewards)) { $res = AddonsCouponReward::setData($model->mall_id, $model->id, AddonsCouponEnum::REWARD_TYPE_CONSUME, $consume_rewards); if (!$res) throw new Exception(AddonsCouponReward::getStaticError()); } $transaction->commit(); return $model; } catch (Exception $e) { $transaction->rollBack(); self::$static_error = $e->getMessage(); return false; } } /** * 根据用户id查询能用的优惠券列表 * 分多商户 * @Author: hua * @DateTime: 2021/10/15 10:44 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $form * @param $isNewRecord * @return array */ public static function getCanUseCouponList($form, $isNewRecord) { if (!empty($isNewRecord)) return $form; // 下单包含主商城和多商户情况下 不返回优惠券 if (count($form['group_order_goods']) > 1) return $form; $mall_id = $form['mall_id']; $is_install = MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_COUPON); $goods_id_arr = $goods_arr = $mch_arr = []; if (!$is_install) return $form; $total_goods_price = 0; $total_coupon_discount_money = 0; $is_original_goods_price = 1; $data = is_array($form->data) ? $form->data : json_decode($form->data, true); $mch_id = 0; $mch_ids = []; // 优惠券优惠金额 $discount_money = $form['marketing']['deduct']['coupon']['money'] ?? 0; foreach ($form['group_order_goods'] as $item) { if (empty($data['user_coupon_ids'])) { if ($item['mch_order_info']['goods_price'] != $item['mch_order_info']['original_goods_price']) { $is_original_goods_price = 0; } } $mch_id = $item['mch_order_info']['mch_id']; // 不同商户不能合单 $mch_ids[] = $mch_id; $mch_arr[$item['mch_order_info']['mch_id']] = $item['mch_order_info']['goods_price']; if (!empty($item['goods'])) { foreach ($item['goods'] as $v) { $coupon_discount_money = 0; foreach ($v['goods_details'] as $val) { if(!empty($val['marketing'])){ $coupon_discount_money += $val['marketing']['coupon_discount_money'] ?? 0; } } $total_coupon_discount_money += $coupon_discount_money; $total_goods_price += $v['goods_price']; $goods_id_arr[] = $v['goods_id']; $goods_arr[$v['goods_id']] = ['num' => $v['num'], 'goods_price' => $v['goods_price'], 'coupon_discount_money' => $coupon_discount_money, 'mch_id' => $v['goods_details'][0]['mch_id']]; } } } $params = []; $time = time(); $where[] = ['status' => StatusEnum::ENABLED]; $where[] = ['coupon_status' => AddonsCouponEnum::STATUS_RECEIVING]; $where[] = ['is_use' => AddonsCouponEnum::IS_USE0]; $where[] = ['or', ['is_giving' => AddonsCouponEnum::GIVING_N], ['is_giving' => AddonsCouponEnum::GIVING, 'giving_status' => AddonsCouponEnum::GIVING_STATUS1]]; $where[] = ['giving_status' => [AddonsCouponEnum::GIVING_STATUS0, AddonsCouponEnum::GIVING_STATUS1]]; $where[] = ['user_id' => $form['user_id']]; $params['where'] = $where; $params['with'] = ['coupon' => function ($query) use ($mall_id) { $query->where(['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED], 'mall_id' => $mall_id])->with(['goodsRelate', 'cateRelate']); }]; $list = AddonsCouponUserRelate::lists($params); $cate_id_arr = $cate_arr = []; $goods_cate_relate_list = self::getCateArr($goods_id_arr, $goods_arr, $cate_id_arr, $cate_arr); $can_use_list = $can_use_list1 = $can_use_list2 = $can_use_list3 = []; // 优惠券今日剩余可使用次数 $exchangeTypeCouponMaxUseNum = []; foreach ($list as &$v) { if ($v['coupon']) { $coupon = $v['coupon']; // 是否原价购买使用(如果是,则只有原价购买商品时可以使用该优惠券) if(!empty($coupon['is_original_use'])) { if($is_original_goods_price == 0) { continue; } } // 验证这张券是否必须转赠后才能使用 if (!self::checkCouponSourceIsFromSharing($v)) { continue; } $coupon_user_relate_arr[$coupon['id']] = $v['created_at']; if ($v['start_time'] > $time) continue; if ($v['end_time'] < $time) continue; // 1 指定分类 2 指定商品 3全部 $coupon['user_coupon_id'] = $v['id']; $coupon['begin_at'] = $v['start_time']; $coupon['end_at'] = $v['end_time']; // 指定分类 if ($coupon['appoint_type'] == AddonsCouponEnum::APPOINT_TYPE1) { $ct_id_arr = array_column($coupon['cateRelate'], 'cate_id'); unset($coupon['cateRelate']); unset($coupon['goodsRelate']); self::packagingArr($coupon, $cate_id_arr, $cate_arr, $can_use_list1, $ct_id_arr, $coupon_user_relate_arr, $coupon['appoint_type'], 0, $total_coupon_discount_money, $goods_cate_relate_list); continue; } // 指定商品 if ($coupon['appoint_type'] == AddonsCouponEnum::APPOINT_TYPE2) { $gs_id_arr = array_column($coupon['goodsRelate'], 'goods_id'); unset($coupon['goodsRelate']); unset($coupon['cateRelate']); if($coupon['type'] == AddonsCouponEnum::EXCHANGE) { // 多件商品下单不能使用该券 if (count($form['order_goods']) > 1) { continue; } $num = self::getTodayLimit($form['mall_id'], $form['user_id'], $coupon); // 验证该券每日使用次数 if (!$num) { continue; } $exchangeTypeCouponMaxUseNum[$coupon['id']] = $num; } self::packagingArr($coupon, $goods_id_arr, $goods_arr, $can_use_list2, $gs_id_arr, $coupon_user_relate_arr, $coupon['appoint_type'], 0, $total_coupon_discount_money); continue; } // 全部 if ($coupon['appoint_type'] == AddonsCouponEnum::APPOINT_TYPE3) { unset($coupon['goodsRelate']); unset($coupon['cateRelate']); // 使用优惠券前的金额 $after_use_coupon_total_price = bcadd($total_goods_price, abs($discount_money), 2); self::packagingArr($coupon, [], [], $can_use_list3, [], $coupon_user_relate_arr, $coupon['appoint_type'], $after_use_coupon_total_price); continue; } // 指定商户 if ($coupon['appoint_type'] == AddonsCouponEnum::APPOINT_TYPE5) { if (!empty($coupon['mch_id'])) { // 该券属于某个商户的全场通用券 $mch_total_goods_price = $mch_arr[$mch_id]; // 计算使用优惠券前的金额 $mch_total_goods_price = bcadd($mch_total_goods_price, abs($discount_money), 2); self::packagingArr($coupon, [], [], $can_use_list4, [], $coupon_user_relate_arr, $coupon['appoint_type'], $mch_total_goods_price); // 剔除不是相关商户的券 $can_use_list4 && $can_use_list4 = static::getMchUseCoupon($can_use_list4, $mch_ids); } continue; } } } if (!empty($can_use_list1)) self::formatArr($can_use_list1, $can_use_list, 2); if (!empty($can_use_list2)) self::formatArr($can_use_list2, $can_use_list, 2); if (!empty($can_use_list3)) self::formatArr($can_use_list3, $can_use_list, 2); if (!empty($can_use_list4)) self::formatArr($can_use_list4, $can_use_list, 2); if (!empty($exchangeTypeCouponMaxUseNum)) { // 兑换券只能下单一个商品,所以拿第一个即可 array_walk($exchangeTypeCouponMaxUseNum, function (&$val) use ($form) { if (!empty($form->sku) && !empty($sku = reset($form->sku))) { $val = min($sku['stock'], $val); } }); } $form->marketing['deduct']['coupon'] = [ 'list' => $can_use_list, 'type_map' => AddonsCouponEnum::getTypeMap(), 'expire_type_map' => AddonsCouponEnum::getExpireTypeMap(), 'appoint_type_map' => AddonsCouponEnum::getAppointTypeMap(), 'discount_money' => $discount_money, 'exchange_type_coupon_max_use_num' => $exchangeTypeCouponMaxUseNum ?: null, 'goods_stock' => $form->sku ? array_column($form->sku, 'stock', 'id') : [], ]; return $form; } /** * 验证该券每日使用次数 * * @param int $mallId * @param int $userId * @param array $coupon * @param int $usedNum 已使用次数 * @param int $fromType * @param bool $minimumZero 是否最小是0 * * @return int */ public static function getTodayLimit(int $mallId, int $userId, array $coupon, int $usedNum = 0, int $fromType = 1, bool $minimumZero = true): int { if ($coupon['day_limit'] <= 0) { return 0; } $res = $coupon['day_limit'] - self::getCouponTodayUseNum($mallId, $userId, $coupon['id'], $fromType) - $usedNum; if (!$minimumZero) { return $res; } // 验证今日使用这个张券的次数 return max($res, 0); } /** * 返回指定优惠券今日使用次数 * * @param int $mallId * @param int $userId * @param int $id * @param int $fromType * * @return int */ public static function getCouponTodayUseNum(int $mallId, int $userId, int $id, int $fromType = 1): int { if ($fromType == 2) { $find = StoreCouponUseLog::find(); } else { $find = AddonsCouponUseLog::find(); } $today = DateHelper::today(); return $find ->where([ 'mall_id' => $mallId, 'user_id' => $userId, 'coupon_id' => $id, 'status' => StatusEnum::ENABLED, ]) ->andWhere([ 'between', 'created_at', $today['start'], $today['end'] ]) ->count(); } /** * 验证这张券是否开启赠送之后才能使用 * * @param $couponUserRelate * @param int $fromType * * @return bool */ public static function checkCouponSourceIsFromSharing($couponUserRelate, int $fromType = 1): bool { if (empty($couponUserRelate['coupon']['is_giving'])) { return true; } if (empty($couponUserRelate['coupon']['is_giving_use'])) { return true; } if ($fromType == 2) { $find = StoreCouponShareLog::find(); } else { $find = AddonsCouponShareLog::find(); } return $find ->where([ 'mall_id' => $couponUserRelate['mall_id'], 'coupon_id' => $couponUserRelate['coupon_id'], 'get_user_coupon_id' => $couponUserRelate['id'], 'giving_status' => AddonsCouponEnum::GIVING_STATUS2 ]) ->exists(); } /** * 给定一个用户优惠券列表,找出开启了转赠后才能使用的优惠券,并查询这个优惠券是否是通过转赠领取的 * * @param int $mallId * @param array $couponUserRelateList * @param int $fromType 1、3平台,2门店 * * @return array */ public static function getGiftedList(int $mallId, array $couponUserRelateList, int $fromType = 1): array { if (!$couponUserRelateList) { return []; } // 用户优惠券id $relateIds = []; foreach ($couponUserRelateList as $item) { if ( empty($item['coupon']) || empty($item['coupon']['is_giving']) || empty($item['coupon']['is_giving_use']) ) { continue; } $relateIds[] = $item['id']; } if (!$relateIds) { return []; } if ($fromType == 2) { $find = StoreCouponShareLog::find(); } else { $find = AddonsCouponShareLog::find(); } return $find ->where([ 'mall_id' => $mallId, 'get_user_coupon_id' => $relateIds, 'giving_status' => AddonsCouponEnum::GIVING_STATUS2 ]) ->select('get_user_coupon_id') ->column(); } /** * @desc: * @Author: hua * @Date: 2021/10/18 * @Time: 11:54 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $coupon //优惠券 * @param $id_arr//关联id数组 * @param $arr * @param $can_use_list * @param $have_id_arr * @param $coupon_user_relate_arr //领取时间数组 * @param int $appoint_type //使用场景类型 * @param int $total_price //总优惠价格 */ public static function packagingArr($coupon, $id_arr, $arr, &$can_use_list, $have_id_arr, $coupon_user_relate_arr, $appoint_type = 1, $total_price = 0,$total_coupon_discount_money=0, $goods_cate_relate_list = []) { $coupon['coupon_discount_money'] = 0; // 指定商品分类可用 if ($appoint_type == AddonsCouponEnum::APPOINT_TYPE1) { // 获取商品分类 $goods_cids = []; foreach ($goods_cate_relate_list as $item) { $goods_cids[$item['goods_id']][] = $item['cate_id']; } // 获取每个商品是否符合优惠券 $intersect = array_unique(array_map(function ($item) use ($have_id_arr) { return boolval(array_intersect($item, $have_id_arr)); }, $goods_cids)); // 不符合返回 if (!(count($intersect) == 1 && reset($intersect))) return ; foreach ($id_arr as $id) { // count(array_diff($id_arr, $have_id_arr)) == 0) 购买商品的分类IDS和当前券的分类IDS相同 if (in_array($id, $have_id_arr)) { if (!empty($coupon['mch_id'])) { //该券属于某个商户的指定商品 if ($arr[$id]['mch_id'] != $coupon['mch_id']) continue; } // 单分类总价 // $price = $arr[$id]['goods_price'] ?? 0; // 全部分类总价 $price = array_sum(array_column($arr, 'goods_price')); if ($coupon['min_price'] && ($total_coupon_discount_money + $price) >= $coupon['min_price']) { if ($coupon['type'] == AddonsCouponEnum::DISCOUNT) round($coupon['sub_price'] = $coupon['discount'] / 10 * $price, 2); $can_use_list[$coupon['mch_id']][] = $coupon; break; } } } } // 指定商品 if ($appoint_type == AddonsCouponEnum::APPOINT_TYPE2) { foreach ($id_arr as $id) { // count(array_diff($id_arr, $have_id_arr)) == 0) 购买商品的IDS和当前券的IDS相同 if (in_array($id, $have_id_arr) && (count(array_diff($id_arr, $have_id_arr)) == 0)) { if (!empty($coupon['mch_id'])) { //该券属于某个商户的指定商品 if ($arr[$id]['mch_id'] != $coupon['mch_id']) continue; } // 兑换券 if ($coupon['type'] == AddonsCouponEnum::EXCHANGE) { $can_use_list[$coupon['mch_id']][] = $coupon; break; } else { // 其他类型的券 $price = $arr[$id]['goods_price']; if ($coupon['min_price'] && ($arr[$id]['coupon_discount_money'] + $price) >= $coupon['min_price']) { if ($coupon['type'] == AddonsCouponEnum::DISCOUNT) round($coupon['sub_price'] = $coupon['discount'] / 10 * $price, 2); $can_use_list[$coupon['mch_id']][] = $coupon; break; } else if (count(array_diff($id_arr, $have_id_arr)) == 0 && bcadd(array_sum(array_column($arr, 'goods_price')), $total_coupon_discount_money, 2) >= $coupon['min_price']) { // 组合使用 $can_use_list[$coupon['mch_id']][] = $coupon; break; } } } } } // 全场可用 || 指定商户 if ($appoint_type == AddonsCouponEnum::APPOINT_TYPE3 || $appoint_type == AddonsCouponEnum::APPOINT_TYPE5) { if ($coupon['min_price'] && $total_price >= $coupon['min_price']) { if ($coupon['type'] == AddonsCouponEnum::DISCOUNT) $coupon['sub_price'] = round($coupon['discount'] / 10 * $total_price, 2); $can_use_list[$coupon['mch_id']][] = $coupon; } } } /** * 获取分类数据 * @Author: hua * @DateTime: 2021/10/15 10:56 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $goods_id_arr * @param $goods_arr * @param $cate_id_arr * @param $cate_arr * @return string */ public static function getCateArr($goods_id_arr, $goods_arr, &$cate_id_arr, &$cate_arr) { // 查询缓存 $goods_cate_relate_list = GoodsCateRelate::getListByGoodsIds($goods_id_arr, 'id, cate_id, goods_id', 5); foreach ($goods_cate_relate_list as $v) { $cate_id_arr[] = $v['cate_id']; $cate_arr[$v['cate_id']]['mch_id'] = $goods_arr[$v['goods_id']]['mch_id'] ?? 0; if (isset($cate_arr[$v['cate_id']]['goods_price'])) { $cate_arr[$v['cate_id']]['goods_price'] += $goods_arr[$v['goods_id']]['goods_price'] ?? 0; } else { $cate_arr[$v['cate_id']]['goods_price'] = $goods_arr[$v['goods_id']]['goods_price'] ?? 0; } } return $goods_cate_relate_list; } /** * 格式化 * @Author: hua * @DateTime: 2021/10/15 10:04 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $input_arr * @param $output_arr * @param int $deep */ public static function formatArr($input_arr, &$output_arr, $deep = 1) { if ($deep == 1) { array_map(function ($arg) use (&$output_arr) { $output_arr[] = $arg; }, $input_arr); } if ($deep == 2) { array_map(function ($args) use (&$output_arr) { array_map(function ($arg) use (&$output_arr) { $output_arr[] = $arg; }, $args); }, $input_arr); } } /** * 获取商城优惠券 * @author hpei * @param int mall_id * @return array [coupon_id=>coupon_name] */ public static function getMallCoupon($mall_id) { return self::find() ->where(['mall_id' => $mall_id]) ->andWhere(['=', 'status', StatusEnum::ENABLED]) ->andWhere(['=', 'coupon_status', AddonsCouponEnum::STATUS_RECEIVING]) ->andWhere(['or', ['=', 'total_count', '-1'], ['>', 'total_count', 0]]) ->andFilterWhere(['or', ['and', ['>', 'end_at', time()], ['=', 'expire_type', 2]], ['=', 'expire_type', 1]]) ->indexBy('id') ->orderBy('sort asc,id desc') ->asArray() ->all(); } /** * @name: * @msg: 解析优惠券信息 * @param {array} $coupon_data 优惠券原始数据 * @param {bool} $is_user_coupon 是否会员已经领取的优惠券的数据,默认 false * @return array */ public static function parseCouponInfo(array $coupon_data, bool $is_user_coupon = false): array { $coupon_data['min_price'] = floatval($coupon_data['min_price']); $coupon_data['sub_price'] = floatval($coupon_data['sub_price']); $coupon_data['discount'] = floatval($coupon_data['discount']); $coupon_data['discount_limit'] = floatval($coupon_data['discount_limit']); $sub_price = 0; if (1 == $coupon_data['type']) { $content = '消费满' . $coupon_data['min_price'] . '元打' . $coupon_data['discount'] . '折'; if ($coupon_data['discount_limit'] > 0) { $content .= ',最高优惠' . $coupon_data['discount_limit'] . '元'; $sub_price = $coupon_data['discount_limit']; } } elseif (2 == $coupon_data['type']) { $content = '消费满' . $coupon_data['min_price'] . '元减' . $coupon_data['sub_price'] . '元'; $sub_price = $coupon_data['sub_price']; } else { $content = ''; } $superposition = ''; if (1 == $coupon_data['is_original_use']) $superposition = '仅原价购买时可用'; if ($is_user_coupon) { $begin_at = date('Y-m-d H:i', $coupon_data['start_time']); $end_at = date('Y-m-d H:i', $coupon_data['end_time']); $use_time = $begin_at . ' 至 ' . $end_at; } else { switch ($coupon_data['expire_type']) { case AddonsCouponEnum::APPOINT_TYPE1: $use_time = str_replace('N', $coupon_data['expire_day'], AddonsCouponEnum::getExpireTypeMap()[AddonsCouponEnum::APPOINT_TYPE1]); break; case AddonsCouponEnum::APPOINT_TYPE2: $begin_at = date('Y-m-d H:i', $coupon_data['begin_at']); $end_at = date('Y-m-d H:i', $coupon_data['end_at']); $use_time = $begin_at . ' 至 ' . $end_at; break; case AddonsCouponEnum::APPOINT_TYPE3: $use_time = str_replace('N', $coupon_data['expire_day'], AddonsCouponEnum::getExpireTypeMap()[AddonsCouponEnum::APPOINT_TYPE3]); $use_time = str_replace('M', $coupon_data['effect_days'], AddonsCouponEnum::getExpireTypeMap()[AddonsCouponEnum::APPOINT_TYPE3]); break; default: $use_time = ''; break; } $begin_at = date('Y-m-d H:i', $coupon_data['begin_at']); $end_at = $coupon_data['end_at'] ? date('Y-m-d H:i', $coupon_data['end_at']) : ''; } if(isset($coupon_data['is_use']) && $coupon_data['is_use'] == 1){ $status_text = '已使用'; }elseif ($coupon_data['is_giving']==1&&$coupon_data['giving_status']==AddonsCouponEnum::GIVING_STATUS2){ $status_text = '已转赠'; }else{ $status_text = AddonsCouponEnum::getCouponStatusMap($coupon_data['coupon_status'] ?? 0, false); } $coupon_info = [ 'name' => $coupon_data['name'], 'appoint_type' => $coupon_data['appoint_type'], 'status_text' => $status_text, 'use_time' => $use_time, 'content' => $content, 'begin_at' => $begin_at, 'end_at' => $end_at, 'sub_price' => floatval($sub_price), 'min_price' => floatval($coupon_data['min_price']), 'rule' => $coupon_data['rule'], 'superposition_use' => $superposition, ]; return $coupon_info; } /** * @name: * @msg: 在优惠券列表中,处理每一张优惠券对于当前会员是否可以领取 * @param {*} $coupon_list 优惠券列表数据,必须包含 is_member、is_receive_limit、receive_count 字段,必须关联查询 jxmall_coupon_member_relation 表 * @param {int} $user_id 会员id,值为 0 表示未登录 * @return {*} */ public static function userCanReceive(array &$coupon_list, int $user_id = 0) { // 当前会员已经领取的优惠券数据 if (!empty($user_id)) { // 会员已经登录 $user_coupon = AddonsCouponUserRelate::find() ->select('coupon_id,count(*) as count') ->where(['user_id' => $user_id, 'coupon_id' => array_column($coupon_list, 'id'), 'status' => 1]) ->groupBy('coupon_id') ->asArray() ->indexBy('coupon_id') ->all(); // dd($user_coupon); } $user = User::findOne($user_id); foreach ($coupon_list as &$lv) { $lv = array_merge($lv, self::parseCouponInfo($lv)); // 默认不可领取当前优惠券 $lv['is_receive'] = 0; // 当前优惠券限制的会员等级 if (1 == $lv['is_member']) { if (!empty($lv['memberRelate'])) { $member_levels = array_column($lv['memberRelate'], 'member_level'); // dd($member_levels); $user_level = 0; if (!empty($user)) $user_level = $user->level; if (in_array($user_level, $member_levels)) $lv['is_receive'] = 1; } } else { $lv['is_receive'] = 1; } if (empty($user_coupon)) { // 没有任何会员领取过优惠券,当前会员可以继续领取优惠券 $lv['is_receive'] = 1; } else { if (!empty($user_coupon[$lv['id']])) { // 会员已经领取过 if (1 == $lv['is_receive_limit']) { // 已领取数量小于限领数量,可以继续领取优惠券 if ($user_coupon[$lv['id']]['count'] < $lv['receive_count']) { $lv['is_receive'] = 1; } } else { // 不限制数量,可以继续领取优惠券 $lv['is_receive'] = 1; } } // 可以继续领取优惠券 $lv['is_receive'] = 0; } } return true; } /** * @name: * @msg: 检查优惠券的使用场景(指定适用类型、是否可以转赠、转赠和使用奖励、适用会员) * @param {array} $post * @return {*} */ private static function checkUseScene(array $coupon_data) { $coupon_info = $coupon_data['coupon_info'] ?? []; $giving_rewards = $coupon_data['giving_reward'] ?? []; $consume_rewards = $coupon_data['consume_reward'] ?? []; $goods_id_list = $coupon_data['goods_id_list'] ?? []; $store_goods_id_list = $coupon_data['store_goods_id_list'] ?? []; $member_level_limits = $coupon_data['member_level_limits'] ?? []; $category_ids = $coupon_data['category_ids'] ?? []; if (1 == $coupon_info['appoint_type']) { // 指定分类可用 if (empty($category_ids)) { throw new \Exception('指定分类可用的优惠券,请指定可用分类'); } } elseif (2 == $coupon_info['appoint_type']) { // 指定商品可用 if (empty($goods_id_list)) { throw new \Exception('指定商品可用的优惠券,请指定可用商品'); } } elseif (AddonsCouponEnum::APPOINT_TYPE6 == $coupon_info['appoint_type']) { // 指定商品可用 if (empty($store_goods_id_list)) { throw new \Exception('请指定可用门店商品'); } } if ($coupon_info['type'] == AddonsCouponEnum::EXCHANGE && !in_array($coupon_info['appoint_type'], [AddonsCouponEnum::APPOINT_TYPE2, AddonsCouponEnum::APPOINT_TYPE6])) { throw new \Exception('使用范围选择错误'); } if (1 == $coupon_info['is_giving']) { // 开启转赠 if (1 == $coupon_info['is_giving_reward'] && empty($giving_rewards)) { throw new \Exception('请填写转赠奖励'); } if (1 == $coupon_info['is_consume_reward'] && empty($consume_rewards)) { throw new \Exception('请填写使用奖励'); } } if (1 == $coupon_info['is_member']) { // 指定会员等级 if (empty($member_level_limits)) { throw new \Exception('请指定可以领取优惠券的会员等级'); } } } /** * 获取商品的优惠券设置 * @Author: lun * @DateTime: 2022/5/12 0012 14:49 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $params * @return bool|string[] */ public static function getGoodCouponSetting($params) { // 后台页面组件展示 if ($params['type'] == 'show_component') { return [ 'component' => 'com-coupon', 'path' => Yii::$app->basePath . '/../addons/Coupon/backend/views/goods', ]; } else { try { if (empty($params['setting'][AddonsEnum::ADDONS_NAME_COUPON])) return true; $setting = $params['setting'][AddonsEnum::ADDONS_NAME_COUPON]; // 数据保存 $res = CouponGiveItemSetting::setGoodsSetting($params['mall_id'], $params['goods_id'], $setting); if ($res === false) throw new Exception(CouponGiveItemSetting::getStaticError()); return true; } catch (Exception $e) { self::setStaticError($e->getMessage()); return false; } } } /** * 优惠卷统计 * @return \yii\db\ActiveQuery */ public function getStatistics() { return $this->hasOne(AddonsCouponStatistics::class, ['coupon_id' => 'id']); } /** * 获取仅当前商户可使用的券 * * @param array $coupon_list * @param array $mch_ids 当前商户所有id * @return array */ public static function getMchUseCoupon($coupon_list, $mch_ids) { foreach ($coupon_list as $k => $mch_coupon_list) { foreach ($mch_coupon_list as $key => $coupon) { $mch_str = $coupon['mch_id'] ?? 0; $coupon_mch_ids = explode(',', $mch_str); // 判断当前券是否是可以在当前商户里面使用 不符合删除 if (count(array_diff($coupon_mch_ids, $mch_ids)) == count($coupon_mch_ids)) unset($coupon_list[$k][$key]); } } return $coupon_list; } /** * 点击使用优惠券前验证 * * @param array $baseWhere * @param int $mallId * @param int $userId * @param array $params * * @return bool */ public static function jumpCheck(array $baseWhere, int $mallId, int $userId, array $params): bool { $fromType = $params['from_type']; $userCouponId = $params['user_coupon_id']; $goodsId = $params['goods_id']; $select = 'id, coupon_id, mall_id'; if ($fromType == 2) { if (empty(MallAddons::isInstall($mallId, AddonsEnum::ADDONS_NAME_STORE))) { self::setStaticError('优惠券不存在'); return false; } $couponUserRelateModel = new StoreCouponUserRelate(); $goodsModel = new StoreGoods(); $couponUserRelateFind = $couponUserRelateModel::find(); $select .= ', from_type'; } else { $couponUserRelateModel = new AddonsCouponUserRelate(); $goodsModel = new Goods(); $couponUserRelateFind = $couponUserRelateModel::find(); } $couponUserRelateModel::paramPack([ 'where' => array_merge($baseWhere, [ ['id' => $userCouponId] ]), 'select' => $select ], $couponUserRelateFind); $couponUserRelate = $couponUserRelateFind->asArray()->one(); if (empty($couponUserRelate)) { self::setStaticError('优惠券不存在'); return false; } // 门店创建的优惠券不校验 if (isset($couponUserRelate['from_type']) && $couponUserRelate['from_type'] != 1) { return true; } $couponUserRelate['coupon'] = AddonsCoupon::find() ->where([ // 'status' => StatusEnum::ENABLED, 'id' => $couponUserRelate['coupon_id'] ]) ->select('id, is_giving, is_giving_use, is_not_allow_balance_pay, day_limit, type') ->asArray() ->one(); if ( !$goodsModel::find() ->where([ 'mall_id' => $mallId, 'id' => $goodsId, 'status' => StatusEnum::ENABLED, 'is_on_sale' => StatusEnum::ENABLED ]) ->select('stock') ->scalar() ) { self::setStaticError('该商品库存不足'); return false; } if (empty($couponUserRelate['coupon'])) { self::setStaticError('优惠券不存在'); return false; } if ($couponUserRelate['coupon']['type'] == AddonsCouponEnum::EXCHANGE && !self::getTodayLimit($mallId, $userId, $couponUserRelate['coupon'], 0, $fromType)) { self::setStaticError('今日使用已上限'); return false; } if (!self::checkCouponSourceIsFromSharing($couponUserRelate, $fromType)) { self::setStaticError('当前优惠券只能转赠后使用'); return false; } return true; } /** * 验证优惠券是否能使用 * * @param array $user_relate_list * @param $form * @param int $fromType * * @return void * @throws Exception */ public static function checkIsAllowUse(array $user_relate_list, $form, int $fromType = 1) { if (empty($user_relate_list)) { return; } // 判断是否有兑换券类型 $coupons = array_column($user_relate_list, 'coupon'); $types = array_column($coupons, 'type'); if (in_array(AddonsCouponEnum::EXCHANGE, $types)) { // 多件商品下单的不能使用兑换券 if (count($form['order_goods']) > 1) { throw new Exception('单件商品下单时才允许使用兑换券'); } if (count(array_unique($types)) > 1) { throw new Exception('不允许使用不同类型的优惠券'); } // 判断兑换券使用数量 if (count($user_relate_list) > reset($form['order_goods'])['num']) { throw new Exception('兑换券选择错误'); } $allowAppointType = $fromType == 2 ? AddonsCouponEnum::APPOINT_TYPE6 : AddonsCouponEnum::APPOINT_TYPE2; $appointTypes = array_column($coupons, 'appoint_type'); if (count(array_unique($appointTypes)) > 1 || !in_array($allowAppointType, $appointTypes)) { throw new Exception('兑换券选择错误'); } $coupon = reset($coupons); if ($coupon['appoint_type'] != $allowAppointType) { throw new Exception('兑换券选择错误'); } // 按同个优惠券归类 $couponInfoById = []; foreach ($coupons as $coupon) { if (!isset($couponInfoById[$coupon['id']])) { $couponInfoById[$coupon['id']] = [ 'coupon' => $coupon, 'num' => 1 ]; } else { $couponInfoById[$coupon['id']]['num']++; } } // 校验每种优惠券每日可使用的数量 foreach ($couponInfoById as $couponInfo) { if (self::getTodayLimit($form['mall_id'], $form['user_id'], $couponInfo['coupon'], $couponInfo['num'], $fromType, false) < 0) { throw new Exception('当前兑换券今日可用数量超限'); } } } } }