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