refactor: [db] 모델 connection을 codebridge로 변경 + 마이그레이션 파일 전체 삭제

- PMIS 모델 21개 + DailyWorkLog 2개에 $connection = 'codebridge' 추가
- MNG 마이그레이션 파일 18개 전체 삭제 (API에서 관리)
- 원칙: MNG는 마이그레이션 파일을 생성하지 않고 API에서만 관리
This commit is contained in:
김보곤
2026-03-19 20:21:42 +09:00
parent 9fd3dacd20
commit 39a8d8e2df
41 changed files with 46 additions and 881 deletions

View File

@@ -12,6 +12,8 @@ class DailyWorkLog extends Model
{
use BelongsToTenant, ModelTrait, SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'daily_work_logs';
protected $fillable = [

View File

@@ -12,6 +12,8 @@ class DailyWorkLogItem extends Model
{
use BelongsToTenant, ModelTrait, SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'daily_work_log_items';
protected $fillable = [

View File

@@ -11,6 +11,8 @@ class PmisArchiveFile extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $fillable = [
'tenant_id',
'folder_id',

View File

@@ -10,6 +10,8 @@ class PmisArchiveFolder extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $fillable = [
'tenant_id',
'parent_id',

View File

@@ -10,6 +10,8 @@ class PmisAttendanceEquipment extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_attendance_equipments';
protected $fillable = [

View File

@@ -10,6 +10,8 @@ class PmisAttendanceWorker extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_attendance_workers';
protected $fillable = [

View File

@@ -10,6 +10,8 @@ class PmisConstructionWorker extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_construction_workers';
protected $fillable = [

View File

@@ -10,6 +10,8 @@ class PmisDailyAttendance extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_daily_attendances';
protected $fillable = [

View File

@@ -10,6 +10,8 @@ class PmisDailyWorkReport extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_daily_work_reports';
protected $fillable = [

View File

@@ -9,6 +9,8 @@ class PmisEquipment extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_equipments';
protected $fillable = [

View File

@@ -9,6 +9,8 @@ class PmisJobType extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_job_types';
protected $fillable = [

View File

@@ -12,6 +12,8 @@ class PmisManual extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $fillable = [
'tenant_id',
'title',

View File

@@ -7,6 +7,8 @@
class PmisManualAttachment extends Model
{
protected $connection = 'codebridge';
protected $fillable = [
'manual_id',
'original_name',

View File

@@ -9,6 +9,8 @@ class PmisMaterial extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_materials';
protected $fillable = [

View File

@@ -12,6 +12,8 @@ class PmisNotice extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $fillable = [
'tenant_id',
'title',

View File

@@ -7,6 +7,8 @@
class PmisNoticeAttachment extends Model
{
protected $connection = 'codebridge';
protected $fillable = [
'notice_id',
'original_name',

View File

@@ -10,6 +10,8 @@ class PmisWorkReportEquipment extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_work_report_equipments';
protected $fillable = [

View File

@@ -10,6 +10,8 @@ class PmisWorkReportMaterial extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_work_report_materials';
protected $fillable = [

View File

@@ -10,6 +10,8 @@ class PmisWorkReportPhoto extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_work_report_photos';
protected $fillable = [

View File

@@ -10,6 +10,8 @@ class PmisWorkReportVolume extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_work_report_volumes';
protected $fillable = [

View File

@@ -10,6 +10,8 @@ class PmisWorkReportWorker extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_work_report_workers';
protected $fillable = [

View File

@@ -9,6 +9,8 @@ class PmisWorkVolume extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $table = 'pmis_work_volumes';
protected $fillable = [

View File

@@ -11,6 +11,8 @@ class PmisWorker extends Model
{
use SoftDeletes;
protected $connection = 'codebridge';
protected $fillable = [
'tenant_id',
'user_id',

View File

@@ -1,38 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_workers', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id')->default(1)->index();
$table->unsignedBigInteger('user_id')->nullable()->index()->comment('SAM users 테이블 FK (연결된 계정)');
$table->string('name', 50);
$table->string('login_id', 50)->nullable()->comment('PMIS 로그인 아이디');
$table->string('phone', 20)->nullable();
$table->string('email', 255)->nullable();
$table->string('department', 100)->nullable()->comment('소속 부서/현장소장 등');
$table->string('position', 50)->nullable()->comment('직책');
$table->string('role_type', 50)->nullable()->comment('권한 유형: 협력업체사용자, 원청관리자 등');
$table->string('gender', 5)->nullable();
$table->string('company', 100)->nullable()->comment('소속 업체명');
$table->string('profile_photo_path', 500)->nullable();
$table->json('options')->nullable();
$table->timestamp('last_login_at')->nullable();
$table->timestamps();
$table->softDeletes();
$table->unique(['tenant_id', 'user_id'], 'pmis_workers_tenant_user_unique');
});
}
public function down(): void
{
Schema::dropIfExists('pmis_workers');
}
};

View File

@@ -1,30 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_job_types', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->string('name', 100);
$table->integer('sort_order')->default(0);
$table->boolean('is_active')->default(true);
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
$table->index(['tenant_id', 'name']);
});
}
public function down(): void
{
Schema::dropIfExists('pmis_job_types');
}
};

View File

@@ -1,39 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_construction_workers', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->string('company_name', 200);
$table->string('trade_name', 100);
$table->unsignedBigInteger('job_type_id')->nullable();
$table->string('name', 50);
$table->string('phone', 20)->nullable();
$table->string('birth_date', 6)->nullable()->comment('YYMMDD');
$table->char('ssn_gender', 1)->nullable()->comment('주민번호 뒷자리 첫째');
$table->unsignedInteger('wage')->default(0);
$table->string('blood_type', 5)->nullable();
$table->text('remark')->nullable();
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
$table->index(['tenant_id', 'company_name']);
$table->index(['tenant_id', 'name']);
$table->foreign('job_type_id')->references('id')->on('pmis_job_types')->nullOnDelete();
});
}
public function down(): void
{
Schema::dropIfExists('pmis_construction_workers');
}
};

View File

@@ -1,39 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_equipments', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->string('company_name', 200);
$table->string('equipment_code', 50)->nullable();
$table->string('equipment_name', 200);
$table->string('specification', 300)->nullable();
$table->string('unit', 50)->nullable();
$table->string('equipment_number', 100);
$table->string('operator', 50)->nullable()->comment('운전원');
$table->date('inspection_end_date')->nullable()->comment('검사종료일');
$table->boolean('inspection_not_applicable')->default(false)->comment('검사 해당없음');
$table->date('insurance_end_date')->nullable()->comment('보험종료일');
$table->boolean('insurance_not_applicable')->default(false)->comment('보험 해당없음');
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
$table->index(['tenant_id', 'company_name']);
$table->index(['tenant_id', 'equipment_name']);
});
}
public function down(): void
{
Schema::dropIfExists('pmis_equipments');
}
};

View File

@@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_materials', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->string('company_name', 200);
$table->string('material_code', 50)->nullable();
$table->string('material_name', 200);
$table->string('specification', 300)->nullable();
$table->string('unit', 50)->nullable();
$table->decimal('design_quantity', 14, 2)->default(0)->comment('설계량');
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
$table->index(['tenant_id', 'company_name']);
$table->index(['tenant_id', 'material_name']);
});
}
public function down(): void
{
Schema::dropIfExists('pmis_materials');
}
};

View File

@@ -1,29 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_work_volumes', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id')->index();
$table->string('work_type', 200)->comment('공종');
$table->string('sub_work_type', 200)->comment('세부공종');
$table->string('unit', 50)->comment('단위');
$table->decimal('design_quantity', 14, 2)->default(0)->comment('설계량');
$table->boolean('daily_report_applied')->default(false)->comment('일보적용');
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('pmis_work_volumes');
}
};

View File

@@ -1,31 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_daily_attendances', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id')->index();
$table->date('date')->comment('일자');
$table->string('company_name', 200)->default('')->comment('업체명');
$table->string('weather', 50)->default('맑음')->comment('날씨');
$table->enum('status', ['draft', 'review', 'approved'])->default('draft')->comment('상태');
$table->text('notes')->nullable()->comment('특이사항');
$table->json('options')->nullable()->comment('검토자 등 부가정보');
$table->timestamps();
$table->softDeletes();
$table->unique(['tenant_id', 'date', 'company_name'], 'pmis_attendance_unique');
});
}
public function down(): void
{
Schema::dropIfExists('pmis_daily_attendances');
}
};

