feat:테넌트설정 API 및 다수 서비스 개선
- TenantSetting CRUD API 추가 - Calendar, Entertainment, VAT 서비스 개선 - 5130 BOM 계산 로직 수정 - quote_items에 item_type 컬럼 추가 - tenant_settings 테이블 마이그레이션 - Swagger 문서 업데이트
This commit is contained in:
@@ -47,4 +47,4 @@ public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('schedules');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -58,4 +58,4 @@ public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('expense_accounts');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -37,4 +37,4 @@ public function down(): void
|
||||
$table->dropColumn(['order_id', 'shipment_id', 'source_type']);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -41,4 +41,4 @@ public function down(): void
|
||||
{
|
||||
DB::table('common_codes')->where('code_group', 'delivery_method')->delete();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* quote_items 테이블에 item_type 컬럼 추가
|
||||
* - item_type: RM(원자재), SM(부자재), CS(소모품), FG(완제품), PT(부품)
|
||||
* - 기존 데이터는 items 테이블에서 조회하여 업데이트
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('quote_items', function (Blueprint $table) {
|
||||
$table->string('item_type', 15)->nullable()->after('item_id')
|
||||
->comment('품목 유형: FG, PT, SM, RM, CS');
|
||||
});
|
||||
|
||||
// 기존 데이터 업데이트: items 테이블에서 item_type 가져오기
|
||||
DB::statement('
|
||||
UPDATE quote_items qi
|
||||
INNER JOIN items i ON qi.item_id = i.id
|
||||
SET qi.item_type = i.item_type
|
||||
WHERE qi.item_id IS NOT NULL
|
||||
');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('quote_items', function (Blueprint $table) {
|
||||
$table->dropColumn('item_type');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* 테넌트별 설정 테이블
|
||||
*
|
||||
* Key-Value 형태로 테넌트별 다양한 설정 저장
|
||||
* - stock_item_types: 재고관리 대상 품목유형
|
||||
* - default_safety_stock: 기본 안전재고
|
||||
* - low_stock_alert: 재고부족 알림 설정
|
||||
* 등
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('tenant_settings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('tenant_id')->comment('테넌트 ID');
|
||||
$table->string('setting_group', 50)->comment('설정 그룹 (stock, order, production 등)');
|
||||
$table->string('setting_key', 100)->comment('설정 키');
|
||||
$table->json('setting_value')->nullable()->comment('설정 값 (JSON)');
|
||||
$table->string('description')->nullable()->comment('설정 설명');
|
||||
$table->timestamps();
|
||||
$table->unsignedBigInteger('updated_by')->nullable()->comment('수정자 ID');
|
||||
|
||||
// 인덱스
|
||||
$table->unique(['tenant_id', 'setting_group', 'setting_key'], 'tenant_settings_unique');
|
||||
$table->index(['tenant_id', 'setting_group'], 'tenant_settings_group_idx');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('tenant_settings');
|
||||
}
|
||||
};
|
||||
@@ -155,6 +155,6 @@ public function run(): void
|
||||
// 데이터 삽입
|
||||
DB::table('fund_schedules')->insert($schedules);
|
||||
|
||||
$this->command->info('FundScheduleSeeder 완료: 자금계획일정 ' . count($schedules) . '개 생성');
|
||||
$this->command->info('FundScheduleSeeder 완료: 자금계획일정 '.count($schedules).'개 생성');
|
||||
}
|
||||
}
|
||||
|
||||
87
database/seeders/StockInitSeeder.php
Normal file
87
database/seeders/StockInitSeeder.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Items\Item;
|
||||
use App\Models\Tenants\Stock;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* 재고 초기화 시더
|
||||
*
|
||||
* - 모든 자재 품목(RM, SM, CS)에 대해 Stock 레코드 생성/업데이트
|
||||
* - 안전재고: 10개
|
||||
* - 실제 재고: 0~100 랜덤
|
||||
*/
|
||||
class StockInitSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$tenantId = 287; // 실제 사용 테넌트
|
||||
|
||||
// 재고 관리 대상 품목 조회 (RM, SM, CS, PT, SF) - FG(완제품) 제외
|
||||
$items = Item::where('tenant_id', $tenantId)
|
||||
->whereIn('item_type', ['RM', 'SM', 'CS', 'PT', 'SF'])
|
||||
->get();
|
||||
|
||||
$this->command->info("총 {$items->count()}개 품목에 대해 Stock 생성/업데이트 시작...");
|
||||
|
||||
$created = 0;
|
||||
$updated = 0;
|
||||
|
||||
DB::transaction(function () use ($items, $tenantId, &$created, &$updated) {
|
||||
foreach ($items as $item) {
|
||||
$stockQty = rand(0, 100);
|
||||
$safetyStock = 10;
|
||||
|
||||
// 재고 상태 계산
|
||||
$status = 'normal';
|
||||
if ($stockQty <= 0) {
|
||||
$status = 'out';
|
||||
} elseif ($stockQty < $safetyStock) {
|
||||
$status = 'low';
|
||||
}
|
||||
|
||||
$stock = Stock::where('tenant_id', $tenantId)
|
||||
->where('item_id', $item->id)
|
||||
->first();
|
||||
|
||||
if ($stock) {
|
||||
// 기존 Stock 업데이트
|
||||
$stock->update([
|
||||
'stock_qty' => $stockQty,
|
||||
'safety_stock' => $safetyStock,
|
||||
'available_qty' => $stockQty,
|
||||
'status' => $status,
|
||||
'updated_by' => 1,
|
||||
]);
|
||||
$updated++;
|
||||
} else {
|
||||
// 새 Stock 생성
|
||||
Stock::create([
|
||||
'tenant_id' => $tenantId,
|
||||
'item_id' => $item->id,
|
||||
'item_code' => $item->code,
|
||||
'item_name' => $item->name,
|
||||
'item_type' => $item->item_type,
|
||||
'specification' => $item->specification ?? null,
|
||||
'unit' => $item->unit ?? 'EA',
|
||||
'stock_qty' => $stockQty,
|
||||
'safety_stock' => $safetyStock,
|
||||
'reserved_qty' => 0,
|
||||
'available_qty' => $stockQty,
|
||||
'lot_count' => 0,
|
||||
'location' => null,
|
||||
'status' => $status,
|
||||
'created_by' => 1,
|
||||
'updated_by' => 1,
|
||||
]);
|
||||
$created++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$this->command->info("완료! 생성: {$created}개, 업데이트: {$updated}개");
|
||||
}
|
||||
}
|
||||
@@ -86,4 +86,4 @@ public function run(): void
|
||||
|
||||
$this->command->info("부가세 신고 마감일 {$year}년 일정이 등록되었습니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
61
database/seeders/TenantSettingSeeder.php
Normal file
61
database/seeders/TenantSettingSeeder.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Tenants\TenantSetting;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
/**
|
||||
* 테넌트 설정 기본값 시더
|
||||
*
|
||||
* tenant_id 287에 대한 기본 설정 생성
|
||||
*/
|
||||
class TenantSettingSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$tenantId = 287;
|
||||
|
||||
$settings = [
|
||||
// 재고 관련 설정
|
||||
[
|
||||
'tenant_id' => $tenantId,
|
||||
'setting_group' => 'stock',
|
||||
'setting_key' => 'stock_item_types',
|
||||
'setting_value' => ['RM', 'SM', 'CS', 'PT', 'SF'],
|
||||
'description' => '재고관리 대상 품목유형 (FG 완제품 제외)',
|
||||
],
|
||||
[
|
||||
'tenant_id' => $tenantId,
|
||||
'setting_group' => 'stock',
|
||||
'setting_key' => 'default_safety_stock',
|
||||
'setting_value' => 10,
|
||||
'description' => '안전재고 기본값',
|
||||
],
|
||||
[
|
||||
'tenant_id' => $tenantId,
|
||||
'setting_group' => 'stock',
|
||||
'setting_key' => 'low_stock_alert',
|
||||
'setting_value' => true,
|
||||
'description' => '재고부족 알림 활성화',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($settings as $setting) {
|
||||
TenantSetting::updateOrCreate(
|
||||
[
|
||||
'tenant_id' => $setting['tenant_id'],
|
||||
'setting_group' => $setting['setting_group'],
|
||||
'setting_key' => $setting['setting_key'],
|
||||
],
|
||||
[
|
||||
'setting_value' => $setting['setting_value'],
|
||||
'description' => $setting['description'],
|
||||
'updated_by' => 1,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$this->command->info('테넌트 설정 시더 완료: '.count($settings).'개 설정');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user