feat: 입고 등록 DevMode 채우기 및 AuthContext 초기값 수정
- DevToolbar에 입고(자재) 버튼 추가, 2행 레이아웃 정리 (회계 | 기준 | 자재를 구분선으로 한 줄 배치) - receivingData 생성기 추가 (품목, 공급업체, 수량 랜덤) - ReceivingDetail에 useDevFill 연동 (로트번호, 작성자 포함) - transformFrontendToApi에서 orderQty 미입력 시 receivingQty 사용 - AuthContext 초기값 null로 변경 (SSR 시 드미트리 하드코딩 제거)
This commit is contained in:
@@ -18,7 +18,8 @@ import React, { createContext, useContext, useState, useCallback, useEffect, Rea
|
||||
export type DevFillPageType =
|
||||
| 'quote' | 'quoteV2' | 'order' | 'workOrder' | 'workOrderComplete' | 'shipment' // 판매/생산 플로우
|
||||
| 'deposit' | 'withdrawal' | 'purchaseApproval' | 'cardTransaction' // 회계 플로우
|
||||
| 'client'; // 기준정보
|
||||
| 'client' // 기준정보
|
||||
| 'receiving'; // 자재
|
||||
|
||||
// 폼 채우기 함수 타입
|
||||
type FillFormFunction = (data?: unknown) => void | Promise<void>;
|
||||
|
||||
@@ -35,6 +35,8 @@ import {
|
||||
CreditCard, // 카드
|
||||
// 기준정보 아이콘
|
||||
Building2, // 거래처
|
||||
// 자재 아이콘
|
||||
PackageCheck, // 입고
|
||||
} from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
@@ -57,6 +59,8 @@ const PAGE_PATTERNS: { pattern: RegExp; type: DevFillPageType; label: string }[]
|
||||
{ pattern: /\/accounting\/card-transactions\/new/, type: 'cardTransaction', label: '카드' },
|
||||
// 기준정보
|
||||
{ pattern: /\/client-management-sales-admin\/new/, type: 'client', label: '거래처' },
|
||||
// 자재
|
||||
{ pattern: /\/material\/receiving-management\/new/, type: 'receiving', label: '입고' },
|
||||
];
|
||||
|
||||
// ?mode=new 쿼리 파라미터를 사용하는 페이지 매핑
|
||||
@@ -91,6 +95,11 @@ const MASTER_DATA_STEPS: { type: DevFillPageType; label: string; icon: typeof Fi
|
||||
{ type: 'client', label: '거래처', icon: Building2, path: '/sales/client-management-sales-admin/new', fillEnabled: true },
|
||||
];
|
||||
|
||||
// 자재 단계 정의
|
||||
const MATERIAL_STEPS: { type: DevFillPageType; label: string; icon: typeof FileText; path: string; fillEnabled: boolean }[] = [
|
||||
{ type: 'receiving', label: '입고', icon: PackageCheck, path: '/material/receiving-management/new', fillEnabled: true },
|
||||
];
|
||||
|
||||
export function DevToolbar() {
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
@@ -320,9 +329,10 @@ export function DevToolbar() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 회계 플로우 버튼 영역 */}
|
||||
{/* 2행: 회계 + 기준정보 + 자재 버튼 영역 */}
|
||||
{isExpanded && (
|
||||
<div className="flex items-center gap-2 px-3 pb-3 border-t border-yellow-300 pt-3">
|
||||
{/* 회계 */}
|
||||
<span className="text-xs text-yellow-600 font-medium mr-1">회계:</span>
|
||||
{ACCOUNTING_STEPS.map((step) => {
|
||||
const Icon = step.icon;
|
||||
@@ -330,7 +340,6 @@ export function DevToolbar() {
|
||||
const isRegistered = hasRegisteredForm(step.type);
|
||||
const isCurrentLoading = isLoading === step.type;
|
||||
|
||||
// 활성화된 페이지: 폼 채우기 (fillEnabled가 true인 경우만)
|
||||
if (isActive && step.fillEnabled) {
|
||||
return (
|
||||
<Button
|
||||
@@ -352,7 +361,6 @@ export function DevToolbar() {
|
||||
);
|
||||
}
|
||||
|
||||
// 비활성화된 페이지 또는 이동만 가능한 버튼: 해당 페이지로 이동
|
||||
return (
|
||||
<Button
|
||||
key={step.type}
|
||||
@@ -367,12 +375,11 @@ export function DevToolbar() {
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 기준정보 버튼 영역 */}
|
||||
{isExpanded && (
|
||||
<div className="flex items-center gap-2 px-3 pb-3 border-t border-yellow-300 pt-3">
|
||||
{/* 구분선 */}
|
||||
<div className="w-px h-6 bg-yellow-300 mx-1" />
|
||||
|
||||
{/* 기준정보 */}
|
||||
<span className="text-xs text-yellow-600 font-medium mr-1">기준:</span>
|
||||
{MASTER_DATA_STEPS.map((step) => {
|
||||
const Icon = step.icon;
|
||||
@@ -380,7 +387,6 @@ export function DevToolbar() {
|
||||
const isRegistered = hasRegisteredForm(step.type);
|
||||
const isCurrentLoading = isLoading === step.type;
|
||||
|
||||
// 활성화된 페이지: 폼 채우기 (fillEnabled가 true인 경우만)
|
||||
if (isActive && step.fillEnabled) {
|
||||
return (
|
||||
<Button
|
||||
@@ -402,7 +408,6 @@ export function DevToolbar() {
|
||||
);
|
||||
}
|
||||
|
||||
// 비활성화된 페이지: 해당 페이지로 이동
|
||||
return (
|
||||
<Button
|
||||
key={step.type}
|
||||
@@ -417,6 +422,53 @@ export function DevToolbar() {
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* 구분선 */}
|
||||
<div className="w-px h-6 bg-yellow-300 mx-1" />
|
||||
|
||||
{/* 자재 */}
|
||||
<span className="text-xs text-yellow-600 font-medium mr-1">자재:</span>
|
||||
{MATERIAL_STEPS.map((step) => {
|
||||
const Icon = step.icon;
|
||||
const isActive = activePage === step.type;
|
||||
const isRegistered = hasRegisteredForm(step.type);
|
||||
const isCurrentLoading = isLoading === step.type;
|
||||
|
||||
if (isActive && step.fillEnabled) {
|
||||
return (
|
||||
<Button
|
||||
key={step.type}
|
||||
size="sm"
|
||||
variant="default"
|
||||
disabled={!isRegistered || isCurrentLoading}
|
||||
className="bg-purple-500 hover:bg-purple-600 text-white border-purple-600"
|
||||
onClick={() => handleFillForm(step.type)}
|
||||
title="폼 자동 채우기"
|
||||
>
|
||||
{isCurrentLoading ? (
|
||||
<Loader2 className="w-4 h-4 mr-1 animate-spin" />
|
||||
) : (
|
||||
<Icon className="w-4 h-4 mr-1" />
|
||||
)}
|
||||
{step.label} 채우기
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
key={step.type}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className={`border-purple-300 text-purple-700 hover:bg-purple-100 hover:border-purple-500 ${isActive ? 'bg-purple-100 border-purple-500' : ''}`}
|
||||
onClick={() => handleNavigate(step.path)}
|
||||
title={`${step.label} 페이지로 이동`}
|
||||
>
|
||||
<Icon className="w-4 h-4 mr-1" />
|
||||
{step.label}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -424,7 +476,7 @@ export function DevToolbar() {
|
||||
{isExpanded && !activePage && (
|
||||
<div className="px-3 pb-3">
|
||||
<p className="text-xs text-yellow-600">
|
||||
견적/수주/작업지시/출하/입금/출금/매입/거래처 페이지에서 자동 채우기가 활성화됩니다
|
||||
견적/수주/작업지시/출하/입금/출금/매입/거래처/입고 페이지에서 자동 채우기가 활성화됩니다
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
62
src/components/dev/generators/receivingData.ts
Normal file
62
src/components/dev/generators/receivingData.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* 입고 샘플 데이터 생성기
|
||||
*/
|
||||
|
||||
import {
|
||||
randomPick,
|
||||
randomInt,
|
||||
randomRemark,
|
||||
today,
|
||||
} from './index';
|
||||
|
||||
// ===== 상수 정의 =====
|
||||
|
||||
const SUPPLIERS = [
|
||||
'(주)대한철강', '삼성전자부품', '한국플라스틱', '글로벌전자',
|
||||
'동양화학', '한국볼트', '지오TNS (KG스틸)', 'SK이노베이션',
|
||||
'포스코', 'LG화학', '현대중공업', '한화솔루션',
|
||||
];
|
||||
|
||||
const ITEMS = [
|
||||
{ code: 'STEEL-001', name: 'SUS304 스테인리스 판재', spec: '1000x2000x3T', unit: 'EA' },
|
||||
{ code: 'STEEL-002', name: '알루미늄 프로파일', spec: '40x40x2000L', unit: 'EA' },
|
||||
{ code: 'ELEC-002', name: 'MCU 컨트롤러 IC', spec: 'STM32F103C8T6', unit: 'EA' },
|
||||
{ code: 'ELEC-005', name: 'DC 모터 24V', spec: '24V 100RPM', unit: 'EA' },
|
||||
{ code: 'ELEC-007', name: '커패시터 100uF', spec: '100uF 50V', unit: 'EA' },
|
||||
{ code: 'PLAS-003', name: 'ABS 사출 케이스', spec: '150x100x50', unit: 'SET' },
|
||||
{ code: 'CHEM-001', name: '에폭시 접착제', spec: '500ml', unit: 'EA' },
|
||||
{ code: 'BOLT-001', name: 'SUS 볼트 M8x30', spec: 'M8x30 SUS304', unit: 'EA' },
|
||||
{ code: '80008', name: '80008 egi1.55', spec: '1.55 * 1218 × 480', unit: 'EA' },
|
||||
];
|
||||
|
||||
// ===== 타입 정의 =====
|
||||
|
||||
export interface ReceivingFormData {
|
||||
itemCode: string;
|
||||
itemName: string;
|
||||
specification: string;
|
||||
unit: string;
|
||||
supplier: string;
|
||||
receivingQty: number;
|
||||
receivingDate: string;
|
||||
status: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
// ===== 메인 생성 함수 =====
|
||||
|
||||
export function generateReceivingData(): ReceivingFormData {
|
||||
const item = randomPick(ITEMS);
|
||||
|
||||
return {
|
||||
itemCode: item.code,
|
||||
itemName: item.name,
|
||||
specification: item.spec,
|
||||
unit: item.unit,
|
||||
supplier: randomPick(SUPPLIERS),
|
||||
receivingQty: randomInt(10, 500),
|
||||
receivingDate: today(),
|
||||
status: 'receiving_pending',
|
||||
remark: randomRemark(),
|
||||
};
|
||||
}
|
||||
@@ -14,4 +14,5 @@ export { generateQuoteData, generateQuoteItem } from './generators/quoteData';
|
||||
export { generateOrderData, generateOrderDataFull } from './generators/orderData';
|
||||
export { generateWorkOrderData } from './generators/workOrderData';
|
||||
export { generateShipmentData } from './generators/shipmentData';
|
||||
export { generateDepositData, generateWithdrawalData, generatePurchaseApprovalData, generateCardTransactionData } from './generators/accountingData';
|
||||
export { generateDepositData, generateWithdrawalData, generatePurchaseApprovalData, generateCardTransactionData } from './generators/accountingData';
|
||||
export { generateReceivingData } from './generators/receivingData';
|
||||
Reference in New Issue
Block a user