feat: G-1 작업지시 관리 API 구현
- 작업지시 테이블 마이그레이션 (work_orders, work_order_items, work_order_bending_details, work_order_issues)
- 작업지시 모델 4개 (WorkOrder, WorkOrderItem, WorkOrderBendingDetail, WorkOrderIssue)
- WorkOrderService 비즈니스 로직 구현
- WorkOrderController REST API 엔드포인트 11개
- FormRequest 검증 클래스 5개
- Swagger API 문서화 완료
API Endpoints:
- GET /work-orders (목록)
- GET /work-orders/stats (통계)
- POST /work-orders (등록)
- GET /work-orders/{id} (상세)
- PUT /work-orders/{id} (수정)
- DELETE /work-orders/{id} (삭제)
- PATCH /work-orders/{id}/status (상태변경)
- PATCH /work-orders/{id}/assign (담당자배정)
- PATCH /work-orders/{id}/bending/toggle (벤딩토글)
- POST /work-orders/{id}/issues (이슈등록)
- PATCH /work-orders/{id}/issues/{issueId}/resolve (이슈해결)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* 작업지시 테이블 (Production Work Orders)
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('work_orders', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('tenant_id')->comment('테넌트ID');
|
||||
$table->string('work_order_no', 50)->comment('작업지시번호');
|
||||
$table->unsignedBigInteger('sales_order_id')->nullable()->comment('수주ID');
|
||||
$table->string('project_name', 200)->nullable()->comment('프로젝트명');
|
||||
$table->string('process_type', 30)->comment('공정유형: screen/slat/bending');
|
||||
$table->string('status', 30)->default('unassigned')->comment('상태: unassigned/pending/waiting/in_progress/completed/shipped');
|
||||
$table->unsignedBigInteger('assignee_id')->nullable()->comment('담당자ID');
|
||||
$table->unsignedBigInteger('team_id')->nullable()->comment('팀ID');
|
||||
$table->date('scheduled_date')->nullable()->comment('예정일');
|
||||
$table->timestamp('started_at')->nullable()->comment('작업시작일시');
|
||||
$table->timestamp('completed_at')->nullable()->comment('작업완료일시');
|
||||
$table->timestamp('shipped_at')->nullable()->comment('출하일시');
|
||||
$table->text('memo')->nullable()->comment('메모');
|
||||
$table->boolean('is_active')->default(true)->comment('활성여부');
|
||||
$table->unsignedBigInteger('created_by')->nullable()->comment('생성자');
|
||||
$table->unsignedBigInteger('updated_by')->nullable()->comment('수정자');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// Indexes
|
||||
$table->unique(['tenant_id', 'work_order_no'], 'uq_work_orders_tenant_no');
|
||||
$table->index(['tenant_id', 'status'], 'idx_work_orders_tenant_status');
|
||||
$table->index(['tenant_id', 'process_type'], 'idx_work_orders_tenant_process');
|
||||
$table->index(['tenant_id', 'assignee_id'], 'idx_work_orders_tenant_assignee');
|
||||
$table->index(['tenant_id', 'scheduled_date'], 'idx_work_orders_tenant_scheduled');
|
||||
$table->index(['tenant_id', 'is_active'], 'idx_work_orders_tenant_active');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('work_orders');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* 작업지시 품목 테이블 (Work Order Items)
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('work_order_items', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('work_order_id')->comment('작업지시ID');
|
||||
$table->unsignedBigInteger('item_id')->nullable()->comment('품목ID');
|
||||
$table->string('item_name', 200)->comment('품목명');
|
||||
$table->string('specification', 500)->nullable()->comment('규격');
|
||||
$table->decimal('quantity', 12, 2)->default(1)->comment('수량');
|
||||
$table->string('unit', 20)->nullable()->comment('단위');
|
||||
$table->integer('sort_order')->default(0)->comment('정렬순서');
|
||||
$table->timestamps();
|
||||
|
||||
// Foreign Keys
|
||||
$table->foreign('work_order_id')
|
||||
->references('id')
|
||||
->on('work_orders')
|
||||
->onDelete('cascade');
|
||||
|
||||
// Indexes
|
||||
$table->index(['work_order_id', 'sort_order'], 'idx_work_order_items_order_sort');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('work_order_items');
|
||||
}
|
||||
};
|
||||
@@ -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
|
||||
{
|
||||
/**
|
||||
* 작업지시 벤딩 상세 테이블 (Bending Process Details)
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('work_order_bending_details', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('work_order_id')->comment('작업지시ID');
|
||||
|
||||
// 벤딩 공정 세부 항목
|
||||
$table->boolean('shaft_cutting')->default(false)->comment('샤프트 절단');
|
||||
$table->boolean('bearing')->default(false)->comment('베어링');
|
||||
$table->boolean('shaft_welding')->default(false)->comment('샤프트 용접');
|
||||
$table->boolean('assembly')->default(false)->comment('조립');
|
||||
$table->boolean('winder_welding')->default(false)->comment('와인더 용접');
|
||||
$table->boolean('frame_assembly')->default(false)->comment('프레임 조립');
|
||||
$table->boolean('bundle_assembly')->default(false)->comment('번들 조립');
|
||||
$table->boolean('motor_assembly')->default(false)->comment('모터 조립');
|
||||
$table->boolean('bracket_assembly')->default(false)->comment('브라켓 조립');
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// Foreign Keys
|
||||
$table->foreign('work_order_id')
|
||||
->references('id')
|
||||
->on('work_orders')
|
||||
->onDelete('cascade');
|
||||
|
||||
// Unique (1:1 관계)
|
||||
$table->unique('work_order_id', 'uq_bending_details_work_order');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('work_order_bending_details');
|
||||
}
|
||||
};
|
||||
@@ -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
|
||||
{
|
||||
/**
|
||||
* 작업지시 이슈 테이블 (Work Order Issues)
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('work_order_issues', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('work_order_id')->comment('작업지시ID');
|
||||
$table->string('title', 200)->comment('이슈 제목');
|
||||
$table->text('description')->nullable()->comment('이슈 설명');
|
||||
$table->string('priority', 20)->default('medium')->comment('우선순위: high/medium/low');
|
||||
$table->string('status', 30)->default('open')->comment('상태: open/in_progress/resolved');
|
||||
$table->unsignedBigInteger('reported_by')->nullable()->comment('보고자ID');
|
||||
$table->unsignedBigInteger('resolved_by')->nullable()->comment('해결자ID');
|
||||
$table->timestamp('resolved_at')->nullable()->comment('해결일시');
|
||||
$table->timestamps();
|
||||
|
||||
// Foreign Keys
|
||||
$table->foreign('work_order_id')
|
||||
->references('id')
|
||||
->on('work_orders')
|
||||
->onDelete('cascade');
|
||||
|
||||
// Indexes
|
||||
$table->index(['work_order_id', 'status'], 'idx_work_order_issues_order_status');
|
||||
$table->index(['work_order_id', 'priority'], 'idx_work_order_issues_order_priority');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('work_order_issues');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user