Browse Source

优惠券返券

master
weigang 5 years ago
parent
commit
ac4ff48e17
  1. 10
      app/Controller/NotifyController.php
  2. 531
      app/Service/CouponRebateService.php
  3. 24
      app/Service/CouponRebateServiceInterface.php
  4. 1
      config/autoload/dependencies.php

10
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(

531
app/Service/CouponRebateService.php

@ -0,0 +1,531 @@
<?php
namespace App\Service;
use Hyperf\Di\Annotation\Inject;
use Hyperf\DbConnection\Db;
use App\Model\Coupon;
use App\Model\CouponUserRecType;
use App\Model\CouponRec;
use App\Constants\LogLabel;
use App\Commons\Log;
use Hyperf\Utils\ApplicationContext;
use App\TaskWorker\SSDBTask;
use App\Constants\SsdbKeysPrefix;
use Exception;
use App\Service\CommonService;
use function AlibabaCloud\Client\json;
class CouponRebateService implements CouponRebateServiceInterface
{
/**
* @Inject
* @var Log
*/
protected $log;
/**
* @Inject
* @var CommonService
*/
protected $commonService;
/**
* 领取优惠券
* 返券活动领取
* 一次可领取多张优惠券
* 一个用户不可重复领取
*/
public function userReceiveCoupon($params)
{
$userId = $params["user_id"];
$receiveType = $params["receive_type"];
$sendUserId = $params["send_user_id"];
$phone = $params["phone"];
// status: 0领取成功 >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 ;
}
}
}
}

24
app/Service/CouponRebateServiceInterface.php

@ -0,0 +1,24 @@
<?php
namespace App\Service;
interface CouponRebateServiceInterface
{
/**
* 领取优惠券
*/
public function userReceiveCoupon($params);
public function isCouponRebate($user_id);
public function getActiveInfo();
public function tieCouponActive($couponActivity,$couponForward,$couponRepay);
public function couponRebate($order_id);
public function couponRebateInTask($order_id);
public function clearSsdbCouponReceiveByName($activity, $userId, $get = 0, $isAll = 0);
}

1
config/autoload/dependencies.php

@ -23,4 +23,5 @@ return [
\App\Service\FeiePrintServiceInterface::class => \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,
];
Loading…
Cancel
Save