ActivityUserService.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. <?php
  2. namespace App\Services;
  3. use App\Constants\HttpStatus;
  4. use App\Constants\System;
  5. use App\Constants\Util;
  6. use App\Models\ActivityReward;
  7. use App\Models\ActivityUser;
  8. use App\Models\Wallet as WalletModel;
  9. use Exception;
  10. use Illuminate\Support\Facades\DB;
  11. use Illuminate\Database\Eloquent\Builder;
  12. class ActivityUserService extends BaseService
  13. {
  14. public static string $MODEL = ActivityUser::class;
  15. public static function getWhere(array $search = []): array
  16. {
  17. $where = [];
  18. if (isset($search['id']) && !empty($search['id'])) {
  19. $where[] = ['id', '=', $search['id']];
  20. }
  21. if (isset($search['title']) && !empty($search['title'])) {
  22. $where[] = ['title', 'like', "%{$search['title']}%"];
  23. }
  24. if (isset($search['status']) && $search['status'] != '') {
  25. $where[] = ['status', '=', $search['status']];
  26. }
  27. if (isset($search['member_id']) && !empty($search['member_id'])) {
  28. $where[] = ['member_id', '=', $search['member_id']];
  29. }
  30. return $where;
  31. }
  32. public static function findOne(array $search)
  33. {
  34. return static::$MODEL::where(static::getWhere($search))->first();
  35. }
  36. /**
  37. * Update or create
  38. * @param array $params
  39. * @return bool
  40. * @throws Exception
  41. */
  42. public static function submit(array $params = []): bool
  43. {
  44. if (isset($params['start_time']))
  45. $params['start_time'] = strtotime($params['start_time'] . " 00:00:00");
  46. if (isset($params['end_time']))
  47. $params['end_time'] = strtotime($params['end_time'] . " 23:59:59");
  48. if (isset($params['detail_image']))
  49. $params['detail_image'] = Util::replacePartInUrl($params['detail_image']);
  50. if (!empty($params['id'])) {
  51. $info = static::findOne(['id' => $params['id']]);
  52. if (!$info) throw new Exception("操作失败", HttpStatus::CUSTOM_ERROR);
  53. $info->update($params);
  54. } else {
  55. $info = static::$MODEL::create($params);
  56. }
  57. return true;
  58. }
  59. public static function updateBettingAmount($memberId, $amount)
  60. {
  61. $activityUser = static::findOne([
  62. 'member_id' => $memberId,
  63. 'status' => static::$MODEL::STATUS_IN_PROGRESS
  64. ]);
  65. if ($activityUser) {
  66. $activityUser->increment('effective_betting_amount', $amount);
  67. if ($activityUser->effective_betting_amount >= $activityUser->betting_amount) {
  68. $activityUser->status = static::$MODEL::STATUS_COMPLETE;
  69. $activityUser->finish_time = time();
  70. }
  71. $activityUser->save();
  72. }
  73. }
  74. public static function finish($id)
  75. {
  76. $activityUser = static::findOne(['id' => $id]);
  77. $activityUser->status = static::$MODEL::STATUS_COMPLETE;
  78. $activityUser->finish_time = time();
  79. $activityUser->save();
  80. }
  81. /**
  82. * @throws Exception
  83. */
  84. public static function gift($id, $amount, $bettingAmount): void
  85. {
  86. $notification = DB::transaction(function () use ($id, $amount, $bettingAmount) {
  87. $application = ActivityUser::where('id', $id)->first();
  88. if (!$application) throw new Exception('活动不存在', HttpStatus::CUSTOM_ERROR);
  89. // Wallet first, matching deposit and settlement transactions.
  90. $wallet = WalletModel::where('member_id', $application->member_id)->lockForUpdate()->first();
  91. if (!$wallet) throw new Exception('账户钱包不存在', HttpStatus::CUSTOM_ERROR);
  92. $activityUser = ActivityUser::where('id', $id)->lockForUpdate()->first();
  93. if (!$activityUser) throw new Exception('活动不存在', HttpStatus::CUSTOM_ERROR);
  94. if ($activityUser->status == static::$MODEL::STATUS_IN_PROGRESS) throw new Exception('充值失败:活动进行中', HttpStatus::CUSTOM_ERROR);
  95. if ($activityUser->status == static::$MODEL::STATUS_COMPLETE) throw new Exception("充值失败:活动已完成", HttpStatus::CUSTOM_ERROR);
  96. if ($activityUser->status != static::$MODEL::STATUS_APPLY) throw new Exception('充值失败:状态异常', HttpStatus::CUSTOM_ERROR);
  97. $activity = ActivityReward::where('id', $activityUser->activity_id)->first();
  98. if (!$activity) throw new Exception('活动不存在', HttpStatus::CUSTOM_ERROR);
  99. $eligibility = ActivityEligibilityService::evaluate($activity, ActivityEligibilityService::memberContext($activityUser->member_id));
  100. if (!$eligibility['is_eligible']) throw new Exception($eligibility['ineligible_reason'], HttpStatus::CUSTOM_ERROR);
  101. $res = null;
  102. $granted = ActivityQuotaService::award($activity, $activityUser->member_id, $amount, function () use ($activityUser, $wallet, $amount, $bettingAmount, &$res) {
  103. $activityUser->status = static::$MODEL::STATUS_IN_PROGRESS;
  104. $activityUser->betting_amount = $bettingAmount;
  105. $activityUser->gift_amount = $amount;
  106. $activityUser->effective_betting_amount = 0;
  107. $activityUser->save();
  108. $memberId = $activityUser->member_id;
  109. $before = (string)$wallet->available_balance;
  110. $wallet->available_balance = bcadd($before, (string)$amount, 2);
  111. $wallet->save();
  112. $res = ['before_balance' => $before, 'after_balance' => $wallet->available_balance];
  113. BalanceLogService::addLog($memberId, $amount, $res['before_balance'], $res['after_balance'], "优惠活动", $activityUser->id, "$activityUser->title; 赠送:$activityUser->gift_amount; 打码量:$activityUser->betting_amount");
  114. });
  115. if (!$granted) throw new Exception($activity->quota_enabled
  116. ? '活动获奖份数已用完,已停止新用户发奖' : '活动预算不足,已停止发奖', HttpStatus::CUSTOM_ERROR);
  117. $availableBalance = floatval($res['after_balance']);
  118. // 去除多余0后,再用 sprintf 补足两位
  119. $availableBalance = sprintf('%.2f', $availableBalance);
  120. $text = "余额变动通知\n";
  121. $text .= "变动金额:" . ($amount > 0 ? '+' : '') . "{$amount}\n";
  122. $text .= "总余额为:{$availableBalance}\n";
  123. $text .= "说明:优惠活动赠送";
  124. return ['member_id' => $activityUser->member_id, 'text' => $text];
  125. });
  126. TopUpService::notifyTransferSuccess($notification['member_id'], $notification['text']);
  127. }
  128. }