View File

@@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_attendance_workers', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id')->index();
$table->unsignedBigInteger('attendance_id')->index();
$table->string('work_type', 200)->comment('공종');
$table->string('job_type', 200)->comment('직종');
$table->string('name', 100)->comment('성명');
$table->decimal('man_days', 5, 1)->default(1.0)->comment('공수');
$table->decimal('amount', 14, 0)->default(0)->comment('금액');
$table->string('work_content', 500)->default('')->comment('작업내용');
$table->integer('sort_order')->default(0);
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->foreign('attendance_id')->references('id')->on('pmis_daily_attendances')->onDelete('cascade');
});
}
public function down(): void
{
Schema::dropIfExists('pmis_attendance_workers');
}
};

View File

@@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_attendance_equipments', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id')->index();
$table->unsignedBigInteger('attendance_id')->index();
$table->string('equipment_name', 200)->comment('장비명');
$table->string('specification', 300)->default('')->comment('규격');
$table->string('equipment_number', 100)->default('')->comment('장비번호');
$table->string('operator', 100)->default('')->comment('운전원');
$table->decimal('man_days', 5, 1)->default(1.0)->comment('공수');
$table->string('work_content', 500)->default('')->comment('작업내용');
$table->integer('sort_order')->default(0);
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->foreign('attendance_id')->references('id')->on('pmis_daily_attendances')->onDelete('cascade');
});
}
public function down(): void
{
Schema::dropIfExists('pmis_attendance_equipments');
}
};

