다크모드
매입 P3(선지급)/P6(미식별출금) — FE 메인테이너 참고
정본 설계:
docs/superpowers/specs/2026-07-07-purchasing-p3-p6-design.md. BE 계약은docs/handoff/backend/purchasing-p3-p6.md참고. P1/P2 기반 구조(라우트·컴포넌트 트리 기본형)는docs/handoff/frontend/purchasing-p1-p2.md를 먼저 읽어야 한다 — 이 문서는 그 위에 얹힌 확장(신규 컴포넌트 3개 + 기존 2개 수정)만 다룬다. 신규 라우트 없음 — 전부/purchasing/console/payment안에서 확장.
1. 컴포넌트 트리 확장
src/components/purchasing/console/payment/
├── MainOrg.vue — (수정) PrepaidStatusOrg·DisbursementQueueOrg 배치
│ + DialogRegisterDisbursementArt/DialogIdentifyDisbursementArt 마운트
│ + paymentVouchers() 4종 통합(회계 전기 버튼)
├── blocks/
│ ├── DynamicTableOrg.vue — (무변경)
│ ├── PrepaidStatusOrg.vue — (신규) 선지급 현황 — vendor별 선급금 잔액 + [상계] 버튼
│ └── DisbursementQueueOrg.vue — (신규) 미식별출금 큐 — 풀 목록 + [식별] 버튼(emit)
└── overlays/
├── DialogOffsetArt.vue — (수정) 초과 차단 제거·toPrepaidPreview 계산·안내문 교체
├── DialogPaymentConfirmArt.vue — (수정) 0131 DR 라인 조건부 추가·"선급금 전환액" 행
├── DialogRegisterDisbursementArt.vue — (신규) 미식별출금 등록 폼
└── DialogIdentifyDisbursementArt.vue — (신규) 식별 다이얼로그(용도 3분기)2. 소비 컴포저블 확장
2-1. usePurchases() 신규 노출
js
const {
creditPrepaid,
debitPrepaid,
applyPrepaid,
prepaidBalanceByVendor,
prepaidLedger,
prepaidLedgerVendors,
getAutoApplyPrepaid,
setAutoApplyPrepaid,
} = usePurchases();콘솔이 직접 호출하는 건 prepaidBalanceByVendor()(조회)와 applyPrepaid(vendorCode)(상계 액션) 뿐 — creditPrepaid/debitPrepaid는 usePayments가 내부적으로 소비(화면에서 직접 호출하지 않음, P1/P2의 pay/peekPaid/unpay 프라이빗 컨벤션 그대로).
2-2. usePayments() 신규 노출
js
const {
disbursements,
recordDisbursement,
disbursementBalance,
reclassifyDisbursement,
cancelDisbursement,
} = usePayments();DialogRegisterDisbursementArt→recordDisbursement(...).DisbursementQueueOrg→disbursementBalance()(인자 없음 = 현재 풀 스냅샷만,asOf파생은 화면에서 아직 미사용).DialogIdentifyDisbursementArt→reclassifyDisbursement(id, {vendorCode, purpose, accountCode}, at).cancelDisbursement: 노출은 돼 있으나 화면 버튼 미배선(§7 확장 포인트,cancelPayment선례와 동일한 패턴).
2-3. usePurchaseJournal() 신규 노출
js
const { vouchersPrepaidApply, vouchersDisbursement, vouchersReclassDisbursement } =
usePurchaseJournal();payment MainOrg.vue의 paymentVouchers()가 vouchersPayment + vouchersPrepaidApply + vouchersDisbursement + vouchersReclassDisbursement 4종을 합쳐 "회계 전기" 버튼의 소스로 쓴다(★Task4 T3 Minor — 종전엔 vouchersPayment만 열거해 P3/P6/P-reclass 전표가 전기 불가능한 "미아 전표"였다).
3. 데이터 흐름
3-1. 선지급(초과 지급) 흐름
DialogOffsetArt: 금액 입력 → allocationPreview(FIFO 미리보기) + toPrepaidPreview(= amount - appliedTotal)
exceeds=true여도 canProceed는 막지 않음(구 가드 폐기) → alert-info-subtle "초과분은 선급금으로 전환돼요"
[다음] → emit('draft', {..., breakdown, toPrepaid: toPrepaidPreview})
→ MainOrg: paymentDraft = draft
→ DialogPaymentConfirmArt(:draft) → debitLines에 0131 조건부 추가(draft.toPrepaid > 0)
→ confirm() → usePayments().recordPayment(draft) → { ok:true, applied, toPrepaid, appliedBreakdown }
→ PrepaidStatusOrg가 자동 재렌더(prepaidBalanceByVendor() reactive 재계산)3-2. 선급금 상계 흐름
PrepaidStatusOrg: [상계] 클릭(hasOpenPayable(vendorCode) === true인 행만 활성)
→ usePurchases().applyPrepaid(vendorCode) → 내부에서 pay() FIFO + debitPrepaid(kind:'상계')
→ payablesByVendor()/prepaidBalanceByVendor() 둘 다 reactive 갱신 → 화면 자동 반영3-3. 미식별출금 등록 → 큐 → 식별 흐름
DialogRegisterDisbursementArt: 등록 폼(amount>0 폼단 가드) → recordDisbursement(...) → emit('registered')
→ suspenseDisbursementPool에 적재 → DisbursementQueueOrg가 disbursementBalance() 재계산해 즉시 표시
DisbursementQueueOrg: 행의 [식별] 클릭 → emit('identify', id)
→ MainOrg: identifyTargetId = id → dialog-identify-disbursement-art showModal()
→ DialogIdentifyDisbursementArt(:disbursement-id): watch(disbursementId)로 폼 리셋
→ purpose(지급/선급/경비) + 분기별 필수 필드(지급·선급→vendorCode / 경비→accountCode)
→ [식별 확정] → reclassifyDisbursement(id, {...}, target.disbursementDate) → emit('identified')
→ MainOrg: identifyTargetId = null → 큐에서 해당 항목 자동 제거(풀에서 splice됨)두 흐름 모두 prop+emit 릴레이만 사용 — 별도 store 없음(P1/P2 §4 컨벤션 그대로).
4. 회계 게이팅
useModuleSubscription().accountingEnabled — P1/P2와 동일 원칙, 이번 확장이 추가한 4종 전표(P3/P-adv-apply/P6/P-reclass)도 전부 같은 게이트 아래 있다:
payment/MainOrg.vue의 "회계 전기" 버튼(v-if="accountingEnabled")이paymentVouchers()(4종 통합) 기준unpostedCount를 계산.PrepaidStatusOrg/DisbursementQueueOrg자체는 게이팅 없음(회계 모듈 미신청이어도 선급금/미식별출금 "업무" 조회·액션은 그대로 가능 — 회계 전표 전기만 게이팅 대상, P1/P2 vendor-ledger 선례와 동형 판단).
5. DS 패턴
PrepaidStatusOrg/DisbursementQueueOrg:card card-sm평면 카드(비접힘) — billingadvance-receipt콘솔(선수금/가수금 현황·큐)의 정확한 미러. 요약 수치는 카드 우측 상단(합계/badge-warning-moderate건수), CLAUDE.md 카드 규율 §8-3 동형.DialogIdentifyDisbursementArt:dialog-md—Select(용도 enum) + 분기별 조건부 필드(v-if="form.purpose !== '경비'"/v-else) +alert-info-subtle("현금은 이미 유출됐어요" — 이중계상 금지 안내, 사용자에게도 회계적 사실을 투명하게 전달).DialogRegisterDisbursementArt:dialog-md— 단순 등록 폼,badge-sm badge-warning-moderate"P6" 태그(billing 가수금 등록 다이얼로그의 배지 어휘 그대로).DialogOffsetArt의 안내 alert 전환: 구alert-error-subtle("채무 초과", 차단) → 신alert-info-subtle("초과분은 선급금으로 전환돼요", 비차단) — 색상까지 의도가 바뀐 것을 반영(에러가 아니라 정상 분기라는 신호).
6. 회귀0 가드
seedDemoDisbursements()도 P1/P2 선례(seedDemoPurchases/seedDemoPayments) 그대로 main.js 부트스트랩에서만 호출 — 모듈 로드 시 자동 소비 안 함.resetPurchases()/resetPayments()가 신규 상태(prepaid*, disbursement*, suspenseDisbursementPool)까지 전부 초기화 — 기존 스펙의beforeEach가 이미 이 두 함수를 호출하므로 별도 조치 불요하나, 신규 스펙 작성 시 반드시 두 reset을 그대로 호출(부분 reset 금지).
7. 테스트 위치 (신규/수정)
src/composables/__tests__/usePurchases.spec.js — (+) 선급금 creditPrepaid/debitPrepaid/applyPrepaid
src/composables/__tests__/usePayments.spec.js — (+) recordDisbursement/reclassifyDisbursement/cancelDisbursement
src/composables/__tests__/usePurchaseJournal.spec.js — (+) vouchersPrepaidApply/vouchersDisbursement/vouchersReclassDisbursement·GL대사
src/components/purchasing/console/payment/blocks/__tests__/PrepaidStatusOrg.spec.js — (신규)
src/components/purchasing/console/payment/blocks/__tests__/DisbursementQueueOrg.spec.js — (신규)
src/components/purchasing/console/payment/overlays/__tests__/DialogRegisterDisbursementArt.spec.js — (신규)
src/components/purchasing/console/payment/overlays/__tests__/DialogIdentifyDisbursementArt.spec.js — (신규)
src/components/purchasing/console/payment/overlays/__tests__/DialogOffsetArt.spec.js — (수정, 초과가드 테스트 재작성)
src/components/purchasing/console/payment/overlays/__tests__/DialogPaymentConfirmArt.spec.js — (+)
src/components/purchasing/console/payment/__tests__/MainOrg.spec.js — (+)8. 확장 포인트
- 채무 없는 완전 신규 거래처의 선지급 UI 노출:
DialogOffsetArt.vendorOptions는usePurchases().payableBalanceByVendor()(열린 채무 보유 거래처만) 파생이라, 매입 이력이 전혀 없는 vendorCode는 Select 옵션에 나타나지 않는다. 컴포저블은 이 케이스를 지원(BE 핸드오프 §5)하지만 화면에서 도달할 경로가 없다. 개선 시useVendorLedger.vendorCodes()(전체 거래처,DialogIdentifyDisbursementArt가 이미 이 소스를 씀) 또는 transaction 콘솔처럼 "신규 거래처 직접 입력" 필드를 추가하는 방향 검토. - 선급금 환급(P-adv-refund) UI: BE에 refund 액션 자체가 없다(스코프아웃). 추가되면
PrepaidStatusOrg에 [환급] 버튼 + 확인 다이얼로그,usePurchaseJournal에 현금 라인 있는 신규 전표(P-adv-refund, DR 0103/CR 0131) 파생 추가. - 미식별출금 재분류 취소 UI:
usePayments().cancelDisbursement(id)는 구현돼 있으나DisbursementQueueOrg/식별된 항목 어디에도 취소 버튼이 없다. 추가 시 재분류된 항목을 어디서 보여줄지(현재 큐는 "미귀속 풀"만 보여줘 식별 완료 건은 화면에서 사라짐 — 별도 "재분류 이력" 뷰가 먼저 필요할 수 있음) 판단 필요. - 자동 상계 토글 UI:
getAutoApplyPrepaid/setAutoApplyPrepaid는 컴포저블에 있으나 이를 끄고 켜는 화면 컨트롤이 없다(항상 기본값 true로 동작 — [상계] 버튼 수동 클릭에만 의존, 자동 배선 트리거 자체가 없어 이 토글이 사실상 무의미한 상태). "자동 상계"를 실제로 자동화하려면recordPurchase()직후 또는 배치 잡에서applyPrepaid호출 지점 신설 필요. - 거래처명 마스터 연결: P1/P2와 동일 후속(선지급 현황·미식별출금 식별 다이얼로그의 vendorCode 표시도 이름 마스터 도입 시 함께 교체).