ultimatepos/Modules/Accounting/Services/HoldingEntityResolutionService.php

127 lines
4.3 KiB
PHP

<?php
namespace Modules\Accounting\Services;
use App\HoldingEntity;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class HoldingEntityResolutionService
{
public function locationEntityMap(int $businessId): array
{
$map = [];
$entities = HoldingEntity::where('business_id', $businessId)
->where('is_active', true)
->get(['id', 'meta']);
foreach ($entities as $entity) {
$locationId = (int) data_get($entity->meta, 'business_location_id', 0);
if ($locationId > 0) {
$map[$locationId] = (int) $entity->id;
}
}
return $map;
}
public function resolveFromLocation(int $businessId, ?int $locationId): ?int
{
if (! $locationId) {
return null;
}
return $this->locationEntityMap($businessId)[$locationId] ?? null;
}
public function assessTagging(int $businessId): array
{
$entityCount = HoldingEntity::where('business_id', $businessId)->where('is_active', true)->count();
if ($entityCount === 0 || ! Schema::hasColumn('accounting_accounts_transactions', 'holding_entity_id')) {
return [
'entities' => $entityCount,
'total_lines' => 0,
'untagged_lines' => 0,
'tagged_pct' => 100,
'ready' => true,
];
}
$total = (int) DB::table('accounting_accounts_transactions as aat')
->join('accounting_accounts as aa', 'aa.id', '=', 'aat.accounting_account_id')
->where('aa.business_id', $businessId)
->count();
$untagged = (int) DB::table('accounting_accounts_transactions as aat')
->join('accounting_accounts as aa', 'aa.id', '=', 'aat.accounting_account_id')
->where('aa.business_id', $businessId)
->whereNull('aat.holding_entity_id')
->count();
$taggedPct = $total > 0 ? round((($total - $untagged) / $total) * 100, 1) : 100;
return [
'entities' => $entityCount,
'total_lines' => $total,
'untagged_lines' => $untagged,
'tagged_pct' => $taggedPct,
'ready' => $untagged === 0 || $taggedPct >= 80,
];
}
public function backfillUntagged(int $businessId): int
{
if (! Schema::hasColumn('accounting_accounts_transactions', 'holding_entity_id')
|| ! Schema::hasTable('transactions')) {
return 0;
}
$locationMap = $this->locationEntityMap($businessId);
if (empty($locationMap)) {
return 0;
}
$updated = 0;
foreach ($locationMap as $locationId => $entityId) {
$updated += DB::table('accounting_accounts_transactions as aat')
->join('transactions as t', 't.id', '=', 'aat.transaction_id')
->join('accounting_accounts as aa', 'aa.id', '=', 'aat.accounting_account_id')
->where('aa.business_id', $businessId)
->whereNull('aat.holding_entity_id')
->where('t.location_id', $locationId)
->whereNotNull('aat.transaction_id')
->update(['aat.holding_entity_id' => $entityId]);
}
return $updated;
}
public function applyEntityScope($query, int $businessId, HoldingEntity $entity): void
{
if (! Schema::hasColumn('accounting_accounts_transactions', 'holding_entity_id')) {
return;
}
$locationId = (int) data_get($entity->meta, 'business_location_id', 0);
$query->where(function ($scoped) use ($entity, $locationId) {
$scoped->where('aat.holding_entity_id', $entity->id);
if ($locationId > 0 && Schema::hasTable('transactions')) {
$scoped->orWhere(function ($fallback) use ($locationId) {
$fallback->whereNull('aat.holding_entity_id')
->whereNotNull('aat.transaction_id')
->whereIn('aat.transaction_id', function ($sub) use ($locationId) {
$sub->select('id')
->from('transactions')
->where('location_id', $locationId);
});
});
}
});
}
}