-expanse
All checks were successful
Build Docker Image / Build Docker Image (push) Successful in 3m14s
Build Docker Image / Restart Docker Compose (push) Successful in 0s

-prjadd '0.00'
This commit is contained in:
x2Skyz
2025-11-25 15:59:21 +07:00
parent 5e22a0af02
commit b46197ca06
2 changed files with 38 additions and 40 deletions

View File

@@ -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

View File

@@ -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();
}
}
}