feat: sam_stat P0 도메인 집계 구현 (Phase 2)
- 영업(Sales), 재무(Finance), 생산(Production) 3개 도메인 구현 - 일간/월간 통계 테이블 6개 마이그레이션 생성 - 도메인별 StatService (SalesStatService, FinanceStatService, ProductionStatService) - Daily/Monthly 6개 Eloquent 모델 생성 - StatAggregatorService에 도메인 서비스 매핑 활성화 - StatJobLog duration_ms abs() 처리 - 스케줄러 등록 (일간 02:00, 월간 1일 03:00) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
protected $connection = 'sam_stat';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
Schema::connection($this->connection)->create('stat_sales_daily', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('tenant_id');
|
||||
$table->date('stat_date');
|
||||
|
||||
// 수주
|
||||
$table->unsignedInteger('order_count')->default(0)->comment('신규 수주 건수');
|
||||
$table->decimal('order_amount', 18, 2)->default(0)->comment('수주 금액');
|
||||
$table->unsignedInteger('order_item_count')->default(0)->comment('수주 품목 수');
|
||||
|
||||
// 매출
|
||||
$table->unsignedInteger('sales_count')->default(0)->comment('매출 건수');
|
||||
$table->decimal('sales_amount', 18, 2)->default(0)->comment('매출 금액');
|
||||
$table->decimal('sales_tax_amount', 18, 2)->default(0)->comment('세액');
|
||||
|
||||
// 고객
|
||||
$table->unsignedInteger('new_client_count')->default(0)->comment('신규 고객 수');
|
||||
$table->unsignedInteger('active_client_count')->default(0)->comment('활성 고객 수');
|
||||
|
||||
// 수주 상태별 건수
|
||||
$table->unsignedInteger('order_draft_count')->default(0);
|
||||
$table->unsignedInteger('order_confirmed_count')->default(0);
|
||||
$table->unsignedInteger('order_in_progress_count')->default(0);
|
||||
$table->unsignedInteger('order_completed_count')->default(0);
|
||||
$table->unsignedInteger('order_cancelled_count')->default(0);
|
||||
|
||||
// 출하
|
||||
$table->unsignedInteger('shipment_count')->default(0);
|
||||
$table->decimal('shipment_amount', 18, 2)->default(0);
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['tenant_id', 'stat_date'], 'uk_tenant_date');
|
||||
$table->index('stat_date');
|
||||
$table->index('tenant_id');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::connection($this->connection)->dropIfExists('stat_sales_daily');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
protected $connection = 'sam_stat';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
Schema::connection($this->connection)->create('stat_finance_daily', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('tenant_id');
|
||||
$table->date('stat_date');
|
||||
|
||||
// 입출금
|
||||
$table->unsignedInteger('deposit_count')->default(0);
|
||||
$table->decimal('deposit_amount', 18, 2)->default(0);
|
||||
$table->unsignedInteger('withdrawal_count')->default(0);
|
||||
$table->decimal('withdrawal_amount', 18, 2)->default(0);
|
||||
$table->decimal('net_cashflow', 18, 2)->default(0)->comment('입금 - 출금');
|
||||
|
||||
// 매입
|
||||
$table->unsignedInteger('purchase_count')->default(0);
|
||||
$table->decimal('purchase_amount', 18, 2)->default(0);
|
||||
$table->decimal('purchase_tax_amount', 18, 2)->default(0);
|
||||
|
||||
// 미수/미지급
|
||||
$table->decimal('receivable_balance', 18, 2)->default(0)->comment('미수금 잔액');
|
||||
$table->decimal('payable_balance', 18, 2)->default(0)->comment('미지급 잔액');
|
||||
$table->decimal('overdue_receivable', 18, 2)->default(0)->comment('연체 미수금');
|
||||
|
||||
// 어음
|
||||
$table->unsignedInteger('bill_issued_count')->default(0);
|
||||
$table->decimal('bill_issued_amount', 18, 2)->default(0);
|
||||
$table->unsignedInteger('bill_matured_count')->default(0);
|
||||
$table->decimal('bill_matured_amount', 18, 2)->default(0);
|
||||
|
||||
// 카드
|
||||
$table->unsignedInteger('card_transaction_count')->default(0);
|
||||
$table->decimal('card_transaction_amount', 18, 2)->default(0);
|
||||
|
||||
// 은행
|
||||
$table->decimal('bank_balance_total', 18, 2)->default(0)->comment('전 계좌 잔액 합계');
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['tenant_id', 'stat_date'], 'uk_tenant_date');
|
||||
$table->index('stat_date');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::connection($this->connection)->dropIfExists('stat_finance_daily');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
protected $connection = 'sam_stat';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
Schema::connection($this->connection)->create('stat_finance_monthly', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('tenant_id');
|
||||
$table->smallInteger('stat_year');
|
||||
$table->tinyInteger('stat_month');
|
||||
|
||||
$table->decimal('deposit_total', 18, 2)->default(0);
|
||||
$table->decimal('withdrawal_total', 18, 2)->default(0);
|
||||
$table->decimal('net_cashflow', 18, 2)->default(0);
|
||||
$table->decimal('purchase_total', 18, 2)->default(0);
|
||||
$table->decimal('card_total', 18, 2)->default(0);
|
||||
|
||||
$table->decimal('receivable_end', 18, 2)->default(0)->comment('월말 미수금');
|
||||
$table->decimal('payable_end', 18, 2)->default(0)->comment('월말 미지급');
|
||||
$table->decimal('bank_balance_end', 18, 2)->default(0)->comment('월말 잔액');
|
||||
|
||||
$table->decimal('mom_cashflow_change', 8, 2)->nullable()->comment('전월 대비 현금흐름 변화 (%)');
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['tenant_id', 'stat_year', 'stat_month'], 'uk_tenant_year_month');
|
||||
$table->index(['stat_year', 'stat_month']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::connection($this->connection)->dropIfExists('stat_finance_monthly');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
protected $connection = 'sam_stat';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
Schema::connection($this->connection)->create('stat_sales_monthly', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('tenant_id');
|
||||
$table->smallInteger('stat_year');
|
||||
$table->tinyInteger('stat_month');
|
||||
|
||||
// 일일 합산
|
||||
$table->unsignedInteger('order_count')->default(0);
|
||||
$table->decimal('order_amount', 18, 2)->default(0);
|
||||
$table->unsignedInteger('sales_count')->default(0);
|
||||
$table->decimal('sales_amount', 18, 2)->default(0);
|
||||
$table->unsignedInteger('shipment_count')->default(0);
|
||||
$table->decimal('shipment_amount', 18, 2)->default(0);
|
||||
|
||||
// 월간 고유 지표
|
||||
$table->unsignedInteger('unique_client_count')->default(0)->comment('거래 고객 수');
|
||||
$table->decimal('avg_order_amount', 18, 2)->default(0)->comment('평균 수주 금액');
|
||||
$table->unsignedBigInteger('top_client_id')->nullable()->comment('최다 거래 고객');
|
||||
$table->decimal('top_client_amount', 18, 2)->default(0);
|
||||
$table->decimal('mom_growth_rate', 8, 2)->nullable()->comment('전월 대비 성장률 (%)');
|
||||
$table->decimal('yoy_growth_rate', 8, 2)->nullable()->comment('전년동월 대비 (%)');
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['tenant_id', 'stat_year', 'stat_month'], 'uk_tenant_year_month');
|
||||
$table->index(['stat_year', 'stat_month']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::connection($this->connection)->dropIfExists('stat_sales_monthly');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
protected $connection = 'sam_stat';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
Schema::connection($this->connection)->create('stat_production_daily', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('tenant_id');
|
||||
$table->date('stat_date');
|
||||
|
||||
// 작업지시
|
||||
$table->unsignedInteger('wo_created_count')->default(0)->comment('신규 작업지시');
|
||||
$table->unsignedInteger('wo_completed_count')->default(0)->comment('완료 작업지시');
|
||||
$table->unsignedInteger('wo_in_progress_count')->default(0)->comment('진행중');
|
||||
$table->unsignedInteger('wo_overdue_count')->default(0)->comment('납기 초과');
|
||||
|
||||
// 생산량
|
||||
$table->decimal('production_qty', 18, 2)->default(0)->comment('생산 수량');
|
||||
$table->decimal('defect_qty', 18, 2)->default(0)->comment('불량 수량');
|
||||
$table->decimal('defect_rate', 5, 2)->default(0)->comment('불량률 (%)');
|
||||
|
||||
// 작업 효율
|
||||
$table->decimal('planned_hours', 10, 2)->default(0)->comment('계획 공수');
|
||||
$table->decimal('actual_hours', 10, 2)->default(0)->comment('실적 공수');
|
||||
$table->decimal('efficiency_rate', 5, 2)->default(0)->comment('효율 (%)');
|
||||
|
||||
// 작업자
|
||||
$table->unsignedInteger('active_worker_count')->default(0);
|
||||
$table->unsignedInteger('issue_count')->default(0)->comment('발생 이슈 수');
|
||||
|
||||
// 납기
|
||||
$table->unsignedInteger('on_time_delivery_count')->default(0);
|
||||
$table->unsignedInteger('late_delivery_count')->default(0);
|
||||
$table->decimal('delivery_rate', 5, 2)->default(0)->comment('납기준수율 (%)');
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['tenant_id', 'stat_date'], 'uk_tenant_date');
|
||||
$table->index('stat_date');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::connection($this->connection)->dropIfExists('stat_production_daily');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
protected $connection = 'sam_stat';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
Schema::connection($this->connection)->create('stat_production_monthly', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('tenant_id');
|
||||
$table->smallInteger('stat_year');
|
||||
$table->tinyInteger('stat_month');
|
||||
|
||||
$table->unsignedInteger('wo_total_count')->default(0);
|
||||
$table->unsignedInteger('wo_completed_count')->default(0);
|
||||
$table->decimal('production_qty', 18, 2)->default(0);
|
||||
$table->decimal('defect_qty', 18, 2)->default(0);
|
||||
$table->decimal('avg_defect_rate', 5, 2)->default(0);
|
||||
$table->decimal('avg_efficiency_rate', 5, 2)->default(0);
|
||||
$table->decimal('avg_delivery_rate', 5, 2)->default(0);
|
||||
$table->decimal('total_planned_hours', 10, 2)->default(0);
|
||||
$table->decimal('total_actual_hours', 10, 2)->default(0);
|
||||
$table->unsignedInteger('issue_total_count')->default(0);
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['tenant_id', 'stat_year', 'stat_month'], 'uk_tenant_year_month');
|
||||
$table->index(['stat_year', 'stat_month']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::connection($this->connection)->dropIfExists('stat_production_monthly');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user