docs: [numbering] 채번규칙 문서 업데이트

- MNG 채번규칙 관리 가이드 추가
- 신규 규칙 생성 템플릿 5종 추가 (원자재로트, 견적, 수주, 작업지시, 매출)
- ReceivingService 연동 내용 추가
- 현재 등록 현황 (프론트_테스트회사)
This commit is contained in:
김보곤
2026-03-17 20:25:59 +09:00
parent 3c2f1865a0
commit 9b6d5bebc9

View File

@@ -1,19 +1,24 @@
# 채번규칙 (Numbering Rules)
> **상태**: 내부 서비스 (직접 API 없음)
> **최종 갱신**: 2026-02-27
> **작성일**: 2026-02-27
> **상태**: 운영 중
> **최종 갱신**: 2026-03-17
---
## 1. 개요
문서 번호(견적번호, 수주번호 등)를 규칙 기반으로 자동 생성하는 내부 서비스. 테넌트별로 채번 규칙을 설정하면, 해당 규칙에 따라 일련번호가 자동 생성된다. 규칙이 없는 경우 레거시 포맷으로 폴백.
### 1.1 목적
문서 번호(견적번호, 수주번호, 원자재 로트번호 등)를 규칙 기반으로 자동 생성하는 내부 서비스. 테넌트별로 채번 규칙을 설정하면, 해당 규칙에 따라 일련번호가 자동 생성된다. 규칙이 없는 경우 레거시 포맷으로 폴백.
### 1.2 핵심 원칙
**핵심 기능:**
- 유연한 패턴 기반 번호 생성 (6가지 세그먼트 유형)
- Atomic UPSERT로 동시성 안전 시퀀스 관리
- 기간별 자동 리셋 (일/월/년/무제한)
- 미리보기 기능 (DB 업데이트 없음)
- 규칙 미설정 시 레거시 로직 자동 폴백
---
@@ -22,11 +27,26 @@
| 모델 | 테이블 | 설명 |
|------|--------|------|
| `NumberingRule` | `numbering_rules` | 채번 규칙 정의 (document_type, pattern, reset_period) |
| `NumberingSequence` | `numbering_sequences` | 일련번호 카운터 (tenant + type + scope + period) |
| | `numbering_sequences` | 일련번호 카운터 (tenant + type + scope + period) |
**지원 문서 유형:** quote, order, sale, work_order, material_receipt
**지원 문서 유형:**
**리셋 주기:** daily, monthly, yearly, never
| 코드 | 한글 | 사용처 |
|------|------|--------|
| `quote` | 견적 | `QuoteNumberService` |
| `order` | 수주 | `OrderService` |
| `sale` | 매출 | (예정) |
| `work_order` | 작업지시 | (예정) |
| `material_receipt` | 원자재수입검사 | `ReceivingService` |
**리셋 주기:**
| 코드 | 설명 | period_key 예시 |
|------|------|----------------|
| `daily` | 매일 01부터 리셋 | `260317` |
| `monthly` | 매월 01부터 리셋 | `202603` |
| `yearly` | 매년 01부터 리셋 | `2026` |
| `never` | 리셋 없이 계속 증가 | `all` |
---
@@ -34,67 +54,259 @@
패턴은 JSON 배열로 세그먼트를 정의한다.
### 3.1 세그먼트 유형
| 세그먼트 | 설명 | 예시 |
|---------|------|------|
| `static` | 고정 문자열 | `{ "type": "static", "value": "QT" }` |
| `date` | 날짜 포맷 | `{ "type": "date", "format": "ymd" }``260227` |
| `sequence` | 일련번호 | `{ "type": "sequence", "padding": 4 }``0001` |
| `static` | 고정 문자열 | `{ "type": "static", "value": "KD" }` |
| `separator` | 구분자 | `{ "type": "separator", "value": "-" }` |
| `param` | 외부 파라미터 | `{ "type": "param", "key": "product_category" }` |
| `mapping` | 값 매핑 | `{ "type": "mapping", "key": "category", "map": {"A": "PR"} }` |
| `date` | 날짜 포맷 (PHP date) | `{ "type": "date", "format": "ymd" }``260317` |
| `sequence` | 일련번호 (자릿수는 rule 레벨) | `{ "type": "sequence" }` |
| `param` | 외부 파라미터 | `{ "type": "param", "key": "pair_code", "default": "SS" }` |
| `mapping` | 값 → 코드 매핑 | `{ "type": "mapping", "key": "category", "map": {"SCREEN": "SC"}, "default": "XX" }` |
### 3.2 date 포맷 예시
| format | 결과 | 설명 |
|--------|------|------|
| `ymd` | `260317` | 2자리 연+월+일 |
| `Ymd` | `20260317` | 4자리 연+월+일 |
| `ym` | `2603` | 2자리 연+월 |
| `Y` | `2026` | 4자리 연도 |
---
## 4. MNG 채번규칙 관리
### 4.1 접근 경로
```
MNG > 권한 관리 > 채번 규칙 관리
URL: admin.codebridge-x.com/numbering-rules
```
### 4.2 관리 화면 기능
| 기능 | 설명 |
|------|------|
| 목록 조회 | 문서유형, 상태 필터 + 규칙명 검색 |
| 새 규칙 | 패턴 세그먼트 편집기 + 실시간 미리보기 |
| 수정 | 기존 규칙의 패턴, 리셋주기, 자릿수 변경 |
| 삭제 | 규칙 삭제 (Hard Delete) |
### 4.3 신규 규칙 생성 절차
1. **+ 새 규칙** 버튼 클릭
2. **기본 정보** 입력:
- 규칙명: 관리용 이름 (예: `원자재 로트번호`)
- 문서유형: 드롭다운 선택 (테넌트당 유형별 1개만 가능)
- 리셋 주기: 일별 / 월별 / 연별 / 무제한
- 시퀀스 자릿수: 2 → `01,02` / 3 → `001,002` / 4 → `0001,0002`
3. **패턴 세그먼트** 구성:
- `+ 세그먼트 추가` 버튼으로 세그먼트를 순서대로 추가
- 각 세그먼트의 타입과 값 설정
4. **미리보기** 확인: 세그먼트 변경 시 실시간 미리보기 표시
5. **생성** 버튼으로 저장
> **주의**: 테넌트당 문서유형별 1개 규칙만 가능하다. 이미 등록된 유형은 선택 불가.
---
## 5. 신규 규칙 생성 템플릿
아래는 자주 사용하는 채번 패턴 템플릿이다. MNG에서 새 규칙 생성 시 참고한다.
### 5.1 원자재 로트번호 (YYMMDD-NN)
> 5130 레거시 방식 차용. 일별 시퀀스 리셋.
| 항목 | 값 |
|------|------|
| 규칙명 | `원자재 로트번호` |
| 문서유형 | `material_receipt` (원자재수입검사) |
| 리셋 주기 | `daily` (일별) |
| 시퀀스 자릿수 | `2` |
**패턴:**
```json
[
{ "type": "date", "format": "ymd" },
{ "type": "separator", "value": "-" },
{ "type": "sequence" }
]
```
**결과:** `260317-01`, `260317-02`, ... → 다음날 `260318-01`
### 5.2 견적번호 (KD-PR-YYMMDD-NN)
| 항목 | 값 |
|------|------|
| 규칙명 | `5130 견적번호` |
| 문서유형 | `quote` (견적) |
| 리셋 주기 | `daily` |
| 시퀀스 자릿수 | `2` |
**패턴:**
**패턴 예시:**
```json
[
{ "type": "static", "value": "KD" },
{ "type": "separator", "value": "-" },
{ "type": "mapping", "key": "category", "map": { "A": "PR" }, "default": "XX" },
{ "type": "static", "value": "PR" },
{ "type": "separator", "value": "-" },
{ "type": "date", "format": "ymd" },
{ "type": "separator", "value": "-" },
{ "type": "sequence", "padding": 2 }
{ "type": "sequence" }
]
```
`KD-PR-260227-01`
---
**결과:** `KD-PR-260317-01`
## 4. 서비스
### 5.3 수주 로트번호 (KD-{pairCode}-YYMMDD-NN)
| 서비스 | 메서드 | 설명 |
|--------|--------|------|
| `NumberingService` | `generate($documentType, $params)` | 번호 생성 (규칙 없으면 null → 레거시 폴백) |
| | `preview($documentType, $params)` | 미리보기 (시퀀스 증가 없음) |
| `QuoteNumberService` | `generate()` | 견적번호 생성 (NumberingService → 레거시 폴백) |
| | `validate()` | 형식 검증 |
| | `isUnique()` | 중복 체크 |
| 항목 | |
|------|------|
| 규칙명 | `5130 수주 로트번호` |
| 문서유형 | `order` (수주) |
| 리셋 주기 | `daily` |
| 시퀀스 자릿수 | `2` |
**레거시 포맷:** `QT{YYYYMMDD}{NNNN}` (예: `QT202602270001`)
**패턴:**
---
## 5. 동시성 처리
```sql
INSERT INTO numbering_sequences (tenant_id, document_type, scope_key, period_key, last_sequence)
VALUES (?, ?, ?, ?, 1)
ON DUPLICATE KEY UPDATE last_sequence = last_sequence + 1
```json
[
{ "type": "static", "value": "KD" },
{ "type": "separator", "value": "-" },
{ "type": "param", "key": "pair_code", "default": "SS" },
{ "type": "separator", "value": "-" },
{ "type": "date", "format": "ymd" },
{ "type": "separator", "value": "-" },
{ "type": "sequence" }
]
```
MySQL의 `UPSERT`를 사용하여 동시 요청에서도 시퀀스 충돌 없이 안전하게 번호 생성.
**결과:** `KD-SS-260317-01`, `KD-TE-260317-01` (pairCode별 독립 시퀀스)
### 5.4 작업지시번호 (WO-YYYYMMDD-NNNN)
| 항목 | 값 |
|------|------|
| 규칙명 | `작업지시번호` |
| 문서유형 | `work_order` (작업지시) |
| 리셋 주기 | `daily` |
| 시퀀스 자릿수 | `4` |
**패턴:**
```json
[
{ "type": "static", "value": "WO" },
{ "type": "separator", "value": "-" },
{ "type": "date", "format": "Ymd" },
{ "type": "separator", "value": "-" },
{ "type": "sequence" }
]
```
**결과:** `WO-20260317-0001`
### 5.5 월별 리셋 예시 (INV-YYYYMM-NNN)
| 항목 | 값 |
|------|------|
| 규칙명 | `매출번호` |
| 문서유형 | `sale` (매출) |
| 리셋 주기 | `monthly` |
| 시퀀스 자릿수 | `3` |
**패턴:**
```json
[
{ "type": "static", "value": "INV" },
{ "type": "separator", "value": "-" },
{ "type": "date", "format": "Ym" },
{ "type": "separator", "value": "-" },
{ "type": "sequence" }
]
```
**결과:** `INV-202603-001` → 4월 리셋 → `INV-202604-001`
---
## 6. 호출 위치
## 6. 서비스 연동
직접 API 엔드포인트는 없으며, 아래 서비스에서 내부 호출된다:
### 6.1 호출 구조
| 서비스 | 용도 |
|--------|------|
| `QuoteNumberService` | 견적번호 생성 |
| `OrderService` | 수주번호 생성 |
| `WorkOrderService` | 작업지시번호 생성 |
| `MaterialReceiptService` | 입고번호 생성 |
```
호출 서비스 → NumberingService.generate(documentType, params)
├─ 규칙 있음 → 패턴 기반 생성 (Atomic UPSERT)
└─ 규칙 없음 → null 반환 → 호출 서비스가 레거시 로직 사용
```
### 6.2 현재 연동 서비스
| 서비스 | 문서유형 | 레거시 폴백 |
|--------|---------|------------|
| `QuoteNumberService` | `quote` | `QT{YYYYMMDD}{NNNN}` |
| `OrderService` | `order` | `ORD{YYYYMMDD}{NNNN}` |
| `ReceivingService` | `material_receipt` | `YYMMDD-NN` (DB 시퀀스) |
### 6.3 연동 코드 패턴
새로운 서비스에서 채번규칙을 사용하려면 아래 패턴을 따른다:
```php
// 1. NumberingService 호출
$numberingService = app(NumberingService::class);
$numberingService->setContext($this->tenantId(), $this->apiUserId());
// 2. 규칙 기반 생성 시도
$number = $numberingService->generate('document_type', [
'param_key' => 'value', // param/mapping 세그먼트용
]);
// 3. 규칙 없으면 레거시 폴백
if ($number !== null) {
return $number;
}
return $this->generateLegacy();
```
---
## 7. 동시성 처리
```sql
INSERT INTO numbering_sequences
(tenant_id, document_type, scope_key, period_key, last_sequence, created_at, updated_at)
VALUES (?, ?, ?, ?, 1, NOW(), NOW())
ON DUPLICATE KEY UPDATE
last_sequence = last_sequence + 1, updated_at = NOW()
```
MySQL의 `ON DUPLICATE KEY UPDATE`로 Atomic 연산을 보장한다. 동시 요청에서도 시퀀스 충돌 없이 안전하게 번호를 생성한다.
**scope_key 분리**: `param`, `mapping` 세그먼트 값이 scope_key로 저장되어, 파라미터별 독립 시퀀스를 유지한다.
예: 수주 `KD-SS-260317-01``KD-TE-260317-01`은 각각 독립 시퀀스.
---
## 8. 현재 등록 현황
### 프론트_테스트회사 (tenant_id: 287)
| # | 규칙명 | 문서유형 | 패턴 미리보기 | 리셋 | 자릿수 |
|---|--------|---------|-------------|------|:------:|
| 1 | 5130 견적번호 | quote | `KD-PR-260317-01` | 일별 | 2 |
| 2 | 5130 수주 로트번호 | order | `KD-SS-260317-01` | 일별 | 2 |
| 3 | 원자재 로트번호 | material_receipt | `260317-01` | 일별 | 2 |
> 신규 테넌트에 규칙이 없으면 각 서비스의 레거시 로직이 자동 적용된다.
---
@@ -105,4 +317,4 @@ MySQL의 `UPSERT`를 사용하여 동시 요청에서도 시퀀스 충돌 없이
---
**최종 업데이트**: 2026-02-27
**최종 업데이트**: 2026-03-17