6
0
Fork 0
jiqu-library-server/app/Services/DrawActivityService.php

133 lines
3.7 KiB
PHP

<?php
namespace App\Services;
use App\Enums\DrawLogStatus;
use App\Enums\DrawPrizeType;
use App\Exceptions\BizException;
use App\Models\Coupon;
use App\Models\DrawActivity;
use App\Models\DrawActivityPrize;
use App\Models\DrawLog;
use App\Models\User;
use Illuminate\Support\Facades\DB;
class DrawActivityService
{
/**
* 活动抽奖
*
* @param \App\Models\DrawActivity $drawActivity
* @param \App\Models\User $user
* @return \App\Models\DrawLog
*/
public function draw(DrawActivity $drawActivity, User $user): DrawLog
{
if (! $drawActivity->isPublished()) {
throw new BizException('抽奖活动未发布');
}
if ($drawActivity->isUnstart()) {
throw new BizException('抽奖活动未开始');
}
if ($drawActivity->isClosed()) {
throw new BizException('抽奖活动已结束');
}
(new DrawTicketService())->change($user, $drawActivity, -1, '活动抽奖');
$prize = $this->getDrawActivityPrize($drawActivity);
// 如果限制了奖品数量,则需扣除奖品库存
if ($prize->limited) {
$prize->update([
'stock' => DB::raw('stock-1'),
'winnings' => DB::raw('winnings+1'),
]);
} else {
$prize->increment('winnings', 1);
}
$drawLog = DrawLog::create([
'user_id' => $user->id,
'draw_activity_id' => $drawActivity->id,
'draw_activity_prize_id' => $prize->id,
'status' => match ($prize->type) {
DrawPrizeType::None => DrawLogStatus::Completed,
default => DrawLogStatus::Pending,
},
]);
$drawLog->setRelation('prize', $prize);
// 自动发放奖品
if ($prize->auto_send) {
// 优惠券
$this->sendPrize($drawLog);
}
return $drawLog;
}
/**
* @param \App\Models\DrawActivity $drawActivity
* @return \App\Models\DrawActivityPrize
*/
protected function getDrawActivityPrize(DrawActivity $drawActivity): DrawActivityPrize
{
$drawActivityPrizes = $drawActivity->prizes()->get();
// 过滤权重为0或库存不足的奖品
$prizes = $drawActivityPrizes->filter(function ($item) {
if ($item->weight === 0 || ($item->limited && $item->stock === 0)) {
return false;
}
return true;
});
$max = $prizes->sum('weight');
if ($max > 0) {
$rand = mt_rand($min = 1, $max);
foreach ($prizes as $prize) {
if ($rand <= $prize->weight + $min) {
return $prize;
}
$min += $prize->weight;
}
}
throw new BizException('抽奖活动异常');
}
/**
* 发放活动奖品
*/
public function sendPrize(DrawLog $drawLog)
{
if (!$drawLog->isPending()) {
throw new BizException("发放奖品失败: 奖品已发放");
}
// 发放奖品
$prize = $drawLog->prize;
// 发放优惠券
if ($prize->type == DrawPrizeType::Coupon) {
if (!$prize->price_type_id) {
throw new BizException("发放奖品失败: 奖品(".$prize->name.")未关联优惠券");
}
$coupon = Coupon::find($prize->price_type_id);
if (!$coupon) {
throw new BizException("发放奖品失败: 奖品(".$prize->name.")关联优惠券不存在");
}
(new CouponService())->sendCoupon($drawLog->user, $coupon, 1);
}
$drawLog->update([
'status' => DrawLogStatus::Completed,
]);
}
}