feat: 계좌관리 추가

This commit is contained in:
pro
2026-01-20 20:43:38 +09:00
parent 7246ac003f
commit 0ae3c5aa07
1533 changed files with 5791 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Models\Materials;
use App\Models\Commons\Category;
use App\Models\Commons\File;
use App\Models\Commons\Tag;
use App\Models\Qualitys\Lot;
use App\Traits\BelongsToTenant;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* @mixin IdeHelperMaterial
*/
class Material extends Model
{
use BelongsToTenant, ModelTrait, SoftDeletes;
protected $fillable = [
'tenant_id',
'category_id',
'name',
'item_name',
'specification',
'material_code',
'material_type',
'unit',
'is_inspection',
'search_tag',
'remarks',
'attributes',
'options',
'created_by',
'updated_by',
'is_active',
];
protected $casts = [
'attributes' => 'array',
'options' => 'array',
'is_active' => 'boolean',
];
protected $hidden = [
'deleted_at',
];
// 카테고리
public function category()
{
return $this->belongsTo(Category::class);
}
// 자재 입고 내역
public function receipts()
{
return $this->hasMany(MaterialReceipt::class, 'material_id');
}
// 로트 관리
public function lots()
{
return $this->hasMany(Lot::class, 'material_id');
}
// 파일 목록 (N:M, 폴리모픽)
public function files()
{
return $this->morphMany(File::class, 'fileable');
}
// 태그 목록 (N:M, 폴리모픽)
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}