View File

@@ -1,39 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_daily_work_reports', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->date('date');
$table->string('company_name', 200)->default('');
$table->string('weather', 50)->default('맑음');
$table->decimal('temp_low', 5, 1)->nullable();
$table->decimal('temp_high', 5, 1)->nullable();
$table->decimal('precipitation', 8, 1)->default(0);
$table->decimal('snowfall', 8, 1)->default(0);
$table->string('fine_dust', 50)->default('');
$table->string('ultra_fine_dust', 50)->default('');
$table->text('work_content_today')->nullable();
$table->text('work_content_tomorrow')->nullable();
$table->text('notes')->nullable();
$table->enum('status', ['draft', 'review', 'approved'])->default('draft');
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->unique(['tenant_id', 'date', 'company_name'], 'pmis_dwr_unique');
$table->index('tenant_id');
});
}
public function down(): void
{
Schema::dropIfExists('pmis_daily_work_reports');
}
};

View File

@@ -1,104 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
// 인원
Schema::create('pmis_work_report_workers', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->foreignId('report_id')->constrained('pmis_daily_work_reports')->cascadeOnDelete();
$table->string('work_type', 200);
$table->string('job_type', 200);
$table->integer('prev_cumulative')->default(0);
$table->integer('today_count')->default(0);
$table->unsignedSmallInteger('sort_order')->default(0);
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
});
// 장비
Schema::create('pmis_work_report_equipments', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->foreignId('report_id')->constrained('pmis_daily_work_reports')->cascadeOnDelete();
$table->string('equipment_name', 200);
$table->string('specification', 300)->default('');
$table->integer('prev_cumulative')->default(0);
$table->integer('today_count')->default(0);
$table->unsignedSmallInteger('sort_order')->default(0);
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
});
// 자재
Schema::create('pmis_work_report_materials', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->foreignId('report_id')->constrained('pmis_daily_work_reports')->cascadeOnDelete();
$table->string('material_name', 200);
$table->string('specification', 300)->default('');
$table->string('unit', 50)->default('');
$table->decimal('design_qty', 14, 2)->default(0);
$table->decimal('prev_cumulative', 14, 2)->default(0);
$table->decimal('today_count', 14, 2)->default(0);
$table->unsignedSmallInteger('sort_order')->default(0);
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
});
// 공사량
Schema::create('pmis_work_report_volumes', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->foreignId('report_id')->constrained('pmis_daily_work_reports')->cascadeOnDelete();
$table->string('work_type', 200);
$table->string('sub_work_type', 200)->default('');
$table->string('unit', 50)->default('');
$table->decimal('design_qty', 14, 2)->default(0);
$table->decimal('prev_cumulative', 14, 2)->default(0);
$table->decimal('today_count', 14, 2)->default(0);
$table->unsignedSmallInteger('sort_order')->default(0);
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
});
// 작업사진
Schema::create('pmis_work_report_photos', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->foreignId('report_id')->constrained('pmis_daily_work_reports')->cascadeOnDelete();
$table->string('photo_path', 500)->default('');
$table->string('location', 200)->default('');
$table->string('content', 500)->default('');
$table->date('photo_date')->nullable();
$table->unsignedSmallInteger('sort_order')->default(0);
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
});
}
public function down(): void
{
Schema::dropIfExists('pmis_work_report_photos');
Schema::dropIfExists('pmis_work_report_volumes');
Schema::dropIfExists('pmis_work_report_materials');
Schema::dropIfExists('pmis_work_report_equipments');
Schema::dropIfExists('pmis_work_report_workers');
}
};

