diff --git a/app/Controller/NotifyController.php b/app/Controller/NotifyController.php index b58bc91..955db3f 100644 --- a/app/Controller/NotifyController.php +++ b/app/Controller/NotifyController.php @@ -13,6 +13,7 @@ use App\Model\Store; use App\Model\StoreAccount; use App\Model\SystemConfig; use App\Model\Users; +use App\Service\CouponRebateServiceInterface; use App\Service\DeviceServiceInterface; use App\Service\FeiePrintServiceInterface; use App\Service\MiniprogramServiceInterface; @@ -61,6 +62,12 @@ class NotifyController extends BaseController */ protected $userService; + /** + * @Inject + * @var CouponRebateServiceInterface + */ + protected $couponRebateService; + public function wxminiOnline() { @@ -175,6 +182,9 @@ class NotifyController extends BaseController $inSalesStatistics = OrderSalesStatistic::query()->insert($statistics); } + // 优惠券返券 + $this->couponRebateService->couponRebateInTask($orderMain->id); + // 喇叭通知,兼容旧音响,MQTT+IOT $res = $this->mqttSpeakerService->speakToStore($orderMain->id); $this->log->event( diff --git a/app/Service/CouponRebateService.php b/app/Service/CouponRebateService.php new file mode 100644 index 0000000..efe3f34 --- /dev/null +++ b/app/Service/CouponRebateService.php @@ -0,0 +1,531 @@ +0领取失败 + $result = [ + 'status' => 1, + 'coupon_text' => '活动已过期~' + ]; + /* 如果请求的优惠券ids为空,则返回过期提示 */ + if($this->commonService->empty($params["ids"])){ + return $result; + } + + $ids = $params["ids"]; + $idsData = is_array($ids) ? $ids : explode(',',$ids); + + // 错误日志记录 + $errorData = [ + 'coupon_ids' =>$ids, + 'user_id' =>$userId, + 'receiveType' =>$receiveType, + 'sendUserId' =>$sendUserId, + 'phone' =>$phone + ]; + + $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class); + $activity = $ssdb->exec('hget', SsdbKeysPrefix::COUPON_REBATE_ACTIVITY ,'activity'); + // ssdb 键值 + $ssdbKey = 'activity_'.$activity.'_user_'.$userId; + $receiveSsdb = []; + + // 判断是否已全部领取过 + $userReceive = $ssdb->exec('hget', SsdbKeysPrefix::COUPON_REBATE_RECEIVE,$ssdbKey); + if($userReceive === false){ + $ids = $idsData; + }else{ + $userReceiveCouponIds = empty($userReceive) ? [] : explode(',',$userReceive) ; + $ids = array_diff($idsData, $userReceiveCouponIds); + $receiveSsdb = $userReceiveCouponIds; + } + + if(count($ids) > 0){ + try{ + Db::transaction( function() use ($ids,$receiveType,$userId,$sendUserId,$phone,&$result,&$errorData,&$receiveSsdb) { + + $now = time(); + $success = []; + + //获取优惠券信息 (读写锁,完全控制,性能低) + $coupons = Coupon::whereIn('id', $ids)->lockForUpdate() + ->where('active_type',2) + ->where('status',1) + ->where('start_time', '<=', $now) + ->where('end_time', '>=', $now) + ->whereRaw('inventory > inventory_use') + ->select('id','title','inventory','inventory_use','full_amount','discounts','active_type') + ->get(); + + foreach($coupons as $coupon){ + $errorData['coupon_id'] = $coupon->id; + + // 查询一次能领取的数量 + $couponReceiveType = CouponUserRecType::where('system_coupon_user_id',$coupon->id)->select('one_receive_number'); + if (env('SUB_CHANNEL') == 1) { + $couponReceiveType->where('receive_type',$receiveType); + } + $couponReceiveType = $couponReceiveType->first(); + + // 优惠券可领取数量 >= 本次领取数量 + if($coupon->inventory - $coupon->inventory_use >= $couponReceiveType->one_receive_number){ + + // 判断是否领取过 存在记录则领取过 + $isReceive = CouponRec::select('id') + ->where('system_coupon_user_id',$coupon->id) + ->where('user_id',$userId) + ->exists(); + + if(!$isReceive){ + //记录已领取的数量 + $coupon->inventory_use += $couponReceiveType->one_receive_number; + + $couponReceive = new CouponRec; + $couponReceive->user_id = $userId; + $couponReceive->system_coupon_user_id = $coupon->id; + $couponReceive->order_main_id = 0; + $couponReceive->receive_time = $now; + $couponReceive->number = $couponReceiveType->one_receive_number; + $couponReceive->number_remain = $couponReceiveType->one_receive_number; + $couponReceive->status = 0; + $couponReceive->update_time = $now; + $couponReceive->receive_type = $receiveType; + $couponReceive->send_user_id = $sendUserId; + $couponReceive->phone = $phone; + + if ( $couponReceive->save() && $coupon->save() ) { + $success[] = $coupon; + $receiveSsdb[] = $coupon->id; + }else{ + $errorData['msg'] = '添加优惠券到用户领取表或者记录已领取数量失败'; + $this->log->event( + LogLabel::COUPON_LOG, + $errorData + ); + } + } + } + } + if(count($success) > 0){ + $result['status'] = 0; + $result['coupon_text'] = '恭喜您领取成功!'; + } + }); + } catch (Exception $e){ + $errorData['msg'] = $e->getMessage(); + $this->log->event( + LogLabel::COUPON_LOG, + $errorData + ); + } + + if(count($receiveSsdb) > 0){ + + $saveSsdb = [ + $ssdbKey, + implode(',',$receiveSsdb) + ]; + if(false === $ssdb->exec('hset',SsdbKeysPrefix::COUPON_REBATE_RECEIVE, $saveSsdb)){ + $errorData['msg'] = '记录领取优惠券到ssdb失败'; + $this->log->event( + LogLabel::COUPON_LOG, + $errorData + ); + }; + } + }else{ + $result['status'] = 2; + $result['coupon_text'] = '您已领取!赶快去下单吧~'; + } + + return $result; + } + + /* + * 判断用户是否已领取过优惠券 + * */ + public function isCouponRebate($user_id) + { + $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class); + $activity = $ssdb->exec('hget', SsdbKeysPrefix::COUPON_REBATE_ACTIVITY ,'activity'); + // ssdb 键值 + $ssdbKey = 'activity_'.$activity.'_user_'.$user_id; + + // 判断是否已全部领取过 + $userReceive = $ssdb->exec('hget', SsdbKeysPrefix::COUPON_REBATE_RECEIVE,$ssdbKey); + if($userReceive === false || is_null($userReceive)){ + return false; + }else{ + return $userReceive; + } + + } + + /* + *获取活动信息 + */ + public function getActiveInfo() + { + //获取SSDB上的活动信息 + $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class); + $active = $ssdb->exec('hgetall',SsdbKeysPrefix::COUPON_REBATE_ACTIVITY); + $coupon_ids = explode(',',$active['forward']); + $time = time(); + $res = Db::table('ims_system_coupon_user') + ->whereIn('id',$coupon_ids) + ->where([ + ['status', '=', 1], + ['active_type', '=', 2], + ['start_time', '<=', $time], + ['end_time', '>', $time], + ]) + ->whereRaw('inventory > inventory_use') + ->orderBy('weigh', 'desc') + ->orderBy('addtime', 'desc') + ->get(); + return $res; + } + + /** + * 将优惠券绑定活动 + * 领取优惠券 COUPON_REBATE_FORWARD 可多张 + * 返还优惠券 COUPON_REBATE_REPAY 只一张 + */ + public function tieCouponActive($couponActivity, $couponForward, $couponRepay) + { + + $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class); + + $data = [ + 'activity', $couponActivity, + 'forward' , $couponForward, + 'repay' , $couponRepay + ]; + + $result = [ + 'result' => ($ssdb->exec('multi_hset', SsdbKeysPrefix::COUPON_REBATE_ACTIVITY, $data) === false) ? false : true , + 'data' => $ssdb->exec('hgetall', SsdbKeysPrefix::COUPON_REBATE_ACTIVITY) + ]; + + return $result; + } + + /* + * 支付成功 返券 + */ + public function couponRebate($order_id) + { + //获取SSDB上的活动信息 + $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class); + $active = $ssdb->execWithoutTask('hgetall',SsdbKeysPrefix::COUPON_REBATE_ACTIVITY); + //判断返券优惠券是否有库存 + $inventory = Db::table('ims_system_coupon_user') + ->where('id',$active['repay']) + ->whereRaw('inventory > inventory_use') + ->exists(); + if(!$inventory){ + //库存不足 + return false; + } + + //获取活动发放优惠券id + $coupon_ids = explode(',',$active['forward']); + + /* 判断被使用的优惠券类型是否为转发活动优惠券 */ + $coupon = Db::table('ims_system_coupon_user_receive as r') + ->leftjoin('ims_system_coupon_user_use as u', 'u.user_receive_id', '=', 'r.id') + ->where([ + ['u.order_main_id', '=', $order_id], + ['r.send_user_id', '>', 0], + ['r.rebate_type', '=', 1], + ['r.receive_type', '=', 4], + ]) + ->whereIn('r.system_coupon_user_id',$coupon_ids) + ->select('r.user_id', 'r.send_user_id') + ->first(); + /* 如果使用的优惠券为转发活动优惠券 + **则给赠送者返一张优惠券 + * **自己给自己转发的券不给返券 + */ + if ($coupon && ($coupon->user_id != $coupon->send_user_id)) { + //是否已返过券 + $exists_coupon_rebate = Db::table('ims_system_coupon_user_receive') + ->where([ + ['system_coupon_user_id' ,'=', $active['repay']], + ['user_id' ,'=', $coupon->send_user_id], + ['receive_type' ,'=', 5], + ]) + ->select('id','status') + ->first(); + //开启事务 + Db::beginTransaction(); + try { + //返券 + if($exists_coupon_rebate){ + //如果已有该优惠券 则领取数量 和 可用数量 自增1 + Db::table('ims_system_coupon_user_receive') + ->where([ + ['id' ,'=', $exists_coupon_rebate->id], + ]) + ->increment('number'); + Db::table('ims_system_coupon_user_receive') + ->where([ + ['id' ,'=', $exists_coupon_rebate->id], + ]) + ->increment('number_remain'); + //如果该用户在领取表中 status为已用完状态 2 则改为已用部分 1 + if($exists_coupon_rebate->status == 2){ + Db::table('ims_system_coupon_user_receive') + ->where([ + ['id' ,'=', $exists_coupon_rebate->id], + ]) + ->update(['status' => 1]);; + } + }else { + //否则新增一条返券记录 + $nowTime = time(); + Db::table('ims_system_coupon_user_receive')->insert([ + [ + 'user_id' => $coupon->send_user_id, + 'system_coupon_user_id' => $active['repay'], + 'receive_type' => 5, + 'status' => 0, + 'number' => 1, + 'number_remain' => 1, + 'order_main_id' => $order_id, + 'receive_time' => $nowTime, + 'update_time' => $nowTime, + 'created_at' => $nowTime, + 'updated_at' => $nowTime, + ] + ]); + } + //首次返券更新rebate_type字段 防止重复返券 + Db::table('ims_system_coupon_user_receive') + ->where([ + ['user_id','=',$coupon->user_id], + ['receive_type','=',4], + ]) + ->whereIn('system_coupon_user_id',$coupon_ids) + ->update(['rebate_type' => 2]); + //更新库存操作 + Db::table('ims_system_coupon_user') + ->where('id', $active['repay']) + ->increment('inventory_use'); + + //添加领取记录到ssdb + $data = [ + $order_id,$coupon->user_id, + ]; + $ssdb->execWithoutTask('multi_hset', SsdbKeysPrefix::COUPON_REBATE_LIST.$coupon->send_user_id, $data); + // 提交 + Db::commit(); + } catch (\Exception $e) { + //写入日志文件 + $log_Data = array(); + $log_Data['name'] = '返券'; + $log_Data['order_id'] = $order_id; + $log_Data['msg'] = '返券失败'; + $this->log->event( + LogLabel::COUPON_LOG, + $log_Data + ); + // 回滚 + Db::rollBack(); + } + } + return true; + } + + /* + * 支付成功 返券 + */ + public function couponRebateInTask($order_id) + { + //获取SSDB上的活动信息 + $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class); + $active = $ssdb->exec('hgetall',SsdbKeysPrefix::COUPON_REBATE_ACTIVITY); + //判断返券优惠券是否有库存 + $inventory = Db::table('ims_system_coupon_user') + ->where('id',$active['repay']) + ->whereRaw('inventory > inventory_use') + ->exists(); + if(!$inventory){ + //库存不足 + return false; + } + + //获取活动发放优惠券id + $coupon_ids = explode(',',$active['forward']); + + /* 判断被使用的优惠券类型是否为转发活动优惠券 */ + $coupon = Db::table('ims_system_coupon_user_receive as r') + ->leftjoin('ims_system_coupon_user_use as u', 'u.user_receive_id', '=', 'r.id') + ->where([ + ['u.order_main_id', '=', $order_id], + ['r.send_user_id', '>', 0], + ['r.rebate_type', '=', 1], + ['r.receive_type', '=', 4], + ]) + ->whereIn('r.system_coupon_user_id',$coupon_ids) + ->select('r.user_id', 'r.send_user_id') + ->first(); + /* 如果使用的优惠券为转发活动优惠券 + **则给赠送者返一张优惠券 + * **自己给自己转发的券不给返券 + */ + if ($coupon && ($coupon->user_id != $coupon->send_user_id)) { + //是否已返过券 + $exists_coupon_rebate = Db::table('ims_system_coupon_user_receive') + ->where([ + ['system_coupon_user_id' ,'=', $active['repay']], + ['user_id' ,'=', $coupon->send_user_id], + ['receive_type' ,'=', 5], + ]) + ->select('id','status') + ->first(); + //开启事务 + Db::beginTransaction(); + try { + //返券 + if($exists_coupon_rebate){ + //如果已有该优惠券 则领取数量 和 可用数量 自增1 + Db::table('ims_system_coupon_user_receive') + ->where([ + ['id' ,'=', $exists_coupon_rebate->id], + ]) + ->increment('number'); + Db::table('ims_system_coupon_user_receive') + ->where([ + ['id' ,'=', $exists_coupon_rebate->id], + ]) + ->increment('number_remain'); + //如果该用户在领取表中 status为已用完状态 2 则改为已用部分 1 + if($exists_coupon_rebate->status == 2){ + Db::table('ims_system_coupon_user_receive') + ->where([ + ['id' ,'=', $exists_coupon_rebate->id], + ]) + ->update(['status' => 1]);; + } + }else { + //否则新增一条返券记录 + $nowTime = time(); + Db::table('ims_system_coupon_user_receive')->insert([ + [ + 'user_id' => $coupon->send_user_id, + 'system_coupon_user_id' => $active['repay'], + 'receive_type' => 5, + 'status' => 0, + 'number' => 1, + 'number_remain' => 1, + 'order_main_id' => $order_id, + 'receive_time' => $nowTime, + 'update_time' => $nowTime, + 'created_at' => $nowTime, + 'updated_at' => $nowTime, + ] + ]); + } + //首次返券更新rebate_type字段 防止重复返券 + Db::table('ims_system_coupon_user_receive') + ->where([ + ['user_id','=',$coupon->user_id], + ['receive_type','=',4], + ]) + ->whereIn('system_coupon_user_id',$coupon_ids) + ->update(['rebate_type' => 2]); + //更新库存操作 + Db::table('ims_system_coupon_user') + ->where('id', $active['repay']) + ->increment('inventory_use'); + + //添加领取记录到ssdb + $data = [ + $order_id,$coupon->user_id, + ]; + $ssdb->exec('multi_hset', SsdbKeysPrefix::COUPON_REBATE_LIST.$coupon->send_user_id, $data); + // 提交 + Db::commit(); + } catch (\Exception $e) { + //写入日志文件 + $log_Data = array(); + $log_Data['name'] = '返券'; + $log_Data['order_id'] = $order_id; + $log_Data['msg'] = '返券失败'; + $this->log->event( + LogLabel::COUPON_LOG, + $log_Data + ); + // 回滚 + Db::rollBack(); + } + } + return true; + } + + /** + * 清优惠券领取记录(SSDB) + */ + public function clearSsdbCouponReceiveByName($activity, $userId, $get = 0, $isAll = 0){ + $key = 'activity_'.$activity.'_user_'.$userId; + $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class); + + if($isAll > 0){ + if($get > 0){ + return $ssdb->exec('hgetAll', SsdbKeysPrefix::COUPON_REBATE_RECEIVE); + }else{ + return ( $ssdb->exec('hclear', SsdbKeysPrefix::COUPON_REBATE_RECEIVE) === false) ? false : true ; + } + }else { + if($get > 0){ + return $ssdb->exec('hget', SsdbKeysPrefix::COUPON_REBATE_RECEIVE, $key); + }else{ + return ( $ssdb->exec('hdel', SsdbKeysPrefix::COUPON_REBATE_RECEIVE, $key) === false) ? false : true ; + } + } + } +} \ No newline at end of file diff --git a/app/Service/CouponRebateServiceInterface.php b/app/Service/CouponRebateServiceInterface.php new file mode 100644 index 0000000..4208c28 --- /dev/null +++ b/app/Service/CouponRebateServiceInterface.php @@ -0,0 +1,24 @@ + \App\Service\FeiePrintService::class, \App\Service\MiniprogramServiceInterface::class => \App\Service\MiniprogramService::class, \App\Service\UserServiceInterface::class => \App\Service\UserService::class, + \App\Service\CouponRebateServiceInterface::class => \App\Service\CouponRebateService::class, ];