feat(billing): renewals, coupons, VAT numbering, billing cycles and invoice payment tracking
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
ea9a53f742
commit
25f23d541e
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\ModuleVmware;
|
||||
use App\Models\Service;
|
||||
use App\Support\ServiceExpirySync;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class ServiceExpiryReconciler
|
||||
{
|
||||
/**
|
||||
* @return array{synced_vmware: int, backfilled_services: int, orphan_vms: int}
|
||||
*/
|
||||
public function run(bool $dryRun = false): array
|
||||
{
|
||||
$stats = ['synced_vmware' => 0, 'backfilled_services' => 0, 'orphan_vms' => $this->orphanVmCount()];
|
||||
|
||||
Service::query()
|
||||
->with('vmware')
|
||||
->whereNotNull('vm_id')
|
||||
->whereNotIn('status', ['terminated', 'cancelled'])
|
||||
->chunkById(200, function ($services) use (&$stats, $dryRun) {
|
||||
foreach ($services as $service) {
|
||||
$this->reconcile($service, $stats, $dryRun);
|
||||
}
|
||||
});
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
private function reconcile(Service $service, array &$stats, bool $dryRun): void
|
||||
{
|
||||
$vm = $service->vmware;
|
||||
if (! $vm) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($service->expires_at) {
|
||||
if ((int) $vm->next_due_date !== $service->expires_at->timestamp) {
|
||||
$stats['synced_vmware']++;
|
||||
$dryRun || ServiceExpirySync::toVmware($service);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($vm->next_due_date) {
|
||||
$stats['backfilled_services']++;
|
||||
$dryRun || $service->update(['expires_at' => Carbon::createFromTimestamp((int) $vm->next_due_date, config('app.timezone'))]);
|
||||
}
|
||||
}
|
||||
|
||||
private function orphanVmCount(): int
|
||||
{
|
||||
return ModuleVmware::query()
|
||||
->whereNotIn('id', Service::query()->whereNotNull('vm_id')->select('vm_id'))
|
||||
->where(fn ($query) => $query
|
||||
->whereNull('service_id')
|
||||
->orWhereNotIn('service_id', Service::query()->select('id')))
|
||||
->count();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user