Files
wace_rps/frontend/lib/api/purchase.ts
T
hjjeong 17b08c7a09 구매관리 발주서 메일 발송 + PDF 다운로드 + 행추가/삭제 제거
- backend purchaseOrderMailService 신설 — getOrderMailInfo / getPartnerManagerList /
  sendOrderMail (SMTP PURCHASE, 발송 성공 시 mail_send_yn='Y'/mail_send_date 갱신)
- backend routes — GET /order-form/mail-info/:objid, POST /order-form/mail,
  GET /options/partner-managers/:partnerObjid
- frontend lib/utils/purchaseOrderPdf — html2canvas-pro + jsPDF (A4, scale=2,
  input/textarea → 텍스트 변환). download:true 면 파일 저장, 아니면 base64 반환
- PurchaseOrderMailDialog 신설 — EstimateMailDialog 패턴 단순화 (한글/영문 본문 분기,
  공급업체 단일 email 자동 채움)
- 3개 양식 다이얼로그 — 읽기전용 + 저장된 발주서일 때 "메일 발송" + "PDF 다운로드"
  버튼 노출. window.print 간이판 제거
- 3개 양식 다이얼로그 — "행 추가"/"선택 행 삭제" 버튼 + 그리드 체크박스 컬럼 제거
  (wace 운영판은 모두 주석 처리/부재. 발주서는 품의서에서 자동 채움된 품목 그대로 사용)
2026-05-19 14:57:47 +09:00

186 lines
6.4 KiB
TypeScript

