905d5c0976
[G9 수주복사 — wace copyEstimateAndOrderInfo 1:1]
- salesOrderMgmtService.copyOrder: 새 영업번호({YY}C-{NNNN}) 채번 +
contract_mgmt 23컬럼 INSERT-SELECT(contract_result='', is_direct_order='Y' 강제) +
contract_item + contract_item_serial 통째 복제
- POST /api/sales/order-mgmt/:id/copy 라우트
- 주문관리 그리드 "수주복사" 버튼 (Copy 아이콘) + handleCopyOrder
[G11 Amaranth 수주 결재상신 — wace ApprovalService.getAmaranthSsoUrl 1:1]
- chpark의 amaranthApprovalClient(HMAC-SHA256 + AES-128-CBC) 재사용
- amaranth_approval만 사용(자체 approval 미경유, wace 운영 패턴 동일)
- target_type='CONTRACT_ORDER', formId='1161', compSeq='1000'
- approKey 분기: 신규 / reject·delete·create는 새 approKey UPDATE / 그 외 재사용
- salesOrderMgmtService.startOrderApproval: user_info.emp_seq 조회 →
라인 0건 가드 → 매핑 분기 → SSO URL 발급 → INSERT/UPDATE → fullUrl 반환
- POST /api/sales/order-mgmt/:id/amaranth-approval 라우트
- 주문관리 그리드 "결재상신" 버튼 (Send 아이콘, sky-600) + handleAmaranthApproval
- getList SQL에 LEFT JOIN amaranth_approval AMR_ORDER 추가 +
order_appr_status(작성중/결재중/결재완료/반려 한글) + order_amaranth_status 노출
[DB 스키마]
- amaranth_approval.target_objid BIGINT → VARCHAR(80) (wace 운영 1:1)
· 출처: wace 매퍼 T.OBJID::VARCHAR = AMR_ORDER.TARGET_OBJID
· 사유: contract_mgmt.objid가 'CM-' prefix varchar라 bigint cast 불가
· 데이터 0건 무손실, ECR/CS는 bigint→varchar 자동 cast로 무영향
- approvalTableMigration.ts 동기화
[운영 배포 환경변수 — wace Constants 1:1 default 박힘]
- AMARANTH_OUT_PROCESS_CODE=RPSPLM_00001 (wace Constants.java:81)
- AMARANTH_FORM_ID_CONTRACT_ORDER=1161 (wace orderMgmtList.jsp:558)
- AMARANTH_COMP_SEQ=1000 (wace orderMgmtList.jsp:559)
- 3개 docker-compose(deploy/onpremise, docker/deploy, docker/prod) 모두
${VAR:-default} 형식으로 매핑 — 호스트 .env 미설정 시 default 동작
[검증]
- G9: BEGIN/ROLLBACK으로 26C-0800(라인 3건) 복사 시뮬레이션 — 헤더 23컬럼 1:1,
채번 26C-0803, 라인 3→3건 + seq 보존
- G11: 4단계 상태 라벨(create→inProcess→complete→reject) 모두 정상,
VARCHAR PK(CM-... prefix) JOIN도 정상
- 문서: docs/migration/sales/06-copy-order-verify.md, 07-amaranth-approval-verify.md
- GAP: G9 ✅, G10 ❌(영업 GAP 아님 — Admin 도메인), G11 ✅
[운영 트러블슈팅 노트 — 07-verify.md 트러블슈팅 섹션]
dev에서 amaranth 측이 "API Proxy 호출 시 유효한 레디스 값이 존재하지 않습니다"로
거부. 우리 코드는 정상 — 'Amaranth - 결재' accessToken을 amaranth 서버 측
Redis에 등록받아야 동작. chpark/RPS ERP 담당자 협조 영역(코드 변경 없음).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
153 lines
5.1 KiB
TypeScript
153 lines
5.1 KiB
TypeScript
import { apiClient } from "./client";
|
|
|
|
export interface OrderListFilter {
|
|
category_cd?: string;
|
|
search_poNo?: string;
|
|
customer_objid?: string;
|
|
search_partObjId?: string;
|
|
search_serialNo?: string;
|
|
contract_result?: string;
|
|
order_start_date?: string;
|
|
order_end_date?: string;
|
|
due_start_date?: string;
|
|
due_end_date?: string;
|
|
product?: string;
|
|
area_cd?: string;
|
|
paid_type?: string;
|
|
contract_currency?: string;
|
|
}
|
|
|
|
export interface OrderRow {
|
|
objid: string;
|
|
contract_no: string | null;
|
|
category_cd: string | null;
|
|
customer_objid: string | null;
|
|
customer_name: string | null;
|
|
product: string | null;
|
|
area_cd: string | null;
|
|
paid_type: string | null;
|
|
paid_type_name: string | null;
|
|
product_name: string | null;
|
|
area_name: string | null;
|
|
contract_currency: string | null;
|
|
exchange_rate: string | null;
|
|
po_no: string | null;
|
|
order_date: string | null;
|
|
receipt_date: string | null;
|
|
req_del_date: string | null;
|
|
contract_result: string | null;
|
|
order_supply_price_sum: string | null;
|
|
order_vat_sum: string | null;
|
|
order_total_amount_sum: string | null;
|
|
writer: string | null;
|
|
writer_name: string | null;
|
|
pm_user_id: string | null;
|
|
pm_user_name: string | null;
|
|
regdate: string | null;
|
|
order_quantity: number | null;
|
|
cancel_qty_sum: number | null;
|
|
has_order_data: number | null;
|
|
earliest_due_date: string | null;
|
|
other_due_date_count: number | null;
|
|
item_summary: string | null;
|
|
part_no: string | null;
|
|
serial_no: string | null;
|
|
order_appr_status: string | null; // 한글 라벨 ('결재완료'/'결재중'/'반려'/'작성중'/'')
|
|
amaranth_status: string | null; // 원본 상태 (호환용)
|
|
order_amaranth_status: string | null; // 원본 상태 ('complete'/'inProcess'/'reject'/'create'/'')
|
|
cu01_cnt: number | null;
|
|
is_direct_order: string | null;
|
|
}
|
|
|
|
export interface OrderItem {
|
|
objid?: string;
|
|
seq: number;
|
|
part_objid: string;
|
|
part_no: string;
|
|
part_name: string;
|
|
quantity?: number;
|
|
due_date?: string;
|
|
customer_request?: string;
|
|
order_quantity?: string;
|
|
order_unit_price?: string;
|
|
order_supply_price?: string;
|
|
order_vat?: string;
|
|
order_total_amount?: string;
|
|
cancel_qty?: string;
|
|
return_reason?: string;
|
|
product?: string;
|
|
serials?: string[];
|
|
}
|
|
|
|
export interface OrderBody {
|
|
objid?: string;
|
|
contract_no?: string;
|
|
category_cd?: string;
|
|
customer_objid?: string;
|
|
product?: string;
|
|
area_cd?: string;
|
|
paid_type?: string;
|
|
contract_currency?: string;
|
|
exchange_rate?: string;
|
|
receipt_date?: string;
|
|
order_date?: string; // 발주일 (wace G2 필수)
|
|
req_del_date?: string;
|
|
po_no?: string;
|
|
contract_result?: string;
|
|
approval_required?: string; // 결재여부 'Y'|'N'
|
|
is_direct_order?: string; // 'Y' 기본 (G2 직접등록)
|
|
pm_user_id?: string;
|
|
customer_request?: string;
|
|
shipping_method?: string;
|
|
incoterms?: string;
|
|
items: OrderItem[];
|
|
}
|
|
|
|
export const salesOrderMgmtApi = {
|
|
async list(filter: OrderListFilter = {}) {
|
|
const res = await apiClient.get("/sales/order-mgmt/list", { params: filter });
|
|
return (res.data?.data ?? []) as OrderRow[];
|
|
},
|
|
async detail(objid: string) {
|
|
const res = await apiClient.get(`/sales/order-mgmt/${objid}`);
|
|
return res.data?.data;
|
|
},
|
|
async generateNumber(): Promise<string> {
|
|
const res = await apiClient.get("/sales/order-mgmt/generate-number");
|
|
return res.data?.data?.contractNo ?? "";
|
|
},
|
|
async create(body: OrderBody) {
|
|
const res = await apiClient.post("/sales/order-mgmt", body);
|
|
return res.data?.data as { objid: string; contract_no: string };
|
|
},
|
|
async update(objid: string, body: OrderBody) {
|
|
return (await apiClient.put(`/sales/order-mgmt/${objid}`, body)).data;
|
|
},
|
|
async remove(objid: string) {
|
|
return (await apiClient.delete(`/sales/order-mgmt/${objid}`)).data;
|
|
},
|
|
async setStatus(objid: string, contract_result: string) {
|
|
return (await apiClient.patch(`/sales/order-mgmt/${objid}/status`, { contract_result })).data;
|
|
},
|
|
// 라인별 cancel_qty 다중 UPDATE (wace saveOrderCancelQty 이식)
|
|
async saveCancelQty(objid: string, entries: { itemObjId: string; cancelQty: string | number; orderQty: string | number }[]) {
|
|
return (await apiClient.post(`/sales/order-mgmt/${objid}/cancel-qty`, { entries })).data;
|
|
},
|
|
async formView(objid: string): Promise<{ info: any; items: any[] }> {
|
|
const res = await apiClient.get(`/sales/order-mgmt/${objid}/form-view`);
|
|
return res.data?.data ?? { info: null, items: [] };
|
|
},
|
|
// G9 수주복사 (wace btnCopy → copyEstimateAndOrderInfo 1:1)
|
|
async copyOrder(objid: string): Promise<{ newObjid: string; newContractNo: string }> {
|
|
const res = await apiClient.post(`/sales/order-mgmt/${objid}/copy`);
|
|
return res.data?.data;
|
|
},
|
|
// G4/G11 수주 결재상신 — Amaranth SSO URL 발급
|
|
// wace orderMgmtList.btnApproval → ApprovalService.getAmaranthSsoUrl 1:1
|
|
async startApproval(objid: string, body: { approvalTitle?: string; subjectStr?: string } = {})
|
|
: Promise<{ fullUrl: string; approKey: string; status: string }> {
|
|
const res = await apiClient.post(`/sales/order-mgmt/${objid}/amaranth-approval`, body);
|
|
return res.data?.data;
|
|
},
|
|
};
|