-**Global** date.js
-แก้ไข Expense สมบูรแบบ
This commit is contained in:
@@ -57,11 +57,11 @@ export class BudgetExpenseController {
|
||||
// ถ้าเจอ Project (aryResult.length >= 1)
|
||||
if (aryResult.length > 0) {
|
||||
|
||||
// [Check 1] เช็คว่าโครงการนี้อนุมัติไปแล้วหรือยัง?
|
||||
const project = aryResult[0];
|
||||
if (project.prjcomstt === 'BAP') {
|
||||
return sendError('โครงการนี้ได้รับการอนุมัติงบประมาณไปแล้ว ไม่สามารถทำรายการซ้ำได้', 'Project Already Approved');
|
||||
}
|
||||
// // [Check 1] เช็คว่าโครงการนี้อนุมัติไปแล้วหรือยัง?
|
||||
// const project = aryResult[0];
|
||||
// if (project.prjcomstt === 'BAP') {
|
||||
// return sendError('โครงการนี้ได้รับการอนุมัติงบประมาณไปแล้ว ไม่สามารถทำรายการซ้ำได้', 'Project Already Approved');
|
||||
// }
|
||||
|
||||
// เรียก makeArySave เพื่อทำการตัดงบ
|
||||
const promise = await this.makeArySave(req, database);
|
||||
|
||||
@@ -40,18 +40,31 @@ export class projectSearch {
|
||||
// เรียก Service ตัวเดิม (Simple)
|
||||
aryResult = await this.projectSearchService.getProjectSearch(database, column, condition);
|
||||
|
||||
} else if (columnParams == 'result' || columnParams == undefined || columnParams == '') {
|
||||
condition['prjseq'] = req.body.request.prjseq
|
||||
} if (columnParams == 'result' || columnParams == undefined || columnParams == '') {
|
||||
|
||||
// กำหนดเงื่อนไข (ถ้ามีส่งมา)
|
||||
condition['prjseq'] = req.body.request.prjseq;
|
||||
|
||||
// สร้าง Column String ที่มี Subquery ดึงงบจาก trnmst
|
||||
let column = `
|
||||
prjseq,
|
||||
prjnam,
|
||||
usrthinam as prjusrnam,
|
||||
prjwntbdg,
|
||||
bdgnam,
|
||||
bdgcod,
|
||||
prjacpbdg,
|
||||
${database}.translatedtl('COMSTT', prjcomstt) as prjcomstt,
|
||||
prjacpdtm`
|
||||
prjseq,
|
||||
prjnam,
|
||||
usrthinam as prjusrnam,
|
||||
prjwntbdg,
|
||||
bdgnam,
|
||||
|
||||
(
|
||||
SELECT string_agg(DISTINCT trnbdgcod, ',')
|
||||
FROM ${database}.trnmst
|
||||
WHERE trnprjseq = p.prjseq
|
||||
) as approved_bdg_codes,
|
||||
|
||||
p.prjacpbdg,
|
||||
${database}.translatedtl('COMSTT', prjcomstt) as prjcomstt,
|
||||
p.prjacpdtm
|
||||
`;
|
||||
|
||||
// ใช้ Service ตัวใหม่ (Detail Search / Join)
|
||||
aryResult = await this.projectSearchService.getProjectDetailSearch(database, column, condition);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { GeneralService } from '../share/generalservice.js';
|
||||
import { connection } from '../config/db.js'; // ต้อง import connection เพื่อทำ Transaction
|
||||
import { connection } from '../config/db.js';
|
||||
import { sendError } from '../utils/response.js';
|
||||
import { getDTM } from '../utils/date.js';
|
||||
|
||||
export class BudgetExpenseService {
|
||||
|
||||
@@ -28,31 +29,65 @@ export class BudgetExpenseService {
|
||||
try {
|
||||
await client.query('BEGIN'); // เริ่ม Transaction
|
||||
|
||||
const currentDate = getDTM();
|
||||
|
||||
// =========================================================
|
||||
// STEP 1: คืนเงินงบประมาณเดิมก่อน (กรณีแก้ไข/ลบรายการ)
|
||||
// =========================================================
|
||||
// ดึงรายการเดิมที่เคยบันทึกไว้ของ Project นี้ เพื่อเอามาคืนเงิน
|
||||
const oldExpenses = await client.query(
|
||||
`SELECT trnbdgcod, trnexpbdg FROM ${database}.trnmst WHERE trnprjseq = $1`,
|
||||
[projectSeq]
|
||||
);
|
||||
|
||||
// วนลูปคืนเงินกลับเข้าตาราง bdgmst (bdgttl + ยอดเดิม)
|
||||
for (const oldItem of oldExpenses.rows) {
|
||||
await client.query(`
|
||||
UPDATE ${database}.bdgmst
|
||||
SET bdgttl = bdgttl + $1, bdgedtdtm = $2
|
||||
WHERE bdgcod = $3
|
||||
`, [oldItem.trnexpbdg, currentDate, oldItem.trnbdgcod]);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// STEP 2: ลบรายการเดิมทิ้งทั้งหมด (Clear Old Transactions)
|
||||
// =========================================================
|
||||
// การลบทั้งหมดแล้วลงใหม่ จะครอบคลุมทั้งกรณี แก้ไขยอด, เพิ่มรายการใหม่, และลบรายการออก
|
||||
await client.query(`DELETE FROM ${database}.trnmst WHERE trnprjseq = $1`, [projectSeq]);
|
||||
|
||||
|
||||
// =========================================================
|
||||
// STEP 3: บันทึกรายการใหม่ และตัดเงินใหม่
|
||||
// =========================================================
|
||||
let totalApprovedAmount = 0;
|
||||
// Format วันที่: YYYYMMDD
|
||||
const currentDate = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
||||
|
||||
// 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 หรือติดลบ
|
||||
if (!expense.amount || Number(expense.amount) <= 0) {
|
||||
throw new sendError(`ยอดเงินต้องมากกว่า 0 (รายการรหัสงบ: ${expense.bdgcod})`);
|
||||
}
|
||||
|
||||
// [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) {
|
||||
return sendError(`ไม่พบรหัสงบประมาณ: ${expense.bdgcod} ในระบบ`, `Cannot Find Budget Code ${expense.bdgcod} in System`);
|
||||
// ⚠️ ต้อง throw error เพื่อให้ไปตกที่ catch แล้ว ROLLBACK
|
||||
throw new sendError(`ไม่พบรหัสงบประมาณ: ${expense.bdgcod} ในระบบ`);
|
||||
}
|
||||
|
||||
// 1.1 หา trnseq ล่าสุด
|
||||
const seqRes = await client.query(`SELECT COALESCE(MAX(trnseq), 0) + 1 as nextseq FROM ${database}.trnmst`);
|
||||
const nextTrnSeq = seqRes.rows[0].nextseq;
|
||||
|
||||
// 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;
|
||||
|
||||
// แปลงยอดเงินเป็นทศนิยม 2 ตำแหน่งให้ชัวร์ก่อนบันทึก
|
||||
const expenseAmount = Number(expense.amount).toFixed(2);
|
||||
|
||||
@@ -99,7 +134,7 @@ export class BudgetExpenseService {
|
||||
await client.query(sqlUpdatePrj, [formattedTotal, currentDate, projectSeq]);
|
||||
|
||||
await client.query('COMMIT'); // ยืนยัน (ทุกอย่างจะถูกบันทึกพร้อมกันเมื่อถึงบรรทัดนี้)
|
||||
return { status: true, total: totalApprovedAmount };
|
||||
return { status: true, msg: 'Budget updated successfully', total: formattedTotal };
|
||||
|
||||
} catch (error) {
|
||||
await client.query('ROLLBACK'); // ยกเลิกทั้งหมด (ถ้ามี error ข้อมูลจะกลับไปเหมือนเดิมทุกประการ)
|
||||
|
||||
16
exthernal-ttc-api/src/utils/date.js
Normal file
16
exthernal-ttc-api/src/utils/date.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* getDTM (Get Date Time)
|
||||
* คืนค่าเวลาปัจจุบันในรูปแบบ: YYYYMMDDHHmm (12 หลัก)
|
||||
* ตัวอย่าง: 202511211445
|
||||
*/
|
||||
export function getDTM() {
|
||||
const now = new Date();
|
||||
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0'); // เดือนเริ่มที่ 0 ต้อง +1
|
||||
const day = String(now.getDate()).padStart(2, '0');
|
||||
const hours = String(now.getHours()).padStart(2, '0');
|
||||
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||
|
||||
return `${year}${month}${day}${hours}${minutes}`;
|
||||
}
|
||||
Reference in New Issue
Block a user