// ============================================================
// 구매관리 — 7개 메뉴 그리드 API.
// 백엔드: /api/purchase/{menu-path}, /api/purchase/options/{suppliers|users|projects}
// ============================================================
import { apiClient } from "./client";
export interface PurchaseListFilter {
year?: string;
customer_objid?: string;
customer_cd?: string;
project_no?: string;
part_no?: string;
part_name?: string;
part_spec?: string;
partner_objid?: string;
purchase_order_no?: string;
proposal_no?: string;
search_status?: string;
writer?: string;
request_user?: string;
purchase_type?: string;
part_type?: string;
product_cd?: string;
category_cd?: string;
paid_type?: string;
mail_send_yn?: string;
delivery_status?: string;
close_status?: string;
sales_mng_user_id?: string;
regdate_start?: string;
regdate_end?: string;
receipt_date_start?: string;
receipt_date_end?: string;
delivery_start_date?: string;
delivery_end_date?: string;
reg_start_date?: string;
reg_end_date?: string;
page?: number;
page_size?: number;
}
export interface PurchaseListResponse<T = any> {
rows: T[];
totalCount: number;
page: number;
pageSize: number;
}
export interface OptionItem {
code: string;
label: string;
}
async function getList<T = any>(path: string, filter: PurchaseListFilter): Promise<PurchaseListResponse<T>> {
const res = await apiClient.get(`/purchase/${path}`, { params: filter });
return res.data?.data as PurchaseListResponse<T>;
}
export interface OrderFormData {
master: Record<string, any>;
parts: Record<string, any>[];
}
export interface SaveOrderPayload {
master: Record<string, any>;
parts: Record<string, any>[];
deletedPartObjids?: string[];
}
export interface SaveOrderResult {
objid: string;
purchase_order_no: string;
}
export interface OrderMailInfo {
pom_objid: string;
purchase_order_no: string;
partner_objid: string;
partner_name: string;
partner_email: string;
writer_email: string;
writer_name: string;
form_type: string;
}
export interface PartnerManager {
name: string;
email: string;
phone: string;
department: string;
is_main: string;
}
export interface SendOrderMailPayload {
pomObjid: string;
toEmails: string;
ccEmails?: string;
subject: string;
contents: string;
pdfBase64: string;
}
export const purchaseApi = {
// 그리드 7종
listPurchaseRequest: (f: PurchaseListFilter = {}) => getList("purchase-request", f),
listQuotationRequest: (f: PurchaseListFilter = {}) => getList("quotation-request", f),
listProposal: (f: PurchaseListFilter = {}) => getList("proposal", f),
listInbound: (f: PurchaseListFilter = {}) => getList("inbound", f),
listInboundByItem: (f: PurchaseListFilter = {}) => getList("inbound-by-item", f),
listInboundByDate: (f: PurchaseListFilter = {}) => getList("inbound-by-date", f),
listProjectStatus: (f: PurchaseListFilter = {}) => getList("project-status", f),
listOrder: (f: PurchaseListFilter = {}) => getList("order-list", f),
// ─── 발주서 폼 (general 양식) ──────────────────────────
/** 품의서 OBJID 로 발주서 폼 초기값 + 품목 자동채움. */
async initOrderForm(proposalObjid: string): Promise<OrderFormData> {
const r = await apiClient.get("/purchase/order-form/init", {
params: { proposal_objid: proposalObjid },
});
return r.data?.data as OrderFormData;
},
/** 기존 발주서 마스터+파트 조회 (수정 모드). */
async getOrderForm(objid: string): Promise<OrderFormData> {
const r = await apiClient.get(`/purchase/order-form/${encodeURIComponent(objid)}`);
return r.data?.data as OrderFormData;
},
/** 마스터+파트 UPSERT + 누락파트 삭제. */
async saveOrderForm(payload: SaveOrderPayload): Promise<SaveOrderResult> {
const r = await apiClient.post("/purchase/order-form/save", payload);
return r.data?.data as SaveOrderResult;
},
/** 발주서 삭제 (cascade). */
async deleteOrderForm(objid: string): Promise<void> {
await apiClient.delete(`/purchase/order-form/${encodeURIComponent(objid)}`);
},
// ─── 발주서 메일 발송 ─────────────────────────────────────
/** 메일 다이얼로그 자동채움 — 공급업체 이메일/이름 + 작성자 이메일 + 발주번호 */
async getOrderMailInfo(pomObjid: string): Promise<OrderMailInfo | null> {
const r = await apiClient.get(`/purchase/order-form/mail-info/${encodeURIComponent(pomObjid)}`);
return (r.data?.data ?? null) as OrderMailInfo | null;
},
/** 공급업체 담당자 리스트 — RPS client_mng 단일 email */
async listPartnerManagers(partnerObjid: string): Promise<PartnerManager[]> {
const r = await apiClient.get(
`/purchase/options/partner-managers/${encodeURIComponent(partnerObjid)}`,
);
return (r.data?.data ?? []) as PartnerManager[];
},
/** PDF 첨부 + SMTP 발송. 성공 시 mail_send_yn='Y'/mail_send_date=NOW() 갱신. */
async sendOrderMail(payload: SendOrderMailPayload): Promise<{ success: boolean; message: string; objid?: string }> {
const r = await apiClient.post("/purchase/order-form/mail", payload);
return r.data as { success: boolean; message: string; objid?: string };
},
// 공통 옵션
async listSuppliers(): Promise<OptionItem[]> {
const r = await apiClient.get("/purchase/options/suppliers");
return (r.data?.data ?? []) as OptionItem[];
},
// 견적요청서 / 발주서 vendor (wace client_mng 매칭)
async listVendors(): Promise<OptionItem[]> {
const r = await apiClient.get("/purchase/options/vendors");
return (r.data?.data ?? []) as OptionItem[];
},
async listUsers(): Promise<OptionItem[]> {
const r = await apiClient.get("/purchase/options/users");
return (r.data?.data ?? []) as OptionItem[];
},
async listProjects(): Promise<OptionItem[]> {
const r = await apiClient.get("/purchase/options/projects");
return (r.data?.data ?? []) as OptionItem[];
},
};
/** 년도 옵션 — wace 운영판 동일 (현재년도 ±4) */
export function getYearOptions(): OptionItem[] {
const y = new Date().getFullYear();
const out: OptionItem[] = [];
for (let i = y + 4; i >= y - 4; i--) {
out.push({ code: String(i), label: String(i) });
}
return out;
}