feat(purchase): 구매신청 검색/직접입력/사진첨부/HEIC 지원/마스터 자동등록
- 소모품 select → 검색형 드롭다운 (debounce + 키보드 탐색) - 미등록 품목 직접 입력 + 분류 선택 지원 - 사진 첨부 (base64 업로드, HEIC→JPEG 프론트 변환) - 구매 처리 시 미등록 품목 소모품 마스터 자동 등록 - item_id NULL 허용, LEFT JOIN, custom_item_name/custom_category/photo_path 컬럼 - DB 마이그레이션 필요: ALTER TABLE purchase_requests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,16 +6,37 @@ const PurchaseController = {
|
||||
// 구매 처리 (신청 → 구매)
|
||||
create: async (req, res) => {
|
||||
try {
|
||||
const { request_id, item_id, vendor_id, quantity, unit_price, purchase_date, update_base_price, notes } = req.body;
|
||||
const { request_id, item_id, vendor_id, quantity, unit_price, purchase_date, update_base_price, register_to_master, notes } = req.body;
|
||||
|
||||
if (!item_id) return res.status(400).json({ success: false, message: '소모품을 선택해주세요.' });
|
||||
// item_id가 없으면 custom item → register_to_master로 자동 등록 가능
|
||||
let effectiveItemId = item_id;
|
||||
|
||||
if (!effectiveItemId && request_id) {
|
||||
// 미등록 품목의 구매 처리 — 마스터 등록 처리
|
||||
const requestData = await PurchaseRequestModel.getById(request_id);
|
||||
if (requestData && requestData.custom_item_name) {
|
||||
if (register_to_master !== false) {
|
||||
// 마스터에 등록
|
||||
const newItemId = await PurchaseModel.registerToMaster(
|
||||
requestData.custom_item_name,
|
||||
requestData.custom_category,
|
||||
null // maker
|
||||
);
|
||||
effectiveItemId = newItemId;
|
||||
// purchase_requests.item_id 업데이트
|
||||
await PurchaseRequestModel.updateItemId(request_id, newItemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!effectiveItemId) return res.status(400).json({ success: false, message: '소모품을 선택해주세요.' });
|
||||
if (!unit_price) return res.status(400).json({ success: false, message: '구매 단가를 입력해주세요.' });
|
||||
if (!purchase_date) return res.status(400).json({ success: false, message: '구매일을 입력해주세요.' });
|
||||
|
||||
// 구매 내역 생성
|
||||
const purchaseId = await PurchaseModel.createFromRequest({
|
||||
request_id: request_id || null,
|
||||
item_id,
|
||||
item_id: effectiveItemId,
|
||||
vendor_id: vendor_id || null,
|
||||
quantity: quantity || 1,
|
||||
unit_price,
|
||||
@@ -27,9 +48,9 @@ const PurchaseController = {
|
||||
// 기준가 업데이트 요청 시
|
||||
if (update_base_price) {
|
||||
const items = await PurchaseModel.getConsumableItems(false);
|
||||
const item = items.find(i => i.item_id === parseInt(item_id));
|
||||
const item = items.find(i => i.item_id === parseInt(effectiveItemId));
|
||||
if (item) {
|
||||
await PurchaseModel.updateBasePrice(item_id, unit_price, item.base_price, req.user.id);
|
||||
await PurchaseModel.updateBasePrice(effectiveItemId, unit_price, item.base_price, req.user.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +58,10 @@ const PurchaseController = {
|
||||
let equipmentResult = null;
|
||||
if (request_id) {
|
||||
const requestData = await PurchaseRequestModel.getById(request_id);
|
||||
if (requestData && requestData.category === 'equipment') {
|
||||
const category = requestData?.category || requestData?.custom_category;
|
||||
if (category === 'equipment') {
|
||||
equipmentResult = await PurchaseModel.tryAutoRegisterEquipment({
|
||||
item_name: requestData.item_name,
|
||||
item_name: requestData.item_name || requestData.custom_item_name,
|
||||
maker: requestData.maker,
|
||||
vendor_name: null,
|
||||
unit_price,
|
||||
@@ -51,7 +73,7 @@ const PurchaseController = {
|
||||
} else {
|
||||
// 직접 구매 시에도 category 확인
|
||||
const items = await PurchaseModel.getConsumableItems(false);
|
||||
const item = items.find(i => i.item_id === parseInt(item_id));
|
||||
const item = items.find(i => i.item_id === parseInt(effectiveItemId));
|
||||
if (item && item.category === 'equipment') {
|
||||
const vendors = await PurchaseModel.getVendors();
|
||||
const vendor = vendors.find(v => v.vendor_id === parseInt(vendor_id));
|
||||
|
||||
Reference in New Issue
Block a user