View File

@@ -1,51 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_archive_folders', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->unsignedBigInteger('parent_id')->nullable();
$table->string('name', 200);
$table->unsignedSmallInteger('sort_order')->default(0);
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
$table->index('parent_id');
});
Schema::create('pmis_archive_files', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->foreignId('folder_id')->constrained('pmis_archive_folders')->cascadeOnDelete();
$table->string('title', 300)->default('');
$table->string('original_name', 500);
$table->string('file_path', 500);
$table->string('file_type', 50)->default('문서');
$table->unsignedBigInteger('file_size')->default(0);
$table->string('site_name', 200)->default('');
$table->unsignedBigInteger('registered_by')->nullable();
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
$table->index('folder_id');
$table->index('file_type');
});
}
public function down(): void
{
Schema::dropIfExists('pmis_archive_files');
Schema::dropIfExists('pmis_archive_folders');
}
};

View File

@@ -1,41 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_manuals', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->string('title', 300);
$table->text('content')->nullable();
$table->string('tags', 500)->default('');
$table->unsignedBigInteger('author_id')->nullable();
$table->unsignedInteger('views')->default(0);
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
});
Schema::create('pmis_manual_attachments', function (Blueprint $table) {
$table->id();
$table->foreignId('manual_id')->constrained('pmis_manuals')->cascadeOnDelete();
$table->string('original_name', 500);
$table->string('file_path', 500);
$table->unsignedBigInteger('file_size')->default(0);
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('pmis_manual_attachments');
Schema::dropIfExists('pmis_manuals');
}
};

View File

@@ -1,40 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pmis_notices', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->string('title', 300);
$table->text('content')->nullable();
$table->unsignedBigInteger('author_id')->nullable();
$table->unsignedInteger('views')->default(0);
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
});
Schema::create('pmis_notice_attachments', function (Blueprint $table) {
$table->id();
$table->foreignId('notice_id')->constrained('pmis_notices')->cascadeOnDelete();
$table->string('original_name', 500);
$table->string('file_path', 500);
$table->unsignedBigInteger('file_size')->default(0);
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('pmis_notice_attachments');
Schema::dropIfExists('pmis_notices');
}
};

View File

