Add quote management functionality with API and UI integration

- Introduced a new `quote` module, including routes, controllers, and services for managing quotes.
- Implemented API endpoints for listing, creating, updating, and deleting quotes, ensuring proper company code filtering for data access.
- Developed a comprehensive UI for quote management, allowing users to create, edit, and view quotes seamlessly.
- Enhanced the admin layout to include the new quote management page, improving navigation and accessibility for users.

These additions significantly enhance the application's capabilities in managing quotes, providing users with essential tools for their sales processes.
This commit is contained in:
kjs
2026-04-02 15:30:44 +09:00
parent d8aaacb8f7
commit ce99001970
12 changed files with 1949 additions and 12 deletions

View File

@@ -0,0 +1,84 @@
import { Response } from "express";
import { AuthenticatedRequest } from "../types/auth";
import * as quoteService from "../services/quoteService";
import { logger } from "../utils/logger";
export async function getList(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const { search, status, startDate, endDate } = req.query as Record<string, string>;
const data = await quoteService.getList(companyCode, { search, status, startDate, endDate });
return res.json({ success: true, data });
} catch (error: any) {
logger.error("견적 목록 조회 실패", { error: error.message });
return res.status(500).json({ success: false, message: error.message });
}
}
export async function getById(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const { id } = req.params;
const data = await quoteService.getById(companyCode, parseInt(id));
if (!data) {
return res.status(404).json({ success: false, message: "견적을 찾을 수 없습니다." });
}
return res.json({ success: true, data });
} catch (error: any) {
logger.error("견적 상세 조회 실패", { error: error.message });
return res.status(500).json({ success: false, message: error.message });
}
}
export async function generateNumber(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const quoteNo = await quoteService.generateNumber(companyCode);
return res.json({ success: true, data: { quoteNo } });
} catch (error: any) {
logger.error("견적번호 생성 실패", { error: error.message });
return res.status(500).json({ success: false, message: error.message });
}
}
export async function create(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const userId = req.user!.userId;
const data = await quoteService.create(companyCode, userId, req.body);
return res.status(201).json({ success: true, data, message: "견적이 등록되었습니다." });
} catch (error: any) {
logger.error("견적 등록 실패", { error: error.message });
return res.status(500).json({ success: false, message: error.message });
}
}
export async function update(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const userId = req.user!.userId;
const { id } = req.params;
await quoteService.update(companyCode, userId, parseInt(id), req.body);
return res.json({ success: true, message: "견적이 수정되었습니다." });
} catch (error: any) {
logger.error("견적 수정 실패", { error: error.message });
return res.status(500).json({ success: false, message: error.message });
}
}
export async function remove(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const { id } = req.params;
await quoteService.remove(companyCode, parseInt(id));
return res.json({ success: true, message: "견적이 삭제되었습니다." });
} catch (error: any) {
logger.error("견적 삭제 실패", { error: error.message });
return res.status(500).json({ success: false, message: error.message });
}
}