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

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);
}
}