@@ -1,92 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
return new class extends Migration
{
/**
* 중복 journal_entry_lines 정리
*
* 문제: 미지급금 관리에서 프리랜서 잔액이 마이너스로 표시됨
* 원인: 동일 전표 내 같은 계정/거래처/금액의 라인이 중복 생성됨
* 해결: 중복 라인 중 ID가 큰 것을 삭제 (원본 보존)
*/
public function up(): void
{
// 1. 동일 전표 내 중복 라인 탐지
// (같은 journal_entry_id + account_code + dc_type + trading_partner_name + debit_amount + credit_amount)
$duplicates = DB::select("
SELECT journal_entry_id, account_code, dc_type, trading_partner_name,
debit_amount, credit_amount, COUNT(*) as cnt,
MIN(id) as keep_id, GROUP_CONCAT(id ORDER BY id) as all_ids
FROM journal_entry_lines
WHERE account_code IN ('25300', '26200')
GROUP BY journal_entry_id, account_code, dc_type, trading_partner_name,
debit_amount, credit_amount
HAVING cnt > 1
");
if (empty($duplicates)) {
Log::info('[Migration] 중복 journal_entry_lines 없음 - 정리 불필요');
return;
}
$totalDeleted = 0;
foreach ($duplicates as $dup) {
$allIds = explode(',', $dup->all_ids);
$keepId = $dup->keep_id;
$deleteIds = array_filter($allIds, fn ($id) => (int) $id !== (int) $keepId);
if (! empty($deleteIds)) {
Log::info("[Migration] 중복 라인 삭제: journal_entry_id={$dup->journal_entry_id}, "
."account_code={$dup->account_code}, dc_type={$dup->dc_type}, "
."partner={$dup->trading_partner_name}, "
."keep_id={$keepId}, delete_ids=".implode(',', $deleteIds));
$deleted = DB::table('journal_entry_lines')
->whereIn('id', $deleteIds)
->delete();
$totalDeleted += $deleted;
}
}
Log::info("[Migration] 중복 journal_entry_lines 정리 완료: {$totalDeleted}건 삭제");
// 2. 삭제 후 전표 합계 재계산
if ($totalDeleted > 0) {
$affectedEntryIds = collect($duplicates)->pluck('journal_entry_id')->unique();
foreach ($affectedEntryIds as $entryId) {
$sums = DB::selectOne("
SELECT COALESCE(SUM(debit_amount), 0) as total_debit,
COALESCE(SUM(credit_amount), 0) as total_credit
FROM journal_entry_lines
WHERE journal_entry_id = ?
", [$entryId]);
DB::table('journal_entries')
->where('id', $entryId)
->update([
'total_debit' => $sums->total_debit,
'total_credit' => $sums->total_credit,
]);
Log::info("[Migration] 전표 합계 재계산: id={$entryId}, "
."debit={$sums->total_debit}, credit={$sums->total_credit}");
}
}
}
/**
* 데이터 정리 마이그레이션이므로 rollback 불가
*/
public function down(): void
{
Log::warning('[Migration] 중복 라인 삭제는 롤백할 수 없습니다.');
}
};

View File

@@ -1,48 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('daily_work_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->date('log_date');
$table->text('memo')->nullable();
$table->text('reflection')->nullable();
$table->unsignedBigInteger('created_by')->nullable();
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->unique(['tenant_id', 'log_date']);
$table->index('tenant_id');
});
Schema::create('daily_work_log_items', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id');
$table->foreignId('daily_work_log_id')->constrained('daily_work_logs')->cascadeOnDelete();
$table->unsignedSmallInteger('sort_order')->default(0);
$table->string('category', 100)->nullable();
$table->string('task', 500);
$table->string('priority', 50)->nullable();
$table->boolean('is_completed')->default(false);
$table->string('note', 500)->nullable();
$table->json('options')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index('tenant_id');
$table->index('daily_work_log_id');
});
}
public function down(): void
{
Schema::dropIfExists('daily_work_log_items');
Schema::dropIfExists('daily_work_logs');
}
};

View File

