-expanse
-prjadd '0.00'
This commit is contained in:
@@ -59,7 +59,7 @@ export class projectAdd {
|
||||
prjnam: req.body.request.prjnam,
|
||||
prjusrseq: req.body.request.prjusrseq,
|
||||
prjwntbdg: req.body.request.prjwntbdg,
|
||||
prjacpbdg: req.body.request.prjacpbdg,
|
||||
prjacpbdg: '0.00',
|
||||
prjbdgcod: req.body.request.prjbdgcod,
|
||||
prjcomstt: req.body.request.prjcomstt,
|
||||
prjacpdtm: req.body.request.prjacpdtm
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { GeneralService } from '../share/generalservice.js';
|
||||
import { connection } from '../config/db.js';
|
||||
import { connection } from '../config/db.js';
|
||||
import { sendError } from '../utils/response.js';
|
||||
import { getDTM } from '../utils/date.js';
|
||||
import { getDTM } from '../utils/date.js'; // ✅ 1. Import ฟังก์ชันกลางเข้ามา
|
||||
|
||||
export class BudgetExpenseService {
|
||||
|
||||
@@ -9,7 +9,6 @@ export class BudgetExpenseService {
|
||||
this.generalService = new GeneralService();
|
||||
}
|
||||
|
||||
// อันนี้ใช้ GeneralService ได้เพราะเป็น Query เดียวจบ
|
||||
async getBudgetExpense(database, name) {
|
||||
const sql = `
|
||||
SELECT trnseq, trnprjnam
|
||||
@@ -23,18 +22,17 @@ export class BudgetExpenseService {
|
||||
|
||||
// ฟังก์ชันอนุมัติและตัดงบ (Transaction)
|
||||
async approveBudgetExpense(database, projectSeq, expenseList, user) {
|
||||
// ⚠️ จำเป็นต้องใช้ client โดยตรงเพื่อคุม Transaction (GeneralService ปกติจะใช้ pool ซึ่งอาจเปลี่ยน connection ระหว่างทางได้)
|
||||
const client = await connection.connect();
|
||||
|
||||
try {
|
||||
await client.query('BEGIN'); // เริ่ม Transaction
|
||||
await client.query('BEGIN');
|
||||
|
||||
const currentDate = getDTM();
|
||||
// 2. เรียกใช้ getDTM() แทนโค้ดเดิม
|
||||
const currentDTM = getDTM();
|
||||
|
||||
// =========================================================
|
||||
// STEP 1: คืนเงินงบประมาณเดิมก่อน (กรณีแก้ไข/ลบรายการ)
|
||||
// =========================================================
|
||||
// ดึงรายการเดิมที่เคยบันทึกไว้ของ Project นี้ เพื่อเอามาคืนเงิน
|
||||
const oldExpenses = await client.query(
|
||||
`SELECT trnbdgcod, trnexpbdg FROM ${database}.trnmst WHERE trnprjseq = $1`,
|
||||
[projectSeq]
|
||||
@@ -46,52 +44,45 @@ export class BudgetExpenseService {
|
||||
UPDATE ${database}.bdgmst
|
||||
SET bdgttl = bdgttl + $1, bdgedtdtm = $2
|
||||
WHERE bdgcod = $3
|
||||
`, [oldItem.trnexpbdg, currentDate, oldItem.trnbdgcod]);
|
||||
`, [oldItem.trnexpbdg, currentDTM, oldItem.trnbdgcod]); // update เวลาแก้ไขล่าสุด
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// STEP 2: ลบรายการเดิมทิ้งทั้งหมด (Clear Old Transactions)
|
||||
// STEP 2: ลบรายการเดิมทิ้ง (เพื่อเตรียมลงใหม่)
|
||||
// =========================================================
|
||||
// การลบทั้งหมดแล้วลงใหม่ จะครอบคลุมทั้งกรณี แก้ไขยอด, เพิ่มรายการใหม่, และลบรายการออก
|
||||
await client.query(`DELETE FROM ${database}.trnmst WHERE trnprjseq = $1`, [projectSeq]);
|
||||
|
||||
|
||||
// =========================================================
|
||||
// STEP 3: บันทึกรายการใหม่ และตัดเงินใหม่
|
||||
// STEP 3: บันทึกรายการใหม่ และตัดเงินใหม่
|
||||
// =========================================================
|
||||
let totalApprovedAmount = 0;
|
||||
|
||||
// 1.2 หาชื่อโครงการ (ดึงครั้งเดียวนอกลูปเพื่อประสิทธิภาพ)
|
||||
const prjRes = await client.query(`SELECT prjnam FROM ${database}.prjmst WHERE prjseq = $1`, [projectSeq]);
|
||||
if (prjRes.rows.length === 0) throw new Error(`Project ${projectSeq} not found`);
|
||||
const projectName = prjRes.rows[0].prjnam;
|
||||
|
||||
// 1. วนลูปตัดงบและบันทึก Transaction
|
||||
for (const expense of expenseList) {
|
||||
// expense: { bdgcod: '33', amount: 5000 }
|
||||
|
||||
// [Validation] ห้ามยอดเงินเป็น 0 หรือติดลบ
|
||||
// 🛑 [Validation] ห้ามยอดเงินเป็น 0 หรือติดลบ
|
||||
if (!expense.amount || Number(expense.amount) <= 0) {
|
||||
throw new sendError(`ยอดเงินต้องมากกว่า 0 (รายการรหัสงบ: ${expense.bdgcod})`);
|
||||
return sendError(`ยอดเงินต้องมากกว่า 0 (รายการรหัสงบ: ${expense.bdgcod})`);
|
||||
}
|
||||
|
||||
// [Check 2] เช็คก่อนว่ามีรหัสงบประมาณนี้จริงหรือไม่
|
||||
// [Check 2] ตรวจสอบว่ามีรหัสงบประมาณนี้จริงหรือไม่
|
||||
const checkBdgSql = `SELECT bdgseq FROM ${database}.bdgmst WHERE bdgcod = $1`;
|
||||
const checkBdgRes = await client.query(checkBdgSql, [expense.bdgcod]);
|
||||
|
||||
if (checkBdgRes.rows.length === 0) {
|
||||
// ⚠️ ต้อง throw error เพื่อให้ไปตกที่ catch แล้ว ROLLBACK
|
||||
throw new sendError(`ไม่พบรหัสงบประมาณ: ${expense.bdgcod} ในระบบ`);
|
||||
return sendError(`ไม่พบรหัสงบประมาณ: ${expense.bdgcod} ในระบบ`);
|
||||
}
|
||||
|
||||
// 1.1 หา trnseq ล่าสุด
|
||||
// Get Next Seq
|
||||
const seqRes = await client.query(`SELECT COALESCE(MAX(trnseq), 0) + 1 as nextseq FROM ${database}.trnmst`);
|
||||
const nextTrnSeq = seqRes.rows[0].nextseq;
|
||||
|
||||
// แปลงยอดเงินเป็นทศนิยม 2 ตำแหน่งให้ชัวร์ก่อนบันทึก
|
||||
const expenseAmount = Number(expense.amount).toFixed(2);
|
||||
|
||||
// 1.3 Insert ลง trnmst (บันทึกยอดที่ตัดในรายการนี้)
|
||||
// Insert รายการใหม่ (บันทึก currentDTM ลง trnacpdtm)
|
||||
const sqlTrn = `
|
||||
INSERT INTO ${database}.trnmst
|
||||
(trnseq, trnprjnam, trnprjseq, trnexpbdg, trnbdgcod, trncomstt, trnacpdtm)
|
||||
@@ -101,47 +92,54 @@ export class BudgetExpenseService {
|
||||
nextTrnSeq,
|
||||
projectName,
|
||||
projectSeq,
|
||||
expenseAmount, //ใช้ค่าที่ format แล้ว
|
||||
expenseAmount,
|
||||
expense.bdgcod,
|
||||
currentDate
|
||||
currentDTM
|
||||
]);
|
||||
|
||||
// 1.4 ตัดเงินจากงบประมาณ (bdgmst)
|
||||
// Postgres จะจัดการลบเลขทศนิยมให้เอง แต่ส่งค่าที่ถูกต้องไปจะดีที่สุด
|
||||
// ตัดเงินงบประมาณ (อัปเดตเวลาแก้ไข)
|
||||
const sqlUpdateBdg = `
|
||||
UPDATE ${database}.bdgmst
|
||||
SET bdgttl = bdgttl - $1,
|
||||
bdgedtdtm = $2
|
||||
WHERE bdgcod = $3
|
||||
`;
|
||||
await client.query(sqlUpdateBdg, [expenseAmount, currentDate, expense.bdgcod]);
|
||||
await client.query(sqlUpdateBdg, [expenseAmount, currentDTM, expense.bdgcod]);
|
||||
|
||||
// สะสมยอดรวม (ระวังเรื่องทศนิยมใน JS)
|
||||
totalApprovedAmount += Number(expense.amount);
|
||||
}
|
||||
|
||||
// 2. อัปเดต Project Master (prjmst)
|
||||
// Format ยอดรวมให้เป็นทศนิยม 2 ตำแหน่งเป๊ะๆ ก่อนบันทึก (เช่น 45000.00)
|
||||
// ---------------------------------------------------------
|
||||
// STEP 4: อัปเดต Project Master (เปลี่ยนสถานะตามยอดเงิน)
|
||||
// ---------------------------------------------------------
|
||||
const formattedTotal = totalApprovedAmount.toFixed(2);
|
||||
|
||||
// [UPDATED] กำหนดสถานะ: ถ้ายอดรวมเป็น 0 ให้เป็น UAC (รออนุมัติ), ถ้ามีเงินให้เป็น BAP (อนุมัติแล้ว)
|
||||
const projectStatus = totalApprovedAmount > 0 ? 'BAP' : 'UAC';
|
||||
|
||||
const sqlUpdatePrj = `
|
||||
UPDATE ${database}.prjmst
|
||||
SET prjacpbdg = $1,
|
||||
prjcomstt = 'BAP',
|
||||
prjacpdtm = $2
|
||||
WHERE prjseq = $3
|
||||
prjcomstt = $2,
|
||||
prjacpdtm = $3
|
||||
WHERE prjseq = $4
|
||||
`;
|
||||
await client.query(sqlUpdatePrj, [formattedTotal, currentDate, projectSeq]);
|
||||
await client.query(sqlUpdatePrj, [formattedTotal, projectStatus, currentDTM, projectSeq]);
|
||||
|
||||
await client.query('COMMIT'); // ยืนยัน (ทุกอย่างจะถูกบันทึกพร้อมกันเมื่อถึงบรรทัดนี้)
|
||||
return { status: true, msg: 'Budget updated successfully', total: formattedTotal };
|
||||
await client.query('COMMIT');
|
||||
return {
|
||||
status: true,
|
||||
msg: 'Budget updated successfully',
|
||||
total: formattedTotal,
|
||||
projectStatus: projectStatus
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
await client.query('ROLLBACK'); // ยกเลิกทั้งหมด (ถ้ามี error ข้อมูลจะกลับไปเหมือนเดิมทุกประการ)
|
||||
await client.query('ROLLBACK');
|
||||
console.error('Transaction Error:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
client.release(); // คืน Connection กลับสู่ Pool
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user