From d046b34ceadced165070b600510caa18e76d7642 Mon Sep 17 00:00:00 2001 From: ctexthuang Date: Thu, 27 Feb 2025 15:32:36 +0800 Subject: [PATCH] feat : coupon --- app/Constants/Common/CouponCode.php | 4 + app/Constants/ConfigCode.php | 21 +++ app/Controller/Api/CouponController.php | 22 +++ app/Model/CouponDispenseLog.php | 35 +++++ app/Model/CouponDispenseUser.php | 13 ++ app/Model/UserCoupon.php | 9 ++ .../Amqp/Coupon/AutoDispenseService.php | 2 +- app/Service/Api/Coupon/HomePopupsService.php | 141 ++++++++++++++++++ app/Service/Api/Coupon/ReceiveService.php | 19 +++ app/Service/Api/Login/LoginBaseService.php | 69 +++++++++ app/Service/Api/Login/WxFastLoginService.php | 20 +-- 11 files changed, 338 insertions(+), 17 deletions(-) create mode 100644 app/Controller/Api/CouponController.php create mode 100644 app/Service/Api/Coupon/HomePopupsService.php create mode 100644 app/Service/Api/Coupon/ReceiveService.php diff --git a/app/Constants/Common/CouponCode.php b/app/Constants/Common/CouponCode.php index a54e9af..2a5828e 100644 --- a/app/Constants/Common/CouponCode.php +++ b/app/Constants/Common/CouponCode.php @@ -51,4 +51,8 @@ class CouponCode CONST INT DISPENSE_STATUS_IS_NO_RECEIVED = 1; CONST INT DISPENSE_STATUS_IS_RECEIVED = 2; + /** + * @var int 优惠券发放方式 0 系统发放 + */ + const int SYSTEMIC_DISTRIBUTION = 0; } \ No newline at end of file diff --git a/app/Constants/ConfigCode.php b/app/Constants/ConfigCode.php index 97950bb..7016f0d 100644 --- a/app/Constants/ConfigCode.php +++ b/app/Constants/ConfigCode.php @@ -4,15 +4,36 @@ namespace App\Constants; class ConfigCode { + /** + * @var string BasicConfiguration|基础配置 + */ const string TODAY_CUT_OFF_TIME_KEY = 'TodayCutOffTime'; // 当日下单截止时间 const string ORDER_CANCEL_TIME_KEY = 'OrderCancelTime'; // 订单取消时间(下单后自动取消) const string SUNDRY_UNIT_PRICE = 'SundryUnitPrice'; // 附加费单价 (服务费) const string SUNDRY_PRICE_COMPUTE_TYPE = 'SundryPriceComputeType'; // 附加费计算方式 1 仅自选计算(默认值) 2 仅套餐计算 3 套餐+自选计算 + /** + * @var string CouponConfiguration|优惠券配置 + */ + const string COUPONS_FOR_NEWCOMERS = 'CouponsForNewcomers'; // 新人赠送的优惠券(送多少张直接用模板 id 加英文字符隔开 0代表不赠送) + const string NEWBIE_COUPON_VALIDITY = 'NewbieCouponValidity'; // 新人优惠券有效期(ps:从领取时间开始的第 x 天 0表示不赠送) + const string INVITING_PARTY_COUPON = 'InvitingPartyCoupon'; // 邀请方优惠券 邀请一个人所送的优惠券 + const string INVITING_PARTY_COUPON_VALIDITY = 'InvitingPartyCouponValidity'; // 邀请方优惠券有效期(ps:从领取时间开始的第 x 天) + const string INVITED_PARTY_COUPON = 'InvitedPartyCoupon'; // 被邀请方优惠券 被邀请一个人所送的优惠券 + const string INVITEE_COUPON_VALIDITY = 'InviteeCouponValidity'; // 被邀请方优惠券有效期(ps:从领取时间开始的第 x 天) + const array DEFAULT_VALUE = [ + //BasicConfiguration self::TODAY_CUT_OFF_TIME_KEY => '15:00:00', self::ORDER_CANCEL_TIME_KEY => 5, self::SUNDRY_UNIT_PRICE => '3', self::SUNDRY_PRICE_COMPUTE_TYPE => 1, + //CouponConfiguration + self::COUPONS_FOR_NEWCOMERS => '0', + self::NEWBIE_COUPON_VALIDITY => '0', + self::INVITING_PARTY_COUPON => '0', + self::INVITING_PARTY_COUPON_VALIDITY => '0', + self::INVITED_PARTY_COUPON => '0', + self::INVITEE_COUPON_VALIDITY => '0', ]; } \ No newline at end of file diff --git a/app/Controller/Api/CouponController.php b/app/Controller/Api/CouponController.php new file mode 100644 index 0000000..adcea52 --- /dev/null +++ b/app/Controller/Api/CouponController.php @@ -0,0 +1,22 @@ +handle(); + } +} diff --git a/app/Model/CouponDispenseLog.php b/app/Model/CouponDispenseLog.php index a2e9faa..82896a4 100644 --- a/app/Model/CouponDispenseLog.php +++ b/app/Model/CouponDispenseLog.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace App\Model; +use App\Constants\Common\CouponCode; +use Hyperf\Collection\Collection; use Hyperf\DbConnection\Model\Model; /** @@ -55,6 +57,15 @@ class CouponDispenseLog extends Model return $this->find($id); } + /** + * @param array $ids + * @return array + */ + public function getListByIds(array $ids): array + { + return $this->whereIn('id',$ids)->get()->toArray(); + } + /** * @param int $id * @param int $receiveCount @@ -64,6 +75,30 @@ class CouponDispenseLog extends Model { return $this->where('id', $id)->increment('receive_count' , $receiveCount); } + + /** + * @return array + */ + public function getNoReceiveCount(): array + { + $all = $this + ->where('claim_rule',CouponCode::DISPENSE_CLAIM_RULE_HOME_POPUPS) + ->whereColumn('total_count','!=','receive_count') + ->where('appoint_group',CouponCode::DISPENSE_APPOINT_GROUP_ALL_PEOPLE) + ->pluck('id') + ->toArray(); + + $appoint = $this + ->where('claim_rule',CouponCode::DISPENSE_CLAIM_RULE_HOME_POPUPS) + ->where('appoint_group','!=',CouponCode::DISPENSE_APPOINT_GROUP_ALL_PEOPLE) + ->pluck('id') + ->toArray(); + + return [ + 'all' => $all, + 'appoint' => $appoint + ]; + } } diff --git a/app/Model/CouponDispenseUser.php b/app/Model/CouponDispenseUser.php index 4878234..69e4d2c 100644 --- a/app/Model/CouponDispenseUser.php +++ b/app/Model/CouponDispenseUser.php @@ -72,4 +72,17 @@ class CouponDispenseUser extends Model 'is_receive' => CouponCode::DISPENSE_STATUS_IS_RECEIVED ]); } + + /** + * @param array $userIds + * @return array + */ + public function getNoReceiveCountByUserIds(array $userIds): array + { + return $this + ->whereIn('user_id', $userIds) + ->where('receive_count',CouponCode::DISPENSE_STATUS_IS_NO_RECEIVED) + ->pluck('coupon_dispense_id') + ->toArray(); + } } diff --git a/app/Model/UserCoupon.php b/app/Model/UserCoupon.php index ad598a2..9e9756b 100644 --- a/app/Model/UserCoupon.php +++ b/app/Model/UserCoupon.php @@ -39,4 +39,13 @@ class UserCoupon extends Model const string CREATED_AT = 'created_time'; const string UPDATED_AT = 'updated_time'; + + public function getReceiveCountByUserIds(int $user_id,array $couponIdArr): array + { + return $this + ->where('user_id', $user_id) + ->whereIn('coupon_id', $couponIdArr) + ->pluck('coupon_id') + ->toArray(); + } } diff --git a/app/Service/Amqp/Coupon/AutoDispenseService.php b/app/Service/Amqp/Coupon/AutoDispenseService.php index 989ff6c..2ea9b38 100644 --- a/app/Service/Amqp/Coupon/AutoDispenseService.php +++ b/app/Service/Amqp/Coupon/AutoDispenseService.php @@ -59,7 +59,7 @@ class AutoDispenseService foreach ($partArr as $onePart) { $insertData = []; foreach ($onePart as $oneUser) { - //todo 模拟数据 + // 模拟数据 $oneUserData = [ 'user_id' => $oneUser, 'coupon_template_id' => $dispenseInfo->coupon_template_id, diff --git a/app/Service/Api/Coupon/HomePopupsService.php b/app/Service/Api/Coupon/HomePopupsService.php new file mode 100644 index 0000000..5fc8e68 --- /dev/null +++ b/app/Service/Api/Coupon/HomePopupsService.php @@ -0,0 +1,141 @@ +couponDispenseUserModel->getNoReceiveCountByUserIds($this->userId); + + $data = $this->couponDispenseLogModel->getNoReceiveCount(); + if (empty($dispenseIds) && empty($data['all']) && empty($data['appoint'])) return $this->returnNullRes(); + + $allDispenseIds = []; + if (!empty($all['all'])) { + $allDispenseIds = $this->userCouponModel->getReceiveCountByUserIds($this->userId,$data['all']); + } + + $canReceive = array_unique(array_merge( + array_diff($data['all'], $allDispenseIds), + array_intersect($dispenseIds,$data['appoint']) + )); + + if (empty($canReceive)) return $this->returnNullRes(); + + $this->receive($canReceive); + + return $this->return->success('success',['canReceive'=>$canReceive]); + } + + /** + * @param array $data + * @return void + */ + private function receive(array $data): void + { + $list = $this->couponDispenseLogModel->getListByIds($data); + if (empty($list)) return; + + $insertData = []; + $appointUpdateData = []; + $allUpdateData =[]; + foreach ($list as $item) { + $oneData = [ + 'user_id' => $this->userId, + 'coupon_template_id' => $item['coupon_template_id'], + 'coupon_name' => $item['coupon_name']->coupon_name, + 'coupon_dispense_id' => $item['id'], + 'status' => CouponCode::COUPON_STATUS_UNUSED, + 'validity_start_time' => $item['validity_start_time'], + 'validity_end_time' => $item['validity_end_time'], + ]; + + $copies = array_map(function () use ($oneData) { + return $oneData; + }, array_fill(0, $item['item_count'], null)); + + $insertData = array_merge($insertData, $copies); + + if ($item['appoint_group'] == CouponCode::DISPENSE_APPOINT_GROUP_ALL_PEOPLE) { + $allUpdateData[] = [ + 'id' => $item['id'], + 'receive_count' => $item['receive_count'] +$item['item_count'], + ]; + } else { + $appointUpdateData[] = [ + 'coupon_dispense_id' => $item['id'], + 'user_id' => $this->userId, + ]; + + $allUpdateData[] = [ + 'id' => $item['id'], + 'receive_count' => $item['receive_count'] +$item['item_count'], + ]; + } + } + + if (empty($allUpdateData)) return; + + if (!empty($appointUpdateData)) { + $appointList = $this->couponDispenseUserModel->where('user_id',$this->userId)->whereIn('id',array_column($appointUpdateData,'coupon_dispense_id'))->pluck('id','coupon_dispense_id'); + + foreach ($appointUpdateData as &$item) { + $item['id'] = $appointList[$item['coupon_dispense_id']]; + } + } + + Db::transaction(function () use($allUpdateData,$appointUpdateData) { + $appointUpdateFlag = true; + + if (!empty($appointUpdateData)) { + $appointUpdateFlag = (new CouponDispenseUser())->update($appointUpdateData); + } + + $allUpdateFlag = (new CouponDispenseLog)->update($allUpdateData); + + if (!$allUpdateFlag || !$appointUpdateFlag) throw new ErrException('领取失败'); + }); + } + + private function returnNullRes(): array + { + return $this->return->success(); + } +} \ No newline at end of file diff --git a/app/Service/Api/Coupon/ReceiveService.php b/app/Service/Api/Coupon/ReceiveService.php new file mode 100644 index 0000000..941c390 --- /dev/null +++ b/app/Service/Api/Coupon/ReceiveService.php @@ -0,0 +1,19 @@ +userInfo = $model; } + /** + * 添加账户 + * @return void + */ + protected function addAccount(): void + { + $model = new UserAccount(); + + $model->user_id = $this->userId; + $model->balance = 0; + $model->integral = 0; + + if (!$model->save()) throw new ErrException('注册失败-00002'); + } + + /** + * @var CouponTemplate $couponTemplateModel + */ + #[Inject] + protected CouponTemplate $couponTemplateModel; + + /** + * @return void + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + protected function addCoupon(): void + { + $couponTemplateId = $this->configCache->getConfigValue(ConfigCode::COUPONS_FOR_NEWCOMERS); + $couponValidity = $this->configCache->getConfigValue(ConfigCode::NEWBIE_COUPON_VALIDITY); + + // 随便一个为0代表不赠送 + if ($couponValidity == 0 || $couponTemplateId == 0) return; + + $couponTemplateId = explode(',', $couponTemplateId); + $couponTemplateList = $this->couponTemplateModel->getDataByIds($couponTemplateId); + + $insertCoupon = []; + foreach ($couponTemplateId as $one){ + if ($couponTemplateList[$one]['status'] == CouponCode::COUPON_TEMPLATE_STATUS_ENABLE) continue; + + $insertCoupon[] = [ + 'coupon_template_id' => $one, + 'coupon_dispense_id' => CouponCode::SYSTEMIC_DISTRIBUTION, + 'user_id' => $this->userId, + 'status' => CouponCode::COUPON_STATUS_UNUSED, + 'coupon_name' => $couponTemplateList[$one]['name'], + 'validity_start_time' => date('Y-m-d H:i:s'), + 'validity_end_time' => date('Y-m-d', strtotime('+'.$couponValidity.' days')), + ]; + } + + if (empty($insertCoupon)) return; + + if (!(new UserCoupon)->insert($insertCoupon)) throw new ErrException('注册失败-00003'); + } + abstract protected function register(); } \ No newline at end of file diff --git a/app/Service/Api/Login/WxFastLoginService.php b/app/Service/Api/Login/WxFastLoginService.php index 2ae06d2..deddf73 100644 --- a/app/Service/Api/Login/WxFastLoginService.php +++ b/app/Service/Api/Login/WxFastLoginService.php @@ -77,7 +77,10 @@ class WxFastLoginService extends LoginBaseService $this->addAccount(); - //todo 要不要生成邀请码 有没有注册奖励 + //todo 邀请过来的 邀请方有没有奖励 被邀请方有没有奖励 + + // 有没有注册奖励 + $this->addCoupon(); }); } @@ -95,19 +98,4 @@ class WxFastLoginService extends LoginBaseService if (!$model->save()) throw new ErrException('注册失败-00001'); } - - /** - * 添加账户 - * @return void - */ - private function addAccount(): void - { - $model = new UserAccount(); - - $model->user_id = $this->userId; - $model->balance = 0; - $model->integral = 0; - - if (!$model->save()) throw new ErrException('注册失败-00002'); - } } \ No newline at end of file