127 lines
4.3 KiB
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);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|