HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/hi.naniguide.com/app/Services/Billing/UsageService.php
<?php

namespace App\Services\Billing;

use App\Models\CampaignRecipient;
use App\Models\Customer;
use App\Models\UsageLog;
use Carbon\Carbon;
use Illuminate\Database\QueryException;

class UsageService
{
    public function log(Customer $customer, string $metric, int $amount = 1, array $context = []): UsageLog
    {
        [$periodStart, $periodEnd] = $this->currentPeriodBounds();

        $attributes = [
            'customer_id' => $customer->id,
            'metric' => $metric,
            'period_start' => $periodStart,
            'period_end' => $periodEnd,
        ];

        try {
            $log = UsageLog::firstOrCreate($attributes, ['amount' => 0]);
        } catch (QueryException $e) {
            if (!$this->isDuplicateUsageLogException($e)) {
                throw $e;
            }

            $log = UsageLog::query()->where($attributes)->first();

            if (!$log instanceof UsageLog) {
                throw $e;
            }
        }

        $log->increment('amount', $amount);
        $log->update(['context' => array_merge($log->context ?? [], $context)]);

        return $log->fresh();
    }

    public function getUsage(Customer $customer): array
    {
        [$periodStart, $periodEnd] = $this->currentPeriodBounds();

        $usage = UsageLog::where('customer_id', $customer->id)
            ->where('period_start', $periodStart)
            ->where('period_end', $periodEnd)
            ->get()
            ->mapWithKeys(fn ($log) => [$log->metric => $log->amount])
            ->toArray();

        $emailsSentThisMonth = CampaignRecipient::query()
            ->whereNotNull('sent_at')
            ->whereBetween('sent_at', [
                Carbon::parse($periodStart)->startOfDay(),
                Carbon::parse($periodEnd)->endOfDay(),
            ])
            ->whereIn('status', ['sent', 'opened', 'clicked'])
            ->whereHas('campaign', function ($q) use ($customer) {
                $q->where('customer_id', $customer->id);
            })
            ->count();

        $usage['emails_sent_this_month'] = max(
            (int) ($usage['emails_sent_this_month'] ?? 0),
            $emailsSentThisMonth
        );

        return $usage;
    }

    private function currentPeriodBounds(): array
    {
        $now = Carbon::now();
        $periodStart = $now->copy()->startOfMonth()->toDateString();
        $periodEnd = $now->copy()->endOfMonth()->toDateString();

        return [$periodStart, $periodEnd];
    }

    private function isDuplicateUsageLogException(QueryException $e): bool
    {
        $sqlState = (string) ($e->errorInfo[0] ?? '');
        $driverCode = (string) ($e->errorInfo[1] ?? '');
        $message = $e->getMessage();

        return $sqlState === '23000'
            && (
                str_contains($message, 'UNIQUE constraint failed: usage_logs')
                || str_contains($message, 'Duplicate entry')
                || str_contains($driverCode, '1062')
                || str_contains($driverCode, '19')
            );
    }
}