Files
fotospiel-app/app/Services/AiEditing/AiUsageLedgerService.php
Codex Agent 36bed12ff9
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled
feat: implement AI styling foundation and billing scope rework
2026-02-06 20:01:58 +01:00

68 lines
2.5 KiB
PHP

<?php
namespace App\Services\AiEditing;
use App\Models\AiEditRequest;
use App\Models\AiUsageLedger;
use App\Models\Event;
use Illuminate\Support\Facades\DB;
class AiUsageLedgerService
{
public function __construct(private readonly AiStylingEntitlementService $entitlements) {}
/**
* @param array<string, mixed> $metadata
*/
public function recordDebitForRequest(AiEditRequest $request, ?float $costUsd = null, array $metadata = []): AiUsageLedger
{
return DB::transaction(function () use ($request, $costUsd, $metadata): AiUsageLedger {
$lockedRequest = AiEditRequest::query()
->whereKey($request->id)
->lockForUpdate()
->firstOrFail();
$existing = AiUsageLedger::query()
->where('request_id', $lockedRequest->id)
->where('entry_type', AiUsageLedger::TYPE_DEBIT)
->first();
if ($existing) {
return $existing;
}
$resolvedCost = $costUsd;
if ($resolvedCost === null || $resolvedCost < 0) {
$resolvedCost = (float) config('ai-editing.billing.default_unit_cost_usd', 0.01);
}
$event = Event::query()->find($lockedRequest->event_id);
$entitlement = $event ? $this->entitlements->resolveForEvent($event) : [
'allowed' => false,
'granted_by' => null,
];
$packageContext = $entitlement['granted_by'] === 'package'
? 'package_included'
: ($entitlement['granted_by'] === 'addon' ? 'addon_unlock' : 'unentitled');
return AiUsageLedger::query()->create([
'tenant_id' => $lockedRequest->tenant_id,
'event_id' => $lockedRequest->event_id,
'request_id' => $lockedRequest->id,
'entry_type' => AiUsageLedger::TYPE_DEBIT,
'quantity' => 1,
'unit_cost_usd' => $resolvedCost,
'amount_usd' => $resolvedCost,
'currency' => 'USD',
'package_context' => $packageContext,
'recorded_at' => now(),
'metadata' => array_merge([
'provider' => $lockedRequest->provider,
'provider_model' => $lockedRequest->provider_model,
'granted_by' => $entitlement['granted_by'],
], $metadata),
]);
});
}
}