@@ -1,51 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* codebridge DB의 tenant_id=1 계정과목을 KIS 5자리 표준으로 완전 교체
*
* - sam DB에는 API 마이그레이션으로 이미 적용 완료
* - codebridge DB에 동일하게 적용
*/
public function up(): void
{
// 1. 한글 카테고리 → 영문 통일
$mapping = [
'자산' => 'asset',
'부채' => 'liability',
'자본' => 'capital',
'수익' => 'revenue',
'비용' => 'expense',
];
foreach ($mapping as $korean => $english) {
DB::table('account_codes')
->where('category', $korean)
->update(['category' => $english]);
}
// 2. tenant_id=1의 5자리가 아닌 코드 삭제 (1, 2, 3자리)
DB::table('account_codes')
->where('tenant_id', 1)
->whereRaw('LENGTH(code) != 5')
->delete();
// 3. 5자리 코드 전체 활성화
DB::table('account_codes')
->where('tenant_id', 1)
->whereRaw('LENGTH(code) = 5')
->update(['is_active' => true]);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// 롤백 불가
}
};

View File

@@ -1,107 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
* 더존 3자리 계정코드 → KIS 5자리 표준코드 마이그레이션
*
* journal_entry_lines, hometax_invoice_journals 테이블의 account_code를
* account_codes 테이블의 이름 기반으로 5자리 코드로 변환한다.
* 이미 5자리인 코드는 건너뛴다.
*/
return new class extends Migration
{
// 더존 3자리 → KIS 5자리 매핑 (이름 기반 검증 완료)
private const MAPPING = [
'101' => '10100', // 현금
'102' => '10200', // 당좌예금
'103' => '10300', // 보통예금
'105' => '10500', // 정기적금
'108' => '10800', // 외상매출금
'109' => '10900', // 대손충당금 → 대손충당금(외상매출금)
'117' => '13500', // 부가세대급금
'135' => '13500', // 부가세대급금 (중복코드)
'157' => '96200', // 임차보증금
'172' => '21200', // 비품
'204' => '25300', // 미지급금
'205' => '26200', // 미지급비용
'207' => '25400', // 예수금
'208' => '25500', // 부가세예수금
'251' => '25100', // 외상매입금
'253' => '25300', // 미지급금
'301' => '33100', // 자본금
'401' => '40100', // 상품매출
'402' => '40400', // 제품매출
'501' => '45100', // 상품매입 → 상품매출원가
'801' => '80200', // 급여 → 직원급여
'805' => '81100', // 복리후생비
'807' => '81300', // 접대비
'808' => '81400', // 통신비
'811' => '81700', // 세금과공과 → 세금과공과금
'812' => '81900', // 임차료 → 지급임차료
'816' => '82100', // 보험료
'817' => '82200', // 차량유지비
'818' => '82400', // 운반비
'820' => '82600', // 도서인쇄비
'821' => '82900', // 사무용품비
'822' => '83000', // 소모품비
'823' => '83100', // 지급수수료
'826' => '83700', // 건물관리비
'838' => '83100', // 용역비 → 지급수수료
'901' => '90100', // 이자수익
];
public function up(): void
{
$tables = ['journal_entry_lines', 'hometax_invoice_journals'];
// 5자리 코드의 계정명 사전 구축
$names = [];
foreach (self::MAPPING as $newCode) {
if (! isset($names[$newCode])) {
$ac = DB::table('account_codes')
->where('code', $newCode)
->first(['name']);
$names[$newCode] = $ac?->name;
}
}
foreach ($tables as $table) {
// 3자리 이하 코드가 있는지 확인
$has3digit = DB::table($table)
->whereRaw('LENGTH(account_code) < 5')
->exists();
if (! $has3digit) {
Log::info("[Migration] {$table}: 3자리 코드 없음, 건너뜀");
continue;
}
foreach (self::MAPPING as $oldCode => $newCode) {
$newName = $names[$newCode] ?? null;
if (! $newName) {
continue;
}
$updated = DB::table($table)
->where('account_code', $oldCode)
->update([
'account_code' => $newCode,
'account_name' => $newName,
]);
if ($updated > 0) {
Log::info("[Migration] {$table}: {$oldCode}{$newCode} ({$newName}): {$updated}");
}
}
}
}
public function down(): void
{
// 역방향 마이그레이션은 지원하지 않음 (데이터 변환은 되돌리기 어려움)
}
};