Binary file not shown.

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Models\Materials;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* @mixin IdeHelperMaterialInspection
*/
class MaterialInspection extends Model
{
use SoftDeletes;
// 입고 내역
public function receipt()
{
return $this->belongsTo(MaterialReceipt::class, 'receipt_id');
}
// 검사 항목
public function items()
{
return $this->hasMany(MaterialInspectionItem::class, 'inspection_id');
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Models\Materials;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* @mixin IdeHelperMaterialInspectionItem
*/
class MaterialInspectionItem extends Model
{
use SoftDeletes;
// 검사 내역
public function inspection()
{
return $this->belongsTo(MaterialInspection::class, 'inspection_id');
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Models\Materials;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* @mixin IdeHelperMaterialReceipt
*/
class MaterialReceipt extends Model
{
use SoftDeletes;
protected $fillable = [
'material_id', 'receipt_date', 'lot_number', 'received_qty', 'unit',
'supplier_name', 'manufacturer_name', 'purchase_price_excl_vat',
'weight_kg', 'status_code', 'is_inspection', 'inspection_date', 'remarks',
];
// 자재 마스터
public function material()
{
return $this->belongsTo(Material::class, 'material_id');
}
// 수입검사 내역
public function inspections()
{
return $this->hasMany(MaterialInspection::class, 'receipt_id');
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,47 @@
<?php
namespace App\Models\Products;
use App\Traits\BelongsToTenant;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* @mixin IdeHelperCommonCode
*/
class CommonCode extends Model
{
use BelongsToTenant, ModelTrait, SoftDeletes;
protected $table = 'common_codes';
protected $fillable = [
'tenant_id',
'code_group',
'code',
'name',
'parent_id',
'attributes',
'description',
'is_active',
'sort_order',
];
protected $casts = [
'attributes' => 'array',
'is_active' => 'boolean',
];
// 관계: 상위 코드
public function parent()
{
return $this->belongsTo(self::class, 'parent_id');
}
// 관계: 하위 코드들
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
}

Binary file not shown.

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Models\Products;
use App\Models\Commons\Tag;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* @mixin IdeHelperPart
*/
class Part extends Model
{
use SoftDeletes;
protected $fillable = ['tenant_id', 'code', 'name', 'category_id', 'part_type_id', 'unit', 'attributes', 'description', 'is_active'];
public function category()
{
return $this->belongsTo(CommonCode::class, 'category_id');
}
public function partType()
{
return $this->belongsTo(CommonCode::class, 'part_type_id');
}
// 태그 목록 (N:M, 폴리모픽)
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,118 @@
<?php
namespace App\Models\Products;
use App\Models\Commons\Category;
use App\Models\Commons\File;
use App\Models\Commons\Tag;
use App\Traits\BelongsToTenant;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Product extends Model
{
use BelongsToTenant, ModelTrait, SoftDeletes;
protected $fillable = [
'tenant_id', 'code', 'name', 'unit', 'category_id',
'product_type', // 라벨/분류용
'attributes', 'attributes_archive', 'options', 'bom', 'description',
'is_sellable', 'is_purchasable', 'is_producible',
// 하이브리드 구조: 최소 고정 필드
'safety_stock', 'lead_time', 'is_variable_size',
'product_category', 'part_type',
// 파일 필드
'bending_diagram', 'bending_details',
'specification_file', 'specification_file_name',
'certification_file', 'certification_file_name',
'certification_number', 'certification_start_date', 'certification_end_date',
'created_by', 'updated_by', 'is_active',
];
protected $casts = [
'attributes' => 'array',
'attributes_archive' => 'array',
'options' => 'array',
'bom' => 'array',
'bending_details' => 'array',
'certification_start_date' => 'date',
'certification_end_date' => 'date',
'is_sellable' => 'boolean',
'is_purchasable' => 'boolean',
'is_producible' => 'boolean',
'is_variable_size' => 'boolean',
'is_active' => 'boolean',
];
protected $hidden = [
'deleted_at',
];
// 분류
public function category()
{
return $this->belongsTo(Category::class, 'category_id');
}
// BOM (자기참조) — 라인 모델 경유
public function componentLines()
{
return $this->hasMany(ProductComponent::class, 'parent_product_id')->orderBy('sort_order');
}
// 라인들
public function parentLines()
{
return $this->hasMany(ProductComponent::class, 'child_product_id');
} // 나를 쓰는 상위 라인들
// 편의: 직접 children/parents 제품에 접근
public function children()
{
return $this->belongsToMany(
self::class, 'product_components', 'parent_product_id', 'child_product_id'
)->withPivot(['quantity', 'sort_order', 'is_default'])
->withTimestamps();
}
public function parents()
{
return $this->belongsToMany(
self::class, 'product_components', 'child_product_id', 'parent_product_id'
)->withPivot(['quantity', 'sort_order', 'is_default'])
->withTimestamps();
}
// 파일 / 태그 (폴리모픽)
public function files()
{
return $this->morphMany(File::class, 'fileable');
}
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
// 스코프
public function scopeType($q, string $type)
{
return $q->where('product_type', $type);
}
public function scopeSellable($q)
{
return $q->where('is_sellable', 1);
}
public function scopePurchasable($q)
{
return $q->where('is_purchasable', 1);
}
public function scopeProducible($q)
{
return $q->where('is_producible', 1);
}
}

Binary file not shown.

View File

@@ -0,0 +1,115 @@
<?php
namespace App\Models\Products;
use App\Models\Materials\Material;
use App\Traits\BelongsToTenant;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class ProductComponent extends Model
{
use BelongsToTenant, ModelTrait, SoftDeletes;
protected $table = 'product_components';
protected $fillable = [
'tenant_id',
'parent_product_id',
'category_id',
'category_name',
'ref_type',
'ref_id',
'quantity',
'sort_order',
// 하이브리드 구조: 고정 필드 (범용 BOM 계산)
'quantity_formula',
'condition',
// 동적 필드 (테넌트별 커스텀)
'attributes',
'created_by',
'updated_by',
];
protected $casts = [
'quantity' => 'decimal:6',
'attributes' => 'array',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
protected $hidden = [
'deleted_at',
];
/**
* 상위 제품 (모델/제품)
*/
public function parentProduct()
{
return $this->belongsTo(Product::class, 'parent_product_id');
}
/**
* 참조된 제품 또는 자재를 동적으로 가져오기
* ref_type에 따라 Product 또는 Material을 반환
*/
public function referencedItem()
{
if ($this->ref_type === 'PRODUCT') {
return $this->belongsTo(Product::class, 'ref_id');
} elseif ($this->ref_type === 'MATERIAL') {
return $this->belongsTo(Material::class, 'ref_id');
}
return null;
}
/**
* 하위 제품 (ref_type = PRODUCT일 때만)
*/
public function product()
{
return $this->belongsTo(Product::class, 'ref_id')
->where('ref_type', 'PRODUCT');
}
/**
* 하위 자재 (ref_type = MATERIAL일 때만)
*/
public function material()
{
return $this->belongsTo(Material::class, 'ref_id')
->where('ref_type', 'MATERIAL');
}
// ---------------------------------------------------
// 🔎 Query Scopes
// ---------------------------------------------------
/**
* 제품 BOM 아이템만
*/
public function scopeProducts($query)
{
return $query->where('ref_type', 'PRODUCT');
}
/**
* 자재 BOM 아이템만
*/
public function scopeMaterials($query)
{
return $query->where('ref_type', 'MATERIAL');
}
/**
* 특정 상위 제품의 BOM
*/
public function scopeForParent($query, int $parentProductId)
{
return $query->where('parent_product_id', $parentProductId);
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More