feat: 테넌트별 채번 규칙 시스템 구현

- numbering_rules 테이블: JSON 패턴 기반 채번 규칙 저장 (tenant별)
- numbering_sequences 테이블: MySQL UPSERT 기반 atomic 시퀀스 관리
- NumberingService: generate/preview/nextSequence 핵심 서비스
- QuoteNumberService: NumberingService 우선, 폴백 QT{YYYYMMDD}{NNNN}
- OrderService: NumberingService 우선 (pair_code 지원), 폴백 ORD{YYYYMMDD}{NNNN}
- StoreOrderRequest: pair_code 필드 추가
- NumberingRuleSeeder: tenant_id=287 견적(KD-PR)/수주(KD-{pairCode}) 규칙

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 09:50:52 +09:00
parent 6318474b6f
commit 78851ec04a
9 changed files with 475 additions and 44 deletions

View File

@@ -14,6 +14,10 @@
class OrderService extends Service
{
public function __construct(
private NumberingService $numberingService
) {}
/**
* 목록 조회 (검색/필터링/페이징)
*/
@@ -145,7 +149,9 @@ public function store(array $data)
return DB::transaction(function () use ($data, $tenantId, $userId) {
// 수주번호 자동 생성
$data['order_no'] = $this->generateOrderNo($tenantId);
$pairCode = $data['pair_code'] ?? null;
unset($data['pair_code']);
$data['order_no'] = $this->generateOrderNo($tenantId, $pairCode);
$data['tenant_id'] = $tenantId;
$data['created_by'] = $userId;
$data['updated_by'] = $userId;
@@ -406,8 +412,29 @@ private function calculateItemAmounts(array &$item): void
/**
* 수주번호 자동 생성
*
* 채번규칙이 있으면 NumberingService 사용 (KD-{pairCode}-{YYMMDD}-{NN}),
* 없으면 레거시 로직 (ORD{YYYYMMDD}{NNNN})
*/
private function generateOrderNo(int $tenantId): string
private function generateOrderNo(int $tenantId, ?string $pairCode = null): string
{
$this->numberingService->setContext($tenantId, $this->apiUserId());
$number = $this->numberingService->generate('order', [
'pair_code' => $pairCode ?? 'SS',
]);
if ($number !== null) {
return $number;
}
return $this->generateOrderNoLegacy($tenantId);
}
/**
* 레거시 수주번호 생성 (ORD{YYYYMMDD}{NNNN})
*/
private function generateOrderNoLegacy(int $tenantId): string
{
$prefix = 'ORD';
$date = now()->format('Ymd');
@@ -456,7 +483,8 @@ public function createFromQuote(int $quoteId, array $data = [])
return DB::transaction(function () use ($quote, $data, $tenantId, $userId) {
// 수주번호 생성
$orderNo = $this->generateOrderNo($tenantId);
$pairCode = $data['pair_code'] ?? null;
$orderNo = $this->generateOrderNo($tenantId, $pairCode);
// Order 모델의 createFromQuote 사용
$order = Order::createFromQuote($quote, $orderNo);