Files
sam-api/app/Services/Stats/DimensionSyncService.php
권혁성 595e3d59b4 feat: sam_stat P1 도메인 확장 (Phase 3)
- 차원 테이블: dim_client, dim_product 마이그레이션 + SCD Type 2 동기화 (DimensionSyncService)
- 재고 통계: stat_inventory_daily + InventoryStatService (stocks, stock_transactions, inspections)
- 견적/영업 통계: stat_quote_pipeline_daily + QuoteStatService (quotes, biddings, sales_prospects)
- 인사/근태 통계: stat_hr_attendance_daily + HrStatService (attendances, leaves, user_tenants)
- KPI/알림: stat_kpi_targets, stat_alerts + KpiAlertService + StatCheckKpiAlertsCommand
- StatAggregatorService에 inventory, quote, hr 도메인 추가 (총 6개 도메인)
- 스케줄러: stat:check-kpi-alerts 매일 09:00 등록

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 20:19:50 +09:00

164 lines
5.3 KiB
PHP

<?php
namespace App\Services\Stats;
use App\Models\Stats\Dimensions\DimClient;
use App\Models\Stats\Dimensions\DimProduct;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class DimensionSyncService
{
/**
* 고객 차원 동기화 (SCD Type 2)
*/
public function syncClients(int $tenantId): int
{
$today = Carbon::today()->format('Y-m-d');
$synced = 0;
$clients = DB::connection('mysql')
->table('clients')
->where('tenant_id', $tenantId)
->select('id', 'tenant_id', 'name', 'client_group_id', 'client_type')
->get();
foreach ($clients as $client) {
$groupName = null;
if ($client->client_group_id) {
$groupName = DB::connection('mysql')
->table('client_groups')
->where('id', $client->client_group_id)
->value('group_name');
}
$current = DimClient::where('tenant_id', $tenantId)
->where('client_id', $client->id)
->where('is_current', true)
->first();
if (! $current) {
DimClient::create([
'tenant_id' => $tenantId,
'client_id' => $client->id,
'client_name' => $client->name,
'client_group_id' => $client->client_group_id,
'client_group_name' => $groupName,
'client_type' => $client->client_type,
'region' => null,
'valid_from' => $today,
'valid_to' => null,
'is_current' => true,
]);
$synced++;
continue;
}
$changed = $current->client_name !== $client->name
|| $current->client_group_id != $client->client_group_id
|| $current->client_type !== $client->client_type;
if ($changed) {
$current->update([
'valid_to' => $today,
'is_current' => false,
]);
DimClient::create([
'tenant_id' => $tenantId,
'client_id' => $client->id,
'client_name' => $client->name,
'client_group_id' => $client->client_group_id,
'client_group_name' => $groupName,
'client_type' => $client->client_type,
'region' => null,
'valid_from' => $today,
'valid_to' => null,
'is_current' => true,
]);
$synced++;
}
}
return $synced;
}
/**
* 제품(품목) 차원 동기화 (SCD Type 2)
*/
public function syncProducts(int $tenantId): int
{
$today = Carbon::today()->format('Y-m-d');
$synced = 0;
$items = DB::connection('mysql')
->table('items')
->where('tenant_id', $tenantId)
->where('is_active', true)
->select('id', 'tenant_id', 'code', 'name', 'item_type', 'category_id')
->get();
foreach ($items as $item) {
$categoryName = null;
if ($item->category_id) {
$categoryName = DB::connection('mysql')
->table('categories')
->where('id', $item->category_id)
->value('name');
}
$current = DimProduct::where('tenant_id', $tenantId)
->where('item_id', $item->id)
->where('is_current', true)
->first();
if (! $current) {
DimProduct::create([
'tenant_id' => $tenantId,
'item_id' => $item->id,
'item_code' => $item->code,
'item_name' => $item->name,
'item_type' => $item->item_type,
'category_id' => $item->category_id,
'category_name' => $categoryName,
'valid_from' => $today,
'valid_to' => null,
'is_current' => true,
]);
$synced++;
continue;
}
$changed = $current->item_name !== $item->name
|| $current->item_code !== $item->code
|| $current->item_type !== $item->item_type
|| $current->category_id != $item->category_id;
if ($changed) {
$current->update([
'valid_to' => $today,
'is_current' => false,
]);
DimProduct::create([
'tenant_id' => $tenantId,
'item_id' => $item->id,
'item_code' => $item->code,
'item_name' => $item->name,
'item_type' => $item->item_type,
'category_id' => $item->category_id,
'category_name' => $categoryName,
'valid_from' => $today,
'valid_to' => null,
'is_current' => true,
]);
$synced++;
}
}
return $synced;
}
}