|
@@ -11,7 +11,8 @@ use app\common\model\Order;
|
|
|
use app\common\Enum\LotteryEnum;
|
|
|
use think\Exception;
|
|
|
use think\Db;
|
|
|
-
|
|
|
+use app\common\exception\BusinessException;
|
|
|
+use app\common\Enum\OrderEnum;
|
|
|
/**
|
|
|
* 抽奖机会服务类
|
|
|
* 处理用户获得抽奖机会的逻辑
|
|
@@ -33,8 +34,51 @@ class LotteryChanceService
|
|
|
const MAX_BATCH_SIZE = 1000;
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
+ * 订单完成后检查并分发抽奖机会(单个活动版本)
|
|
|
+ * 查询一个正在进行的活动,返回单个结果
|
|
|
+ *
|
|
|
+ * @param array $orderInfo 订单信息 ['id', 'total_amount', 'goods' => [['goods_id']]]
|
|
|
+ * @param int $userId 用户ID
|
|
|
+ * @return array|null 获得的抽奖机会信息,如果没有则返回null
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public static function checkAndGrantChanceForOrderOne($orderInfo, $userId)
|
|
|
+ {
|
|
|
+ if (empty($orderInfo) || empty($userId)) {
|
|
|
+ throw new BusinessException('订单信息或用户ID不能为空');
|
|
|
+ }
|
|
|
+
|
|
|
+ // try {
|
|
|
+ // 获取当前正在进行的单个抽奖活动
|
|
|
+ $activity = static::getCurrentRunningActivity();
|
|
|
+
|
|
|
+ // 如果没有正在进行的活动,返回null
|
|
|
+ if (!$activity) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理当前活动
|
|
|
+ $chances = static::processActivityForOrder($activity, $orderInfo, $userId);
|
|
|
+
|
|
|
+ if ($chances > 0) {
|
|
|
+ return [
|
|
|
+ 'lottery_id' => $activity->id,
|
|
|
+ 'lottery_name' => $activity->name,
|
|
|
+ 'chances' => $chances,
|
|
|
+ 'granted_time' => time()
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+
|
|
|
+ // } catch (Exception $e) {
|
|
|
+ // trace("订单抽奖机会分发失败 - 用户ID: {$userId}, 错误: " . $e->getMessage(), 'error');
|
|
|
+ // throw new BusinessException('订单抽奖机会分发失败');
|
|
|
+ // }
|
|
|
+ }
|
|
|
/**
|
|
|
- * 订单完成后检查并分发抽奖机会 *
|
|
|
+ * 订单完成后检查并分发抽奖机会 多个的
|
|
|
* @param array $orderInfo 订单信息 ['id', 'total_amount', 'goods' => [['goods_id']]]
|
|
|
* @param int $userId 用户ID
|
|
|
* @return array 获得的抽奖机会信息
|
|
@@ -43,13 +87,13 @@ class LotteryChanceService
|
|
|
public static function checkAndGrantChanceForOrder($orderInfo, $userId)
|
|
|
{
|
|
|
if (empty($orderInfo) || empty($userId)) {
|
|
|
- throw new Exception('订单信息或用户ID不能为空');
|
|
|
+ throw new BusinessException('订单信息或用户ID不能为空');
|
|
|
}
|
|
|
|
|
|
$grantedChances = [];
|
|
|
|
|
|
try {
|
|
|
- // 获取所有正在进行的抽奖活动
|
|
|
+ // 获取所有正在进行的抽奖活动 一段时间 有且只有一个抽奖活动
|
|
|
$activities = LotteryService::getRunningActivities();
|
|
|
|
|
|
foreach ($activities as $activity) {
|
|
@@ -77,7 +121,51 @@ class LotteryChanceService
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 充值完成后检查并分发抽奖机会
|
|
|
+ * 充值完成后检查并分发抽奖机会(单个活动版本)
|
|
|
+ * 查询一个正在进行的活动,返回单个结果
|
|
|
+ *
|
|
|
+ * @param array $rechargeInfo 充值信息 ['amount', 'type' => 'recharge']
|
|
|
+ * @param int $userId 用户ID
|
|
|
+ * @return array|null 获得的抽奖机会信息,如果没有则返回null
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public static function checkAndGrantChanceForRechargeOne($rechargeInfo, $userId)
|
|
|
+ {
|
|
|
+ if (empty($rechargeInfo) || empty($userId)) {
|
|
|
+ throw new Exception('充值信息或用户ID不能为空');
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取当前正在进行的单个抽奖活动
|
|
|
+ $activity = static::getCurrentRunningActivity();
|
|
|
+
|
|
|
+ // 如果没有正在进行的活动,返回null
|
|
|
+ if (!$activity) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理当前活动
|
|
|
+ $chances = static::processActivityForRecharge($activity, $rechargeInfo, $userId);
|
|
|
+
|
|
|
+ if ($chances > 0) {
|
|
|
+ return [
|
|
|
+ 'activity_id' => $activity->id,
|
|
|
+ 'activity_name' => $activity->name,
|
|
|
+ 'chances' => $chances,
|
|
|
+ 'granted_time' => time()
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+
|
|
|
+ } catch (Exception $e) {
|
|
|
+ trace("充值抽奖机会分发失败 - 用户ID: {$userId}, 错误: " . $e->getMessage(), 'error');
|
|
|
+ throw $e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 充值完成后检查并分发抽奖机会(多个活动版本)
|
|
|
*
|
|
|
* @param array $rechargeInfo 充值信息 ['amount', 'type' => 'recharge']
|
|
|
* @param int $userId 用户ID
|
|
@@ -207,11 +295,19 @@ class LotteryChanceService
|
|
|
return $result;
|
|
|
}
|
|
|
|
|
|
+ // ============ 活动查询方法 ============
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ /**
|
|
|
+ * 获取当前正在进行的单个抽奖活动
|
|
|
+ * 假设同一时间段只有一个活动在进行
|
|
|
+ *
|
|
|
+ * @return LotteryActivity|null
|
|
|
+ */
|
|
|
+ public static function getCurrentRunningActivity()
|
|
|
+ {
|
|
|
+ $activities = LotteryService::getRunningActivities();
|
|
|
+ return empty($activities) ? null : $activities[0];
|
|
|
+ }
|
|
|
|
|
|
// ============ 私有处理方法 ============
|
|
|
|
|
@@ -234,7 +330,6 @@ class LotteryChanceService
|
|
|
$conditions = static::getValidConditions($activity->id);
|
|
|
$totalChances = 0;
|
|
|
$chanceDetails = [];
|
|
|
-
|
|
|
foreach ($conditions as $condition) {
|
|
|
// 跳过充值条件
|
|
|
if ($condition->type == LotteryEnum::CONDITION_TYPE_RECHARGE_AMOUNT) {
|
|
@@ -248,7 +343,10 @@ class LotteryChanceService
|
|
|
$chanceDetails[] = $result['detail'];
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+ echo '<pre>';
|
|
|
+ print_r($chanceDetails);
|
|
|
+ echo '</pre>';
|
|
|
+ die();
|
|
|
// 如果获得了抽奖机会,记录到数据库
|
|
|
if ($totalChances > 0) {
|
|
|
// 为每个条件分别记录
|
|
@@ -262,6 +360,7 @@ class LotteryChanceService
|
|
|
]);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
|
|
|
return $totalChances;
|
|
|
}
|
|
@@ -285,7 +384,7 @@ class LotteryChanceService
|
|
|
$conditions = static::getValidConditions($activity->id);
|
|
|
$totalChances = 0;
|
|
|
$chanceDetails = [];
|
|
|
-
|
|
|
+
|
|
|
foreach ($conditions as $condition) {
|
|
|
// 只处理充值条件
|
|
|
if ($condition->type != LotteryEnum::CONDITION_TYPE_RECHARGE_AMOUNT) {
|
|
@@ -347,7 +446,8 @@ class LotteryChanceService
|
|
|
|
|
|
// 如果可重复获得,根据金额倍数计算次数
|
|
|
if (static::canRepeat($condition)) {
|
|
|
- $multiple = floor($orderInfo['total_amount'] / $condition->condition_value);
|
|
|
+ // 使用bcdiv进行精确的金额除法运算,然后取整
|
|
|
+ $multiple = floor(bcdiv($orderInfo['total_amount'], $condition->condition_value, 2));
|
|
|
$chances *= $multiple;
|
|
|
}
|
|
|
}
|
|
@@ -391,7 +491,8 @@ class LotteryChanceService
|
|
|
|
|
|
// 如果可重复获得,根据金额倍数计算次数
|
|
|
if (static::canRepeat($condition)) {
|
|
|
- $multiple = floor($rechargeInfo['amount'] / $condition->condition_value);
|
|
|
+ // 使用bcdiv进行精确的金额除法运算,然后取整
|
|
|
+ $multiple = floor(bcdiv($rechargeInfo['amount'], $condition->condition_value, 2));
|
|
|
$chances *= $multiple;
|
|
|
}
|
|
|
}
|
|
@@ -545,7 +646,9 @@ class LotteryChanceService
|
|
|
public static function validateOrderAmountCondition(LotteryCondition $condition, $orderInfo)
|
|
|
{
|
|
|
$orderAmount = $orderInfo['total_amount'] ?? 0;
|
|
|
- return $orderAmount >= $condition->condition_value;
|
|
|
+
|
|
|
+ // 使用bccomp进行精确的金额比较,返回值:-1(小于)、0(等于)、1(大于)
|
|
|
+ return bccomp($orderAmount, $condition->condition_value, 2) >= 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -562,7 +665,8 @@ class LotteryChanceService
|
|
|
}
|
|
|
|
|
|
$rechargeAmount = $orderInfo['amount'] ?? 0;
|
|
|
- return $rechargeAmount >= $condition->condition_value;
|
|
|
+ // 使用bccomp进行精确的金额比较
|
|
|
+ return bccomp($rechargeAmount, $condition->condition_value, 2) >= 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -582,12 +686,13 @@ class LotteryChanceService
|
|
|
|
|
|
// 计算活动期间用户累计消费
|
|
|
$totalAmount = Order::where('user_id', $userId)
|
|
|
- ->where('status', 'paid')
|
|
|
- ->where('createtime', '>=', $activity->start_time)
|
|
|
- ->where('createtime', '<=', $activity->end_time)
|
|
|
- ->sum('total_amount');
|
|
|
+ ->where('order_status', OrderEnum::STATUS_PAY)
|
|
|
+ ->where('pay_time', '>=', $activity->start_time)
|
|
|
+ ->where('pay_time', '<=', $activity->end_time)
|
|
|
+ ->sum('amount');
|
|
|
|
|
|
- return $totalAmount >= $condition->condition_value;
|
|
|
+ // 使用bccomp进行精确的金额比较
|
|
|
+ return bccomp($totalAmount, $condition->condition_value, 2) >= 0;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -906,7 +1011,7 @@ class LotteryChanceService
|
|
|
return $userChance->save();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
// ============ 统计和查询方法 ============
|
|
|
|
|
|
/**
|