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

231 lines
6.7 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\Services;
use App\Exceptions\BizException;
use App\Models\Activity;
use App\Models\Coupon;
use App\Models\ProductPart;
use App\Models\ReceivePartCouponLog;
use App\Models\User;
use App\Models\UserCoupon;
use Illuminate\Database\QueryException;
class CouponService
{
/**
* 根据SKU商品获取可用优惠券
*
* @param User $user
* @param array $products 至少包含以下内容
* [
* ['sku' => 商品SKU, 'quantity' => 10]
* ]
* @return array
*/
public function getAvailableCoupons(User $user, array $products): array
{
$coupons = $user->coupons()->onlyAvailable()->get();
$coupons->load(['ranges' => function ($query) {
$query->isEnable();
}]);
$availableCoupons = [];
foreach ($coupons as $coupon) {
// 是否满足券使用规则
$passes = false;
// 可用优惠券的商品的总额
$amount = 0;
foreach ($products as $product) {
$sku = $product['sku'];
if ($coupon->isSupport($sku)) {
$passes = true;
$amount += $sku->getRealPrice($user) * $product['quantity'];
}
}
if ($passes && $amount >= $coupon->coupon_threshold) {
$availableCoupons[] = $coupon;
}
}
return $availableCoupons;
}
/**
* 根据分区,领取优惠券
*/
public function receivePartCoupon(ProductPart $part, User $user)
{
//如果分区不显示,直接退出;
if (!$part->is_show) {
return;
}
//如果用户已领取过该分区设置的券,直接退出;
if (ReceivePartCouponLog::where(['user_id'=>$user->id, 'part_id'=>$part->id])->exists()) {
return;
}
//取出需要发放的券
$coupons = Coupon::whereIn('id', $part->coupons->pluck('coupon_id')->toArray())->get();
$coupons = $coupons->keyBy('id');
$someCoupons = [];
foreach ($part->coupons as $coupon) {
$someCoupons[] = [
'coupon'=>$coupons[$coupon->coupon_id],
'num'=>$coupon->num,
];
}
$this->receiveSomeCoupons($user, $someCoupons);
ReceivePartCouponLog::create(['user_id'=>$user->id, 'part_id'=>$part->id]);
}
/**
* 根据活动领取优惠券
*
* @return void
*/
public function receiveActivityCoupons(Activity $activity, User $user)
{
$someCoupons = [];
foreach ($activity->coupons as $coupon) {
$someCoupons[] = [
'coupon'=>$coupon,
'num'=>$coupon->pivot->qty,
];
}
$this->receiveSomeCoupons($user, $someCoupons, $activity->id);
}
/**
* 领取一批券
*
* @param User $user
* @param array $coupons
* @return void
*/
protected function receiveSomeCoupons(User $user, array $coupons, ?int $activityId = null)
{
$userCoupons = [];
foreach ($coupons as $key=> $coupon) {
//更新对应券发送量,余量;
try {
$canSent = true;
if ($coupon['coupon']->limit > 0) {//限量才减少余量
$coupon['coupon']->decrement('stock', $coupon['num']);
}
} catch (QueryException $e) {
if (strpos($e->getMessage(), 'Numeric value out of range') !== false) {
$canSent = false;
} else {
throw new $e();
}
}
if ($canSent) {
for ($i = 0; $i < $coupon['num']; $i++) {
$userCoupons[] = self::createUserCouponData($user->id, $coupon['coupon'], $activityId ?? null);
}
$coupon['coupon']->increment('sent', $coupon['num']);
}
}
UserCoupon::insert($userCoupons);
}
/**
* todo-领取指定券
*
* @param User $user
* @param Coupon $coupon
* @param int $num
* @return void
*/
public function receiveCoupon(User $user, Coupon $coupon, int $num = 1)
{
return;
}
/**
* 创建用户券数据
*
* @return array
*/
public static function createUserCouponData(int $userId, Coupon $coupon, ?int $activityId = null)
{
//如果userId小于等于0直接退出
if ($userId <= 0) {
return [];
}
if ($coupon->use_start_at && $coupon->use_end_at) {
$useStartAt = $coupon->use_start_at;
$useEndAt = $coupon->use_end_at;
} else {
$useStartAt = now();
$useEndAt = now()->addDays($coupon->use_day);
}
return [
'user_id' => $userId,
'coupon_id' => $coupon->id,
'coupon_name' => $coupon->name,
'coupon_type' => $coupon->type,
'coupon_amount' => (int) bcmul($coupon->amount, 100),
'coupon_threshold'=> (int) bcmul($coupon->threshold, 100),
'use_start_at' => $useStartAt,
'use_end_at' => $useEndAt,
'created_at' => now(),
'updated_at' => now(),
'activity_id' => $activityId ?? null,
];
}
/**
* 送优惠券
*
* @param \App\Models\User $user
* @param \App\Models\Coupon $coupon
* @param int $num
* @return void
*/
public function sendCoupon(User $user, Coupon $coupon, int $num = 1)
{
// 如果优惠券数量有限制,需扣除优惠券库存
if ($coupon->limit > 0) {
if ($coupon->stock < $num) {
throw new BizException('优惠券数量不足');
}
$coupon->decrement('stock', $num);
}
$coupon->increment('sent', $num);
$tz = now();
$coupons = [];
for ($i = 0; $i < $num; $i++) {
$coupons[] = [
'user_id' => $user->id,
'coupon_id' => $coupon->id,
'coupon_name' => $coupon->name,
'coupon_type' => $coupon->type,
'coupon_amount' => (int) bcmul($coupon->amount, 100),
'coupon_threshold'=> (int) bcmul($coupon->threshold, 100),
'use_start_at' => $coupon->use_start_at ?: $tz,
'use_end_at' => $coupon->use_end_at ?: $tz->copy()->addDays($coupon->use_day),
'activity_id' => null,
'created_at' => $tz,
'updated_at' => $tz,
];
}
UserCoupon::insert($coupons);
}
}