ActivityBudgetService.php 1.1 KB

1234567891011121314151617181920212223242526272829303132
  1. <?php
  2. namespace App\Services;
  3. use App\Models\ActivityReward;
  4. use Illuminate\Support\Facades\DB;
  5. /** Preserve the monetary budget behavior for activities created before quotas. */
  6. class ActivityBudgetService
  7. {
  8. public static function award(ActivityReward $activity, $amount, callable $grant): bool
  9. {
  10. if (!is_numeric($amount) || !preg_match('/^\d{1,12}(\.\d{1,2})?$/', (string)$amount)
  11. || bccomp((string)$amount, '0', 2) <= 0) {
  12. return false;
  13. }
  14. return DB::transaction(function () use ($activity, $amount, $grant) {
  15. $locked = ActivityReward::where('id', $activity->id)->lockForUpdate()->first();
  16. if (!$locked) return false;
  17. if ((int)$locked->type === 2) {
  18. $grant();
  19. return true;
  20. }
  21. $used = bcadd((string)($locked->budget_used ?? '0'), (string)$amount, 2);
  22. if ($locked->budget !== null && bccomp($used, (string)$locked->budget, 2) > 0) return false;
  23. $grant();
  24. $locked->budget_used = $used;
  25. $locked->save();
  26. return true;
  27. });
  28. }
  29. }