coupon-admin/app/controller/api/Coupon.php

709 lines
27 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace app\controller\api;
use app\exception\RepositoryException;
use app\model\Account;
use app\model\Coupon as CouponModel;
use app\model\CouponBill;
use app\model\CouponMain;
use app\model\Deduction;
use app\model\Redpack;
use app\model\Score;
use app\repository\AccountRepository;
use app\repository\BusinessRepository;
use app\repository\CouponRepository;
use app\service\wx\WechatPay;
use app\validate\CouponRelease;
use app\validate\CouponUsingRule;
use think\Exception;
use think\facade\Config;
use think\facade\Db;
use think\facade\Log;
/**
* 优惠卷相关
* Class Coupon
* @package app\controller\api
*/
class Coupon extends Base
{
protected $noNeedLogin = [];
/**
* 我的优惠卷列表
*
* type in ['', 'notUsed', 'normal', 'used']
*/
public function getCouponList()
{
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 10);
$type = $this->request->param('type', '');
$page = $page < 1 ? 1 : $page;
$size = $size < 1 ? 10 : $size;
$accountCode = $this->request->user['user_code'] ?? '';
try {
$whereMap = [];
$sortOrder = ['received_time' => 'desc'];
$fields = [
'id',
'is_verificated as isVerificated',
'money',
'name as couponName',
'business_code as businessCode',
'end_time as endTime',
'consumer_name as consumerName',
'verificate_time as verificateTime',
'(end_time > NOW()) as sort_weight'];
$whereMap[] = ['consumer_code', '=', $accountCode];
switch ($type) {
case 'all':
// 全部持有优惠券
$sortOrder = ['sort_weight' => 'desc', 'end_time' => 'asc'];
break;
case 'notUsed':
// 未使用(包含已过期)
$whereMap[] = ['is_verificated', '=', self::BOOL_FALSE];
$sortOrder = ['sort_weight' => 'desc', 'end_time' => 'asc'];
break;
case 'normal':
// 未使用且未过期
$whereMap[] = ['is_verificated', '=', self::BOOL_FALSE];
$whereMap[] = ['end_time', '< TIME', date('Y-m-d H:i:s')];
break;
case 'used':
// 已使用
$whereMap[] = ['is_verificated', '=', self::BOOL_TRUE];
$sortOrder = ['verificate_time' => 'desc'];
break;
}
$res = CouponRepository::getInstance()->findList($whereMap, $fields, $page, $size,function ($q){
return $q->with(["couponMain","scoreModel"]);
}, $sortOrder);
$res['list'] ->each(function ($item){
//重置优惠券名称
if(isset($item->couponMain) && $item->couponMain){
$item->couponName = $item->couponMain->name;
}
//是否已经打分过了
if(isset($item->scoreModel) && $item->scoreModel){
$item->scored = true;
$item->score = $item->scoreModel->score;
}else{
$item->scored = false;
$item->score = Score::COMMON_OFF;
}
});
$res['list'] = multiTwoArrayKeysExcludeFilter($res['list']->toArray(), ['sort_weight']);
return $this->json(0, 'success', $res);
} catch (RepositoryException | \Exception $e) {
return $this->json(5001, '优惠卷查询失败!');
}
}
/**
* 我的优惠卷列表 指定商家
*
*/
public function getCouponListByBusinessCode()
{
$page = $this->request->param('page/d', 1);
$size = $this->request->param('size/d', 10);
$businessCode = $this->request->param('business_code/s', '');
$page = $page < 1 ? 1 : $page;
$size = $size < 1 ? 10 : $size;
$accountCode = $this->request->user['user_code'] ?? '';
try {
$whereMap = [];
$fields = [
'id',
'is_verificated as isVerificated',
'money',
'name as couponName',
'business_code as businessCode',
'end_time as endTime',
'consumer_name as consumerName',
'verificate_time as verificateTime',
'(end_time > NOW()) as sort_weight'];
$whereMap[] = ['consumer_code', '=', $accountCode];
$whereMap[] = ['business_code', '=', $businessCode];
$sortOrder = ['sort_weight' => 'desc', 'end_time' => 'asc'];
$res = CouponRepository::getInstance()->findList($whereMap, $fields, $page, $size,function ($q){
return $q->with(["couponMain","scoreModel"]);
}, $sortOrder);
$res['list'] ->each(function ($item){
//重置优惠券名称
if(isset($item->couponMain) && $item->couponMain){
$item->couponName = $item->couponMain->name;
}
});
$res['list'] = multiTwoArrayKeysExcludeFilter($res['list']->toArray(), ['sort_weight']);
return $this->json(0, 'success', $res);
} catch (RepositoryException | \Exception $e) {
return $this->json(5001, '优惠卷查询失败!');
}
}
/**
* 领取优惠券
* */
public function receiveCoupon()
{
$accountId = $this->request->user['user_id'] ?? 0;
$lat = input("lat/f",0);
$lng = input("lng/f",0);
$account = AccountRepository::getInstance()->findById($accountId, [], function ($q) {
return $q->with(['business', 'parent']);
});
if(empty($account)){
return $this->json(6001,"无效的用户");
}
if ($lat <= 0 || $lng <= 0) {
return $this->json(4001, "请授权定位");
}
$couponMainId = input("couponId/d", 0);
$couponMain = CouponMain::findOne(["id" => $couponMainId],[],function ($q){
//执行领取 开启锁
return $q->with("business")->lock(true);
});
//检查优惠券状态
$checkCouponMainReceiveStatus = CouponRepository::getInstance()->checkCouponMainReceiveStatus($couponMain);
if( $checkCouponMainReceiveStatus !== true ){
return $checkCouponMainReceiveStatus;
}
try {
//检查是否可以领取 0可领取 1已领取
AccountRepository::getInstance()->getCouponReceiveStatusText($account->user_code,$couponMain);//领取状态
}catch (RepositoryException $e){
return $this->json(4001,$e->getMessage());
}
//检查通过 执行领取
$time = time();
Db::startTrans();
try {
//写入领取记录
$data = [
"coupon_id" =>$couponMain->id,
"name" =>$couponMain->name,
"type_id" =>$couponMain->type,
"type_name" =>$couponMain->type_name,
"business_code" =>$couponMain->business_code,
"business_name" =>$couponMain->business?$couponMain->business->business_name:'',
"consumer_code" =>$account->user_code,
"consumer_name" =>$account->nick_name,
"money" => $couponMain->money,
"content" => createUuid(),//未知作用
"received_time" => date("Y-m-d H:i:s",$time),
"lat" => $lat,
"lng" => $lng,
"end_time" => date($couponMain->end_time . " 00:00:00"),
"edition" => couponMain::COMMON_ON,//版本 未知作用
"is_verificated" => couponMain::COMMON_OFF,//版本 未知作用
];
CouponRepository::getInstance()->receiveCoupon($data);
Db::commit();
return $this->json();
}catch (RepositoryException $e){
Log::error("优惠券领取失败RepositoryException:".$e->getMessage());
Db::rollback();
return $this->json(5001,"领取失败");
}catch (Exception $e){
Log::error("优惠券领取失败:".$e->getMessage());
Db::rollback();
return $this->json(5001,"领取失败");
}
}
/**
* 核验优惠券 程序----核心操作----
* */
public function verification()
{
$accountId = $this->request->user['user_id'] ?? 0;
$lat = input("lat/f",0);
$lng = input("lng/f",0);
$couponId = input("couponId/d",0);
$account = AccountRepository::getInstance()->findById($accountId, [], function ($q) {
return $q->with(['business', 'parent']);
});
$time = time();
if(empty($account)){
return $this->json(6001,"无效的用户");
}
if ($lat <= 0 || $lng <= 0) {
return $this->json(4001, "请授权定位");
}
$coupon = CouponRepository::getInstance()->findById($couponId,[],function ($q){
return $q->with(["couponMain"]);
});
if($coupon->consumer_code != $account->user_code ){
return $this->json(4001, "参数错误");
}
if(empty($coupon)){
return $this->json(4001, "优惠券不存在");
}
if($coupon->status != CouponMain::status_on){
return $this->json(4001, "优惠券已停用");
}
if($coupon->on_shelf != CouponMain::on_shelf_on){
return $this->json(4001, "优惠券下架");
}
if(strtotime($coupon->end_time) < $time){
return $this->json(4001, "优惠券已过期");
}
if(!isset($coupon->couponMain)||empty($coupon->couponMain)){
return $this->json(4001, "商家优惠券信息错误");
}
$business = BusinessRepository::getInstance()->getModel()->with(["agency"])->where(["code"=>$coupon->couponMain->business_code])->lock(true)->find();
if(empty($business)){
return $this->json(4001, "商家不存在");
}
if($business->balance < $coupon->couponMain->deduction_money){
return $this->json(4001, "商家余额不足");
}
//开始数据操作
Db::startTrans();
try {
// 1. 修改优惠券状态
$coupon->save([
"is_verificated"=>CouponModel::is_verificated_on,
"used_time"=>date("Y-m-d H:i:s" ,$time),
"verificate_time"=>date("Y-m-d H:i:s" ,$time)
]);
//可分配金额
$deductionMoney = $coupon->couponMain->deduction_money;
$agencyMoney = ($deductionMoney/100) * $coupon->couponMain->commission_agency;
$adminMoney = ($deductionMoney/100) * $coupon->couponMain->commission_admin;
$consumerMoney = ($deductionMoney/100) * $coupon->couponMain->commission_consumer;
// 2. 写入优惠券流水
$couponBillData = [
"coupon_main_id"=>$coupon->couponMain->id,
"coupon_id"=>$coupon->id,
"user_code"=>$account->user_code,
"agency_code"=>$business->agency_code,
"commission_agency"=>$coupon->couponMain->commission_agency,
"commission_admin"=>$coupon->couponMain->commission_admin,
"commission_consumer"=>$coupon->couponMain->commission_consumer,
"money"=>$coupon->couponMain->money,
"agency_money"=>$agencyMoney,
"admin_money"=>$adminMoney,
"consumer_money"=>$consumerMoney,
"lat"=>$lat,
"lng"=>$lng,
];
$couponBill = CouponBill::create($couponBillData);
// 3. 写入商家扣费记录
$deductionData = [
"money"=>$deductionMoney,
"business_code"=>$business->code,
"business_name"=>$business->business_name,
"balance"=>$business->balance - $deductionMoney,
"reason"=> sprintf("[%s]验证优惠券[%s]扣除[%s]",$account->nick_name, $coupon->couponMain->name,$deductionMoney),
"coupon_main_id"=> $coupon->couponMain->id,
"coupon_id"=> $coupon->id,
"bill_id"=> $couponBill->id,
"create_time"=> date("Y-m-d H:i:s",$time),
];
Deduction::create($deductionData);
//4. 商家扣钱
$business->save(["balance"=>$business->balance - $deductionMoney]);
//5. 渠道商加钱
if(isset($business->agency)&&$business->agency){
$business->agency->inc("balance",$agencyMoney)->update();
}
//6. 用户提现到零钱
$RedpackData =[
"mch_billno"=>createUuid(),
"openid"=>$account->open_id,
"user_code"=>$account->user_code,
"money"=>$consumerMoney*100,
];
$redpackModelData = Redpack::create($RedpackData);
$payment = WechatPay::getInstance();
$redpack = $payment->redpack;
$res = $redpackData = [
'mch_billno' => $time.randomStr(0,10),
'send_name' => '红包',
're_openid' => $redpackModelData->openid,
'total_num' => 1, //固定为1可不传
'total_amount' => $redpackModelData->money, //单位为分不小于100
'wishing' => '恭喜发财',
'client_ip' => $this->request->ip(), //可不传,不传则由 SDK 取当前客户端 IP
'act_name' => '验证优惠券得红包',
'remark' => '验证优惠券得红包',//测试备注
// ...
];
$result = $redpack->sendNormal($redpackData);
var_dump($result);
Db::rollback();
}catch (RepositoryException $e){
Db::rollback();
return $this->json(5001, "服务器错误");
}catch (\Exception $e){
echo $e->getMessage();
Db::rollback();
return $this->json(5002, "服务器错误");
}
}
/**
* 发布优惠券
* */
public function add()
{
$accountId = $this->request->user['user_id'] ?? 0;
$account = AccountRepository::getInstance()->findById($accountId, [], function ($q) {
return $q->with(['business'=>function($q){
$q->lock(true);
}, 'parent']);
});
if(empty($account)){
return $this->json(6001,"登录失效");
}
if ($account->type == Account::type_consumer) {
return $this->json(4001, "您不是商家");
}
if (!isset($account->business) || empty($account->business)) {
return $this->json(4001, "商家信息错误");
}
$data = input();
Config::load("extra/distribution_proportion","distribution_proportion");
$distributionProportion = config("distribution_proportion");
$totalC = $distributionProportion['agency'] + $distributionProportion['admin'] + $distributionProportion['consumer'];
if ($totalC != 100) {
return $this->json(5002, "系统设置分配比例总和不等于100,不能发布");
}
//验证通过 不管是商家还是工作人员 都可以发布优惠券
$couponMain = [
"name" => $data['name'] ?? '',
"business_code" => $account->business->code,
"money" => $data['money'] ?? 0,
"type" => $data['type'] ?? 0,
"count" => $data['count'] ?? 0,
"type_name" => $data['type_name'] ?? '',
"start_time" => $data['start_time'] ?? '',
"end_time" => $data['end_time'] ?? '',
"deduction_money" => $data['deduction_money'] ?? '',
"image_url" => $data['image_url'] ?? '',
"intro" => $data['intro'] ?? '',
"white_list" => $data['white_list'] ?? '',
"status" => CouponMain::status_on,
"on_shelf" => CouponMain::on_shelf_off,//默认下架 后天审核上架
"commission_agency" => $distributionProportion['agency'],
"commission_admin" => $distributionProportion['admin'],
"commission_consumer" => $distributionProportion['consumer'],
];
$usingRule = input("using_rule/a");
$validate = new CouponRelease();
if (!$validate->check($couponMain)) {
return $this->json(4001, $validate->getError());
}
$usingRuleValidate = new CouponUsingRule();
if (!$usingRuleValidate->check($usingRule)) {
return $this->json(4001, $usingRuleValidate->getError());
}
//验证通过
$couponMain['business_type'] = $account->business['type'];
$couponMain['business_name'] = $account->business['business_name'];
$couponMain['lng'] = $account->business['lng'];
$couponMain['lat'] = $account->business['lat'];
$couponMain['create_time'] = date("Y-m-d H:i:s");
//保留两位小数
$couponMain['money'] = floor($couponMain['money'] * 100) / 100;
$totalMoney = $couponMain['money'] * $couponMain['count'];
if ($account->business["balance"] < $totalMoney) {
return $this->json(4001, '商家余额不足');
}
Db::startTrans();
try {
CouponRepository::getInstance()->releaseCouponMain($couponMain, $totalMoney, $usingRule);
Db::commit();
return $this->json();
} catch (RepositoryException $e) {
Db::rollback();
return $this->json(5001, "发布失败" . $e->getMessage());
} catch (\think\Exception $e) {
Db::rollback();
return $this->json(5002, "发布失败" . $e->getMessage());
}
}
/**
* 修改优惠券
* */
public function edit()
{
$accountId = $this->request->user['user_id'] ?? 0;
$couponMainId = input("couponMainId/d");
$account = AccountRepository::getInstance()->findById($accountId, [], function ($q) {
return $q->with(['business'=>function($q){
$q->lock(true);
}, 'parent']);
});
if(empty($account)){
return $this->json(6001,"登录失效");
}
if ($account->type == Account::type_consumer) {
return $this->json(4001, "您不是商家");
}
if (!isset($account->business) || empty($account->business)) {
return $this->json(4001, "商家信息错误");
}
$couponMain = CouponMain::findById($couponMainId,[],function ($q){
return $q->with(["usingRule"]);
});
if (empty($couponMain)) {
return $this->json(4001, "优惠券不存在");
}
if (!isset($couponMain->usingRule)||empty($couponMain->usingRule)) {
return $this->json(4001, "优惠券信息错误");
}
$data = input();
//验证通过 不管是商家还是工作人员 都可以修改优惠券 只能修改指定字段
$couponMainData = [
"name" => $data['name'] ?? '',
"type" => $data['type'] ?? 0,
"type_name" => $data['type_name'] ?? '',
"start_time" => $data['start_time'] ?? '',
"end_time" => $data['end_time'] ?? '',
"image_url" => $data['image_url'] ?? '',
"intro" => $data['intro'] ?? '',
"white_list" => $data['white_list'] ?? '',
];
$usingRule = input("using_rule/a");
$validate = new CouponRelease();
if (!$validate->scene("api_edit")->check($couponMainData)) {
return $this->json(4001, $validate->getError());
}
$usingRuleValidate = new CouponUsingRule();
if (!$usingRuleValidate->check($usingRule)) {
return $this->json(4001, $usingRuleValidate->getError());
}
//验证通过
Db::startTrans();
try {
$couponMain->save($couponMainData);
$couponMain->usingRule->save($usingRule);
Db::commit();
return $this->json();
} catch (RepositoryException $e) {
Db::rollback();
return $this->json(5001, "修改失败失败" );
} catch (\think\Exception $e) {
Db::rollback();
return $this->json(5002, "修改失败500" );
}
}
/**
* 商家管理优惠券
* */
public function getPageList()
{
$accountId = $this->request->user['user_id'] ?? 0;
$account = AccountRepository::getInstance()->findById($accountId, [], function ($q) {
return $q->with(['business', 'parent']);
});
if(empty($account)){
return $this->json(6001,"登录失效");
}
if ($account->type == Account::type_consumer) {
return $this->json(4001, "您不是商家");
}
if (!isset($account->business) || empty($account->business)) {
return $this->json(4001, "商家信息错误");
}
$page = $this->request->param('page/d', 1);
$size = $this->request->param('rows/d', 10);
$page = $page < 1 ? 1 : $page;
$size = $size < 1 ? 10 : $size;
$keyword = $this->request->param('key/s',"");
$businessCode = $account->business_code;
try {
$whereMap = [];
$sortOrder = ['sort' => 'desc'];
$whereMap[] = ["business_code" ,"=", $businessCode ];
if(!empty($keyword)){
$whereMap[] = ["name" ,"like", "%{$keyword}%" ];
}
$res = CouponRepository::getInstance(new CouponMain())->findList($whereMap, [], $page, $size,function ($q){
return $q->with(["usingRule","couponType"]);
}, $sortOrder);
$time = time();
$res['list'] ->each(function ($item) use($time){
//已使用张数
$item->usingCount = CouponRepository::getInstance()->getCouponMainUsingCount($item->id);
if(strtotime($item->start_time) <= $time && strtotime($item->end_time) >= $time){
$item->conduct = true;
}else{
$item->conduct = false;
}
});
return $this->json(0, 'success', $res["list"]);
} catch (RepositoryException | \Exception $e) {
echo $e->getMessage();
return $this->json(5001, '优惠卷查询失败!');
}
}
/**
* 优惠券的领取 使用记录列表
* */
public function getShopCouponList()
{
$accountId = $this->request->user['user_id'] ?? 0;
$account = AccountRepository::getInstance()->findById($accountId, [], function ($q) {
return $q->with(['business', 'parent']);
});
if(empty($account)){
return $this->json(6001,"登录失效");
}
if ($account->type == Account::type_consumer) {
return $this->json(4001, "您不是商家");
}
if (!isset($account->business) || empty($account->business)) {
return $this->json(4001, "商家信息错误");
}
$couponMainId = input("couponId/d");
$couponMain = CouponMain::findById($couponMainId);
if(empty($couponMain)){
return $this->json(4001, "优惠券不存在");
}
if($couponMain->business_code != $account->business->code){
return $this->json(4001, "优惠券参数信息错误");
}
$page = $this->request->param('page/d', 1);
$size = $this->request->param('rows/d', 10);
$type = $this->request->param('type/s', 10);
$page = $page < 1 ? 1 : $page;
$size = $size < 1 ? 10 : $size;
$sortOrder = ["id"=>"desc"];
$whereMap = [
["coupon_id","=",$couponMainId]
];
switch ($type) {
case 'all':
// 全部持有优惠券
$sortOrder = [ 'end_time' => 'asc'];
break;
case 'notUsed':
// 未使用(包含已过期)
$whereMap[] = ['is_verificated', '=', self::BOOL_FALSE];
$sortOrder = ['end_time' => 'asc'];
break;
case 'normal':
// 未使用且未过期
$whereMap[] = ['is_verificated', '=', self::BOOL_FALSE];
$whereMap[] = ['end_time', '< TIME', date('Y-m-d H:i:s')];
break;
case 'used':
// 已使用
$whereMap[] = ['is_verificated', '=', self::BOOL_TRUE];
$sortOrder = ['verificate_time' => 'desc'];
break;
}
$field = ["is_verificated","received_time","verificate_time","consumer_code"];
$data = CouponRepository::getInstance()->findList($whereMap,$field,$page,$size,function($q){
return $q->withjoin(["account"=>function($q){
$q->field(["nick_name","avatar_url","gender","user_code"]);
}]);
},$sortOrder);
//所有
$data["allNum"] = CouponRepository::getInstance()->getModel()->where(["coupon_id"=>$couponMainId])->count();
//未使用
$data["unUsedNum"] = CouponRepository::getInstance()->getModel()->where(['is_verificated' => self::BOOL_FALSE,"coupon_id"=>$couponMainId])->count();
//已使用
$data["usedNum"] = CouponRepository::getInstance()->getModel()->where(['is_verificated' => self::BOOL_TRUE ,"coupon_id"=>$couponMainId])->count();
return $this->json(0,"success",$data);
}
/**
* 获取优惠券详情
* */
public function getCouponMainInfo()
{
$couponMainId = input("couponMainId/d");
$couponMain = CouponMain::findById($couponMainId,[],function ($q){
return $q->with("usingRule");
});
if(empty($couponMain)){
return $this->json(4001,"优惠券不存在");
}
return $this->json(0,"success",$couponMain->toArray());
}
}