2025-12-19 16:02:48 +09:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Models;
|
|
|
|
|
|
|
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
|
|
|
|
|
class Price extends Model
|
|
|
|
|
{
|
|
|
|
|
use SoftDeletes;
|
|
|
|
|
|
|
|
|
|
protected $table = 'prices';
|
|
|
|
|
|
|
|
|
|
protected $fillable = [
|
|
|
|
|
'tenant_id',
|
|
|
|
|
'item_type_code',
|
|
|
|
|
'item_id',
|
|
|
|
|
'client_group_id',
|
|
|
|
|
'purchase_price',
|
|
|
|
|
'processing_cost',
|
|
|
|
|
'loss_rate',
|
|
|
|
|
'margin_rate',
|
|
|
|
|
'sales_price',
|
|
|
|
|
'rounding_rule',
|
|
|
|
|
'rounding_unit',
|
|
|
|
|
'supplier',
|
|
|
|
|
'effective_from',
|
|
|
|
|
'effective_to',
|
|
|
|
|
'note',
|
|
|
|
|
'status',
|
|
|
|
|
'is_final',
|
|
|
|
|
'finalized_at',
|
|
|
|
|
'finalized_by',
|
|
|
|
|
'created_by',
|
|
|
|
|
'updated_by',
|
|
|
|
|
'deleted_by',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
protected function casts(): array
|
|
|
|
|
{
|
|
|
|
|
return [
|
|
|
|
|
'purchase_price' => 'decimal:4',
|
|
|
|
|
'processing_cost' => 'decimal:4',
|
|
|
|
|
'loss_rate' => 'decimal:2',
|
|
|
|
|
'margin_rate' => 'decimal:2',
|
|
|
|
|
'sales_price' => 'decimal:4',
|
|
|
|
|
'rounding_unit' => 'integer',
|
|
|
|
|
'effective_from' => 'date',
|
|
|
|
|
'effective_to' => 'date',
|
|
|
|
|
'is_final' => 'boolean',
|
|
|
|
|
'finalized_at' => 'datetime',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 상태 상수
|
|
|
|
|
*/
|
|
|
|
|
public const STATUS_DRAFT = 'draft';
|
|
|
|
|
|
|
|
|
|
public const STATUS_ACTIVE = 'active';
|
|
|
|
|
|
|
|
|
|
public const STATUS_INACTIVE = 'inactive';
|
|
|
|
|
|
|
|
|
|
public const STATUS_FINALIZED = 'finalized';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 품목 유형 상수
|
|
|
|
|
*/
|
|
|
|
|
public const ITEM_TYPE_PRODUCT = 'PRODUCT';
|
|
|
|
|
|
|
|
|
|
public const ITEM_TYPE_MATERIAL = 'MATERIAL';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 반올림 규칙 상수
|
|
|
|
|
*/
|
|
|
|
|
public const ROUNDING_ROUND = 'round';
|
|
|
|
|
|
|
|
|
|
public const ROUNDING_CEIL = 'ceil';
|
|
|
|
|
|
|
|
|
|
public const ROUNDING_FLOOR = 'floor';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 특정 품목의 현재 유효 단가 조회
|
|
|
|
|
*/
|
|
|
|
|
public static function getCurrentPrice(
|
|
|
|
|
int $tenantId,
|
|
|
|
|
string $itemTypeCode,
|
|
|
|
|
int $itemId,
|
|
|
|
|
?int $clientGroupId = null
|
|
|
|
|
): ?self {
|
|
|
|
|
return static::where('tenant_id', $tenantId)
|
|
|
|
|
->where('item_type_code', $itemTypeCode)
|
|
|
|
|
->where('item_id', $itemId)
|
|
|
|
|
->where(function ($query) use ($clientGroupId) {
|
|
|
|
|
if ($clientGroupId) {
|
|
|
|
|
$query->where('client_group_id', $clientGroupId)
|
|
|
|
|
->orWhereNull('client_group_id');
|
|
|
|
|
} else {
|
|
|
|
|
$query->whereNull('client_group_id');
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
->where('status', self::STATUS_ACTIVE)
|
|
|
|
|
->where('effective_from', '<=', now())
|
|
|
|
|
->where(function ($query) {
|
|
|
|
|
$query->whereNull('effective_to')
|
|
|
|
|
->orWhere('effective_to', '>=', now());
|
|
|
|
|
})
|
|
|
|
|
->orderByRaw('client_group_id IS NULL') // 고객그룹 지정된 것 우선
|
|
|
|
|
->orderBy('effective_from', 'desc')
|
|
|
|
|
->first();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 품목 코드로 현재 유효 판매단가 조회
|
|
|
|
|
* (quote_formula_items.item_code와 연동용)
|
|
|
|
|
*/
|
|
|
|
|
public static function getSalesPriceByItemCode(int $tenantId, string $itemCode): float
|
|
|
|
|
{
|
2025-12-22 22:48:03 +09:00
|
|
|
// items 테이블에서 품목 코드로 검색 (products + materials 통합 테이블)
|
|
|
|
|
$item = DB::table('items')
|
2025-12-19 16:02:48 +09:00
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->where('code', $itemCode)
|
|
|
|
|
->whereNull('deleted_at')
|
|
|
|
|
->first();
|
|
|
|
|
|
2025-12-22 22:48:03 +09:00
|
|
|
if (! $item) {
|
|
|
|
|
return 0;
|
2025-12-19 16:02:48 +09:00
|
|
|
}
|
|
|
|
|
|
2025-12-22 22:48:03 +09:00
|
|
|
$price = static::getCurrentPrice($tenantId, $item->item_type, $item->id);
|
2025-12-19 16:02:48 +09:00
|
|
|
|
2025-12-22 22:48:03 +09:00
|
|
|
return (float) ($price?->sales_price ?? 0);
|
2025-12-19 16:02:48 +09:00
|
|
|
}
|
|
|
|
|
}
|