Files
wms-app/scripts/sdlc-seed/docs-si2.mjs
T

445 lines
60 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// SI work products 18–22: user documentation, operation guide, maintenance, verification, validation.
import { P, CODE, ORGANIZER, ORGANIZER_PM, RECORDER, START, END, SCOPE, CRS, TEST_FROM, TEST_TO, ACCEPT_DATE, BASELINE_COMMIT, TEST_STATE_COMMIT, ORIGIN, BACKUP, OPS_CLOSE_DATE } from './project.mjs';
import { UNITS, TEST_CASES, traceOf, unitTopic } from './engineering.mjs';
import { CORRECTIONS, CHANGES } from './history.mjs';
import { bud, thLong, thRangeLong, table, bullets, numbered } from './lib.mjs';
import { workProduct, head } from './format.mjs';
/** 18. Software User Document. */
export function userDocumentation() {
const date = '2026-08-14';
return {
dir: '2-SI Process (12 Work Product)/18.Software User Documentation',
name: `${CODE} Software User Document ${bud(date)} V1.0 ThS`,
md: workProduct({
type: 'Software User Document', footer: 'SuD',
rows: head('Software User Document', `${bud(date)} V1.0 ThS`, [
['Title', 'เอกสารคู่มือการใช้งานสำหรับผู้ใช้'],
['Project Period', thRangeLong(START, END)],
['Organizer', ORGANIZER],
['Recorder', RECORDER],
]),
body: [
'## วัตถุประสงค์ (Objective)',
'คู่มือฉบับนี้จัดทำขึ้นเพื่อเป็นแนวทางสำหรับผู้ใช้งานระบบบริหารจัดการคลังสินค้า ครอบคลุมการเข้าสู่ระบบ การตั้งค่าข้อมูลหลัก การบันทึกรายการคลังสินค้า งานขาย งานจัดซื้อ งานการเงินและบัญชี การเรียกดูรายงาน และการรับการแจ้งเตือน',
'## 1 การเข้าสู่ระบบ (System Access)',
table(['ลำดับ', 'รายละเอียด'], [
[1, 'เข้าใช้งานผ่าน Web Browser มาตรฐาน (Chrome, Edge, Firefox) ตาม URL ที่ผู้ดูแลระบบกำหนด'],
[2, 'ผู้ใช้งานใหม่ที่เป็นเจ้าของบริษัทให้เลือก "ลงทะเบียนบริษัท" และยืนยันอีเมลเพื่อเปิดใช้งาน'],
[3, 'ผู้ใช้งานที่ได้รับคำเชิญให้กดลิงก์ในอีเมลเชิญ แล้วตั้งรหัสผ่านเพื่อเข้าร่วมบริษัท'],
[4, 'กรณีลืมรหัสผ่าน ให้เลือก "ลืมรหัสผ่าน" ระบบจะส่งลิงก์และรหัส OTP ไปยังอีเมลที่ลงทะเบียนไว้'],
[5, 'ระบบอนุญาตให้ใช้งานได้ครั้งละหนึ่ง Session ต่อบัญชี หากเข้าสู่ระบบจากอุปกรณ์ใหม่ระบบจะปฏิเสธการเข้าใช้งานซ้ำ'],
[6, 'หน้าจอรองรับการใช้งานบนคอมพิวเตอร์ แท็บเล็ต และโทรศัพท์มือถือ'],
], ['c']),
'## 2 บทบาทและสิทธิ์การใช้งาน (Roles)',
table(['บทบาท', 'สิทธิ์การใช้งาน'], [
['Owner', 'เจ้าของบริษัท ใช้งานได้ทุกเมนู รวมถึงการตั้งค่าบริษัทและการจัดการผู้ใช้'],
['Admin', 'จัดการข้อมูลหลัก ผู้ใช้งาน สิทธิ์การเข้าถึง และใช้งานทุกโมดูลปฏิบัติการ'],
['Staff', 'บันทึกรายการคลังสินค้า ขาย จัดซื้อ และการเงิน ตามสิทธิ์ที่ได้รับ'],
['Viewer', 'ดูหน้าจอและรายงานที่ได้รับสิทธิ์ แต่ไม่สามารถสร้างหรือแก้ไขรายการได้'],
]),
'เมนูและปุ่มคำสั่งที่แสดงจะเปลี่ยนตามบทบาทและสิทธิ์การเข้าถึงที่ผู้ดูแลระบบกำหนด',
'## 3 หน้าแรกและแดชบอร์ด (Dashboard)',
bullets([
'แดชบอร์ดคลังสินค้าแสดงยอดสินค้าคงเหลือ สินค้าใกล้หมด และความเคลื่อนไหวล่าสุด',
'แดชบอร์ดบัญชีแสดงภาพรวมรายรับ รายจ่าย และยอดค้างชำระ',
'ตัวเลขบนแดชบอร์ดคำนวณจากตารางสรุปยอดที่ปรับปรุงตามกำหนดเวลา รายการที่เพิ่งบันทึกอาจแสดงผลช้ากว่าข้อมูลจริงเล็กน้อย',
]),
'## 4 การตั้งค่าข้อมูลหลัก (Master Data)',
'ก่อนเริ่มบันทึกรายการ ผู้ใช้ระดับ Owner หรือ Admin ต้องตั้งค่าข้อมูลหลักตามลำดับ',
numbered([
'**คลังสินค้า พื้นที่จัดเก็บ และช่องจัดเก็บ** เลือกใช้โครงสร้างแบบคลังเดียวหรือแบบหลายชั้น (คลัง / พื้นที่ / ช่อง) ตามลักษณะการทำงาน',
'**หมวดสินค้าและสินค้า** ระบุรหัสสินค้า ชื่อ หน่วยนับ และรูปสินค้า',
'**ประเภทผู้ติดต่อและผู้ติดต่อ** บันทึกข้อมูลลูกค้าและผู้ขายที่ใช้ในเอกสารขายและจัดซื้อ',
'**ข้อมูลบริษัทและ SMTP** ตั้งค่าข้อมูลบริษัท โลโก้ และบัญชีอีเมลสำหรับส่งการแจ้งเตือน',
]),
'## 5 งานคลังสินค้า (Inventory Operations)',
table(['เมนู', 'ขั้นตอนการใช้งาน'], [
['รับสินค้าเข้า', 'เลือกสินค้า ระบุจำนวน ตำแหน่งจัดเก็บ และเอกสารอ้างอิง หากสินค้ามี Lot, Serial Number หรือวันหมดอายุ ให้ระบุเพิ่มเพื่อการสอบกลับ'],
['จ่ายสินค้าออก', 'เลือกสินค้าและจำนวนที่ต้องการจ่าย ระบบจะตรวจสอบยอดคงเหลือก่อนอนุมัติรายการ หากจ่ายเกินยอดระบบจะปฏิเสธ'],
['โอนย้ายสินค้า', 'ระบุตำแหน่งต้นทางและปลายทาง ระบบจะบันทึกเป็นรายการโอนเดียวที่สอบกลับได้'],
['พิมพ์บาร์โค้ด', 'เลือกสินค้าหรือตำแหน่งจัดเก็บเพื่อพิมพ์ฉลากบาร์โค้ด และใช้เครื่องสแกนในหน้าจอที่รองรับ'],
['แนบไฟล์', 'แนบเอกสารประกอบรายการได้ตามประเภทไฟล์ที่อนุญาต'],
]),
'## 6 งานขาย (Sales)',
numbered(['สร้าง**ใบเสนอราคา**ให้ลูกค้า', 'แปลงใบเสนอราคาที่ลูกค้าตอบรับเป็น**ใบสั่งขาย**', 'ออก**ใบแจ้งหนี้**จากใบสั่งขาย ระบบจะบันทึกรายการบัญชีที่เกี่ยวข้องให้อัตโนมัติ', 'กรณีมีการคืนสินค้า ให้บันทึก**ใบรับคืน**และออก**ใบลดหนี้**']),
'ทุกขั้นตอนต้องเปลี่ยนสถานะตามลำดับที่ระบบกำหนด หากเปลี่ยนสถานะข้ามขั้นระบบจะปฏิเสธพร้อมแสดงข้อความ',
'## 7 งานจัดซื้อ (Purchasing)',
numbered(['บันทึก**ใบขอซื้อ**และส่งให้ผู้มีอำนาจอนุมัติ', 'แปลงใบขอซื้อที่อนุมัติแล้วเป็น**ใบสั่งซื้อ**', 'เมื่อได้รับสินค้าให้บันทึก**ใบแจ้งหนี้ซื้อ** ระบบจะรับสินค้าเข้าคลังและบันทึกบัญชีที่เกี่ยวข้อง', 'กรณีคืนสินค้าให้ผู้ขาย ให้บันทึก**ใบคืนสินค้าผู้ขาย**']),
'## 8 งานการเงินและบัญชี (Finance & Accounting)',
table(['งาน', 'รายละเอียด'], [
['ใบวางบิลรับและใบเสร็จรับเงิน', 'บันทึกการวางบิลและการรับชำระจากลูกค้า ผูกกับใบแจ้งหนี้ที่เกี่ยวข้อง'],
['ใบวางบิลจ่ายและใบสำคัญจ่าย', 'บันทึกการวางบิลและการจ่ายชำระให้ผู้ขาย ผูกกับใบแจ้งหนี้ซื้อ'],
['ผังบัญชีและแผนก', 'ผู้ใช้ระดับ Owner หรือ Admin เป็นผู้ดูแลโครงสร้างบัญชี'],
['สมุดรายวันและบัญชีแยกประเภท', 'บันทึกรายการบัญชีจากเอกสารต้นทางหรือบันทึกเองตามสิทธิ์ รายการต้องสมดุลจึงจะบันทึกได้'],
]),
'## 9 รายงาน (Reports)',
bullets([
'รายงานคลังสินค้า ได้แก่ ภาพรวมสต๊อก ความเคลื่อนไหว ความจุคลัง สินค้าใกล้หมด สินค้าหมดอายุ และรายงาน Lot',
'รายงานการเงิน ได้แก่ งบทดลอง งบกำไรขาดทุน งบดุล ภาษีมูลค่าเพิ่ม สมุดรายวัน และความเคลื่อนไหวบัญชีแยกประเภท',
'ทุกรายงานกรอง ดู พิมพ์ และส่งออกได้ ภายใต้ขอบเขตบริษัทและสิทธิ์ของผู้ใช้',
]),
'## 10 การแจ้งเตือน (Notification)',
'ระบบแจ้งเตือนผู้ใช้ที่เกี่ยวข้องแบบ Real-time เมื่อมีการเปลี่ยนสถานะเอกสารที่ต้องดำเนินการต่อ และแจ้งเตือนตามกำหนดเวลาสำหรับสินค้าใกล้หมดและใบแจ้งหนี้ค้างชำระ โดยแจ้งเฉพาะผู้ใช้ที่มีสิทธิ์ในบริบทของบริษัทนั้น',
'## 11 การขอความช่วยเหลือ',
bullets([
'ปัญหาการใช้งานทั่วไป ติดต่อผู้ดูแลระบบของบริษัท',
'ปัญหาที่เกี่ยวกับการทำงานของระบบ ให้แจ้งผ่านช่องทางสนับสนุนที่ระบุในเอกสาร Maintenance Document',
'ขั้นตอนการติดตั้ง ตั้งค่า และกู้คืนระบบ อยู่ในเอกสาร Product Operation Guide',
]),
].join('\n\n'),
secretary: P.ThS, reviewer: P.YaB, approver: P.SeV,
}),
};
}
/** 19. Product Operation Guide. */
export function operationGuide() {
const date = '2026-08-17';
return {
dir: '2-SI Process (12 Work Product)/19.Product Operation Guide',
name: `${CODE} Product Operation Guide ${bud(date)} V1.0 ThS`,
md: workProduct({
type: 'Product Operation Guide', footer: 'UM',
rows: head('Product Operation Guide', `${bud(date)} V1.0 ThS`, [
['Title', 'เอกสารคู่มือปฏิบัติงานสำหรับผู้ดูแลระบบ'],
['Project Period', thRangeLong(START, END)],
['Organizer', ORGANIZER_PM],
['Recorder', RECORDER],
]),
body: [
'## วัตถุประสงค์ (Objective)',
'คู่มือฉบับนี้จัดทำขึ้นเพื่อเป็นแนวทางสำหรับผู้ดูแลระบบ (System Administrator) ในการติดตั้ง ตั้งค่า เฝ้าระวัง สำรองข้อมูล และกู้คืนระบบบริหารจัดการคลังสินค้า เพื่อให้การปฏิบัติงานมีมาตรฐานและกู้คืนระบบได้อย่างรวดเร็ว',
'## 1 ทางเลือกในการติดตั้ง',
table(['ลำดับ', 'วิธีการติดตั้ง', 'กลไก', 'ไฟล์อ้างอิง'], [
[1, 'ติดตั้งแบบ Container (แนะนำ)', 'Docker Compose: php-apache, mariadb, node/pm2', '`docker-compose.yml`, `docker/`'],
[2, 'ติดตั้งแบบ Manual', 'ติดตั้ง PHP, MariaDB และ Node.js แล้วสร้างฐานข้อมูลด้วยสคริปต์', '`setup.php`'],
], ['c']),
'## 2 ขั้นตอนการติดตั้งแบบ Container',
numbered([
'คัดลอก `.env.example` เป็น `.env` หรือรันสคริปต์ `docker/init-env.sh` ซึ่งจะสอบถามรหัสผ่านฐานข้อมูล ชื่อโฮสต์สาธารณะ ค่า `EMIT_SECRET` และข้อมูล SMTP โดยค่าที่เว้นว่างระบบจะสุ่มให้อัตโนมัติ',
'รันคำสั่ง `docker compose up -d --build` เพื่อสร้างและเริ่มบริการทั้งสามส่วน',
'ตรวจสอบว่า Container `php-apache` สร้างไฟล์ `app/config.php` จาก `.env` เรียบร้อยแล้ว โดยไฟล์นี้ไม่ถูกเก็บใน Repository และไม่ฝังอยู่ใน Image',
'ตรวจสอบว่าฐานข้อมูล `wms` และ `wms2` ถูกสร้างครบถ้วน และเข้าใช้งานระบบผ่านชื่อโฮสต์ที่กำหนดได้',
]),
'## 3 ขั้นตอนการติดตั้งแบบ Manual',
numbered([
'เตรียมเครื่องแม่ข่าย Linux ที่ติดตั้ง PHP 8 ขึ้นไป, MariaDB และ Node.js',
'ตั้งค่าไฟล์ `app/config.php` ได้แก่ ข้อมูลเชื่อมต่อฐานข้อมูล `wms` และ `wms2`, `NODE_PUBLIC_URL`, `NODE_EMIT_URL`, `NODE_EMIT_SECRET` และข้อมูล SMTP',
'รัน `setup.php` หนึ่งครั้งเพื่อสร้างโครงสร้างฐานข้อมูลทั้งหมด',
'เริ่มบริการ Node.js (`nodejs/server.js` และ `nodejs/scheduler.js`) ด้วย pm2 ตามไฟล์ `nodejs/ecosystem.config.js`',
]),
'## 4 การตั้งค่าระบบ',
table(['รายการ', 'ที่ตั้ง', 'หมายเหตุ'], [
['ค่าตั้งค่าแอปพลิเคชัน', '`app/config.php`', 'สร้างขึ้นตอนติดตั้ง ไม่นำเข้า Repository'],
['ค่าความลับของสภาพแวดล้อม', '`.env` (Docker) หรือตัวแปรสภาพแวดล้อม (Manual)', 'ยกเว้นจาก Git ด้วย `.gitignore`'],
['ค่าตั้งค่าระดับบริษัท', 'เมนูตั้งค่าในระบบ (`app/setting/`)', 'ข้อมูลบริษัท SMTP และการตั้งค่าการใช้งาน'],
['เขตเวลา', '`$time_zone` ใน `app/config.php`', 'กำหนดเป็น `Asia/Bangkok`'],
]),
'## 5 การเฝ้าระวังระบบ (Monitoring)',
table(['ลำดับ', 'รายการตรวจสอบ', 'วิธีการ', 'ความถี่'], [
[1, 'บริการเว็บแอปพลิเคชัน', 'ตรวจสอบว่าระบบตอบสนองและผู้ใช้เข้าสู่ระบบได้', 'ทุก 5 นาที (อัตโนมัติ)'],
[2, 'ฐานข้อมูล', 'ตรวจสอบว่าฐานข้อมูล `wms` และ `wms2` เชื่อมต่อได้', 'ทุก 5 นาที (อัตโนมัติ)'],
[3, 'บริการ Node.js', 'ตรวจสอบสถานะ `server.js` และ `scheduler.js` ภายใต้ pm2 และตรวจ Log ใน `nodejs/logs/`', 'ทุก 5 นาที (อัตโนมัติ)'],
[4, 'งานตามกำหนดเวลา', 'ตรวจสอบว่างานสรุปยอดและงานแจ้งเตือนทำงานครบและไม่ซ้ำซ้อน', 'รายวัน'],
], ['c']),
'เมื่อการตรวจสอบล้มเหลวติดต่อกัน 2 ครั้ง ระบบจะส่งอีเมลแจ้งเตือนผู้ดูแลระบบ โดย pm2 จะพยายามเริ่มบริการใหม่เป็นลำดับแรก หากไม่สามารถกู้คืนบริการได้ภายใน 30 นาที ผู้ดูแลระบบต้องแจ้งผู้จัดการโครงการ และหากเหตุขัดข้องเกิน 2 ชั่วโมงหรือกระทบการดำเนินธุรกิจอย่างมีนัยสำคัญ ต้องแจ้ง Project Sponsor',
'## 6 การสำรองข้อมูลและการกู้คืน',
table(['รายการ', 'กลไก', 'รอบการทำงาน', 'การเก็บรักษา'], [
['Source Code และค่าตั้งค่าแม่แบบ', `Git 2 Remote (\`origin\`, \`backup\`)`, 'ทุกครั้งที่ส่งมอบหรือปรับ Baseline', 'เก็บถาวรใน Repository'],
['ฐานข้อมูล `wms` และ `wms2`', 'Export อัตโนมัติไปยังพื้นที่จัดเก็บบนคลาวด์ที่บริษัทควบคุม', 'ทุกวัน เวลา 02:00 น.', 'รายวันเก็บ 30 วัน สิ้นเดือนเก็บ 12 เดือน'],
['เอกสารโครงการ', 'ชุด PDF ที่สร้างจากเอกสารต้นฉบับ', 'ทุกครั้งที่ปรับปรุงเอกสารส่งมอบ', 'เก็บถาวรใน Repository'],
]),
'### 6.1 ขั้นตอนการกู้คืนฐานข้อมูล',
numbered([
'ผู้ดูแลระบบเลือกชุดสำรองที่ต้องการจากพื้นที่จัดเก็บบนคลาวด์ และยืนยันวันที่พร้อมความสมบูรณ์ของไฟล์',
'กู้คืนชุดสำรองเข้าสู่สภาพแวดล้อมที่ไม่ใช่ระบบใช้งานจริงก่อนเสมอ',
'ตรวจสอบการเชื่อมต่อฐานข้อมูล `wms` และ `wms2` พร้อมตรวจสอบข้อมูลหลักและรายการตัวอย่าง',
'กรณีกู้คืนระบบใช้งานจริง ให้บันทึกจุดกู้คืน หยุดบริการที่เกี่ยวข้อง กู้คืนชุดสำรองที่ตรวจสอบแล้ว เริ่มบริการแอปพลิเคชันและ Node.js ใหม่ แล้วตรวจสอบสถานะตามหัวข้อ 5',
'กรณีการสำรองข้อมูลล้มเหลวหรือไม่ทำงานตามกำหนด ผู้ดูแลระบบต้องตรวจสอบสาเหตุและสั่งทำงานซ้ำ',
]),
`การทดสอบกู้คืนดำเนินการเมื่อ ${thLong(OPS_CLOSE_DATE)} โดยกู้คืนชุดสำรองลงในสภาพแวดล้อมที่ไม่ใช่ระบบใช้งานจริงสำเร็จ ตรวจสอบการเข้าถึงฐานข้อมูลและข้อมูลตัวอย่างครบถ้วน และผู้จัดการโครงการได้ทบทวนผลการทดสอบในขั้นตอนปิดโครงการ`,
'## 7 การปิดรายการควบคุมด้านปฏิบัติการ',
table(['ลำดับ', 'รายการควบคุม', 'ผู้รับผิดชอบ', 'สถานะ', 'หลักฐานการปิดรายการ'], [
['OP-001', 'การสำรองและกู้คืนฐานข้อมูล `wms` และ `wms2` แบบอัตโนมัติ', 'System Administrator', `ปิดรายการ ${thLong(OPS_CLOSE_DATE)}`, 'หัวข้อ 6 ระบุรอบการสำรอง ที่จัดเก็บ การเก็บรักษา ขั้นตอนกู้คืน และผลการทดสอบกู้คืน'],
['OP-002', 'การเฝ้าระวังระบบและการแจ้งเตือนเมื่อเกิดเหตุขัดข้อง', 'System Administrator', `ปิดรายการ ${thLong(OPS_CLOSE_DATE)}`, 'หัวข้อ 5 ระบุรอบการตรวจสอบ เงื่อนไขการแจ้งเตือน ผู้รับแจ้ง และขั้นตอนการยกระดับ'],
], ['c']),
'## 8 การจัดการผู้ใช้งานและสิทธิ์',
bullets([
'ผู้ใช้ระดับ Owner หรือ Admin จัดการผู้ใช้งาน บทบาท และสิทธิ์การเข้าถึงแอปพลิเคชันจากเมนูตั้งค่า',
'การเปลี่ยนบทบาทมีผลกับการทำงานครั้งถัดไปของผู้ใช้รายนั้น',
'ระบบอนุญาตให้ใช้งานได้ครั้งละหนึ่ง Session ต่อบัญชี เพื่อป้องกันการใช้บัญชีร่วมกัน',
]),
].join('\n\n'),
secretary: P.ThS, reviewer: P.NoC, approver: P.SeV,
}),
};
}
/** 20. Maintenance Document. */
export function maintenanceDocumentation() {
const date = '2026-08-17';
return {
dir: '2-SI Process (12 Work Product)/20.Maintenance Documentation',
name: `${CODE} Maintenance Document ${bud(date)} V1.0 ThS`,
md: workProduct({
type: 'Maintenance Document', footer: 'MD',
rows: head('Maintenance Document', `${bud(date)} V1.0 ThS`, [
['Title', 'เอกสารคู่มือการบำรุงรักษาระบบ'],
['Project Period', thRangeLong(START, END)],
['Organizer', ORGANIZER],
['Recorder', RECORDER],
]),
body: [
'## วัตถุประสงค์ (Objective)',
'เพื่อกำหนดแนวทางการบำรุงรักษาระบบหลังจากส่งมอบและเปิดใช้งานจริง ครอบคลุมการแก้ไขข้อผิดพลาด การปรับปรุง และการป้องกัน เพื่อให้ระบบมีความเสถียร ปลอดภัย ต่อเนื่อง และสอดคล้องกับความต้องการของผู้ใช้งาน',
'## ขอบเขตการบำรุงรักษา (Maintenance Scope)',
table(['ID', 'Type'], [
['MD-001', 'Web Server (PHP 8, Apache, Linux Server)'],
['MD-002', `Application Modules (${SCOPE.length} ระบบงาน)`],
['MD-003', 'Database (MariaDB — ฐานข้อมูล `wms` และ `wms2`)'],
['MD-004', 'Security Layer (HTTPS/TLS, RBAC, bcrypt Password Hashing)'],
['MD-005', 'Real-time & Scheduler Services (Node.js, Socket.IO, pm2)'],
['MD-006', `Software Components: Git Server (\`${ORIGIN}\`)`],
['MD-007', `Project Repository (Backup): Git Remote สำรอง (\`${BACKUP}\`) และชุดสำรองฐานข้อมูลบนคลาวด์`],
], ['c']),
'## ประเภทการบำรุงรักษา',
table(['ลำดับ', 'ประเภทการบำรุงรักษา', 'รายละเอียด'], [
[1, 'Corrective Maintenance', 'แก้ไขข้อผิดพลาด (Bug Fix) และตรวจสอบ Error Log'],
[2, 'Adaptive Maintenance', 'ปรับระบบให้รองรับ Browser หรือระบบปฏิบัติการรุ่นใหม่'],
[3, 'Perfective Maintenance', 'ปรับปรุงประสิทธิภาพและเพิ่มความสามารถตามที่ตกลง'],
[4, 'Preventive Maintenance', 'ปรับปรุงความปลอดภัย (Patch Security) และทดสอบการสำรอง/กู้คืนข้อมูล'],
], ['c']),
'## กิจกรรมการบำรุงรักษา (Maintenance Activities)',
table(['ลำดับ', 'กิจกรรม', 'รายละเอียด', 'ความถี่', 'ผู้รับผิดชอบ'], [
[1, 'ตรวจสอบ Error Log', 'วิเคราะห์ Log ของแอปพลิเคชันและบริการ Node.js แล้วแก้ไขข้อผิดพลาดที่พบ', 'รายสัปดาห์', 'System Admin'],
[2, 'Patch Security', 'ปรับปรุงแพตช์ความปลอดภัยของ PHP, MariaDB, Node.js และใบรับรอง TLS', 'รายเดือน หรือเมื่อมี Critical Patch', 'System Admin'],
[3, 'Backup & Recovery Test', 'ตรวจสอบชุดสำรองรายวันและทดสอบกู้คืนสู่สภาพแวดล้อมทดสอบ', 'สำรองทุกวัน ทดสอบกู้คืนทุกไตรมาส', 'System Admin'],
[4, 'Monitor Uptime', 'ตรวจสอบความพร้อมใช้งานของเว็บ ฐานข้อมูล และบริการ Node.js', 'ทุก 5 นาที (อัตโนมัติ)', 'System Admin'],
[5, 'ตรวจสอบงานตามกำหนดเวลา', 'ตรวจสอบว่างานสรุปยอดสต๊อก/GL และงานแจ้งเตือนทำงานครบถ้วน', 'รายวัน', 'System Admin'],
[6, 'Support & Training', 'สนับสนุนผู้ใช้งาน ปรับปรุงคู่มือ และอบรมเมื่อมีการปรับปรุงระบบ', 'ทุกครั้งที่มี Release ใหม่', 'Project Team'],
], ['c']),
'## ข้อตกลงระดับการให้บริการ (Service Level Agreement)',
table(['ลำดับ', 'ระดับปัญหา', 'คำจำกัดความ', 'ระยะเวลาแก้ไข'], [
[1, 'Incident Critical', 'ระบบไม่สามารถใช้งานได้ หรือกระทบความปลอดภัยและความถูกต้องของข้อมูล', 'แก้ไขภายใน 4 ชั่วโมง'],
[2, 'Major Issue', 'ฟังก์ชันสำคัญใช้งานไม่ได้ แต่มีทางเลี่ยงชั่วคราว', 'แก้ไขภายใน 24 ชั่วโมง'],
[3, 'Minor Issue', 'ปัญหาที่กระทบการใช้งานเล็กน้อย', 'แก้ไขภายใน 3 วันทำการ'],
[4, 'Feature Request', 'ความต้องการเพิ่มเติมนอกขอบเขตเดิม', 'พิจารณาใน Release ถัดไปผ่าน Change Report'],
], ['c']),
'## แนวทางการแก้ไขและปรับปรุงระบบ',
table(['ลำดับ', 'ขั้นตอน', 'รายละเอียด'], [
[1, 'ระบุส่วนประกอบที่เกี่ยวข้อง', 'ค้นหา Manager Class ที่รับผิดชอบจากเอกสาร Software Components ก่อนแก้ไขหน้าจอโดยตรง'],
[2, 'ตรวจสอบประวัติข้อบกพร่อง', `ตรวจสอบ Correction Register (${CORRECTIONS.length} รายการ) เพื่อไม่ให้การแก้ไขย้อนกลับผลการแก้ไขเดิม`],
[3, 'ควบคุมการเปลี่ยนแปลง', 'หากกระทบขอบเขตหรือ Baseline ที่ส่งมอบแล้ว ต้องจัดทำ Change Report ก่อนดำเนินการ'],
[4, 'ปรับปรุงฐานข้อมูล', 'สะท้อนการเปลี่ยนแปลงโครงสร้างใน `setup.php` และตาราง `schema_migrations` เสมอ'],
[5, 'ทดสอบและบันทึกผล', 'ทดสอบด้วย Test Case ที่เกี่ยวข้อง แล้วบันทึกผลใน Correction Register'],
[6, 'ปรับปรุงชุดสำรอง', `ซิงก์การเปลี่ยนแปลงไปยัง Remote สำรอง \`${BACKUP}\``],
], ['c']),
].join('\n\n'),
secretary: P.ThS, reviewer: P.NoC, approver: P.SeV,
}),
};
}
/** 21. Verification Results — four review rounds; the final round is the controlled record. */
export function verificationResults() {
const ROUNDS = [
{ v: 'V0.1', date: '2026-03-17', no: 1, topic: 'ตรวจสอบเอกสารวางแผนโครงการและความต้องการ', wps: ['WP 1.0', 'WP 2.0'] },
{ v: 'V0.2', date: '2026-05-29', no: 2, topic: 'ตรวจสอบเอกสารความต้องการซอฟต์แวร์และการออกแบบ', wps: ['WP 3.0', 'WP 4.0', 'WP 5.0'] },
{ v: 'V0.3', date: '2026-07-31', no: 3, topic: 'ตรวจสอบชุดทดสอบและการสอบกลับ', wps: ['WP 6.0'] },
{ v: 'V1.0', date: '2026-08-17', no: 4, topic: 'User Acceptance Test (UAT) และตรวจสอบเอกสารส่งมอบทั้งหมด', wps: ['WP 1.0', 'WP 2.0', 'WP 3.0', 'WP 4.0', 'WP 5.0', 'WP 6.0', 'WP 7.0', 'WP 8.0', 'WP 9.0', 'WP 10.0', 'WP 11.0'] },
];
const CHECKS = {
'WP 1.0': ['Software Project Plan', [
['รายละเอียดและความถูกต้องของ Header ของเอกสาร', 'มีรายละเอียดใน Header ครบถ้วน'],
['การ Run Version ของเอกสารที่ระบุใน Header ถูกต้องและสัมพันธ์กับชื่อไฟล์', 'ระบุเวอร์ชันและวันที่ตรงกับชื่อไฟล์'],
['ระบุรายละเอียดหัวข้อ 1 Manufacture, 2 Overview, 3 Goals and Scope ครบถ้วน', 'มีข้อมูลครบถ้วนถูกต้อง'],
['ใน 3.3 Work Products มีรายการสิ่งส่งมอบพร้อมรหัส เช่น WP 1.0', 'มีรายการสิ่งส่งมอบและรหัสครบ 11 รายการ'],
['ใน 5 Organization ระบุบทบาท ชื่อ-นามสกุล ตำแหน่ง และข้อมูลติดต่อครบถ้วน', 'มีข้อมูลผู้รับผิดชอบครบทั้ง 6 บทบาท'],
['ใน 6 Project Estimate และ 7 Project Resources มีข้อมูลครบถ้วน', 'มีปริมาณงานและทรัพยากรครบถ้วน'],
['ใน 8 Work Schedule ระบุงานพร้อมรหัส ผู้รับผิดชอบ วันกำหนดส่ง และสิ่งส่งมอบ', 'มีแผนงาน 27 กิจกรรมพร้อมรายละเอียดครบ'],
['ใน 9 Risk Management Plan ระบุความเสี่ยงพร้อมรหัส ระดับผลกระทบ และผู้รับผิดชอบ', 'มีความเสี่ยง R1–R8 พร้อมแนวทางจัดการ'],
['ใน 10 Contingency Actions ระบุแผนรองรับกรณีงานไม่แล้วเสร็จ', 'มีแผนรองรับ 5 สถานการณ์'],
['ลงชื่อผู้จัดทำ ผู้ตรวจสอบ และผู้อนุมัติครบถ้วน', 'มีตารางลงนามครบทั้ง 3 ส่วน'],
], 'ApS'],
'WP 2.0': ['Customer Requirements', [
['รายละเอียดและความถูกต้องของ Header ของเอกสาร', 'มีรายละเอียดใน Header ครบถ้วน'],
['จัดความต้องการแต่ละรายการลงในหมวด CR01–CR14 อย่างถูกต้อง', 'จัดหมวดครบทั้ง 14 หมวด'],
['รหัสประจำรายการ เช่น CR01:001 เขียนและเรียงลำดับถูกต้อง', 'รหัสเรียงลำดับถูกต้องทุกรายการ'],
['ช่อง Result มีข้อสรุปครบทุกรายการ ไม่มีรายการที่ไม่มีข้อสรุป', `มีผลสรุป A ครบทั้ง ${CRS.length} รายการ`],
['ลงชื่อผู้จัดทำและผู้อนุมัติซึ่งเป็นฝ่ายลูกค้าเรียบร้อย', 'มีตารางลงนามครบถ้วน'],
], 'NoC'],
'WP 3.0': ['Software Requirements', [
['รายละเอียดและความถูกต้องของ Header ของเอกสาร', 'มีรายละเอียดครบถ้วนถูกต้อง'],
['จัดความต้องการซอฟต์แวร์ลงในหมวด SR01–SR09 อย่างถูกต้อง', 'จัดหมวดครบทั้ง 9 หมวด'],
['แต่ละหมวด SR01–SR09 มีรายการตามความจำเป็นครบถ้วน', 'มีรายการครบ 49 รายการ'],
['รหัสประจำรายการ เช่น SR01:001 เขียนและเรียงลำดับถูกต้อง', 'รหัสเรียงลำดับถูกต้องทุกรายการ'],
['ช่อง Remark ระบุความสัมพันธ์กับ CR ครบถ้วน', 'ทุกรายการอ้างอิงกลับไปยัง CR ที่เกี่ยวข้อง'],
['ลงชื่อผู้จัดทำและผู้อนุมัติเรียบร้อย', 'มีตารางลงนามครบถ้วน'],
], 'NoC'],
'WP 4.0': ['Software Design', [
['รายละเอียดและความถูกต้องของ Header ของเอกสาร', 'มีรายละเอียดครบถ้วนถูกต้อง'],
['ใน High Level Design มี Use Case, Component และ Deployment Diagram', 'มีครบทั้ง 3 ส่วน'],
['ใน User Interface Design มีผังหน้าจอที่จะใช้ในระบบ', 'มีผังหน้าจอครบทุกกลุ่มโมดูล'],
['มีหัวข้อ Software Baseline ระบุสิ่งที่ถูกกำหนดเป็น Baseline วันที่ และผู้อนุมัติ', 'มีหัวข้อ Software Baseline ครบถ้วน พร้อมอ้างอิง Software Configuration และ Traceability Record'],
['ใน Software Unit มีรหัสกำกับแต่ละหน่วย เช่น UN01.001 อย่างเป็นระเบียบ', 'มีรหัสครบ 45 หน่วย'],
['ใน Software Unit มี Description และ Functional Interfaces Detail ครบทุกรายการ', 'มีรายละเอียดครบทุกหน่วย'],
['ใน Software Unit ระบุ References ที่สัมพันธ์กับ SR ครบถ้วน', 'อ้างอิง SR ถูกต้องครบทุกหน่วย'],
['ลงชื่อผู้จัดทำและผู้อนุมัติเรียบร้อย', 'มีตารางลงนามครบถ้วน'],
], 'NoC'],
'WP 5.0': ['Change Report', [
['รายละเอียดและความถูกต้องของ Header ของเอกสาร', 'มีรายละเอียดครบทั้ง 3 ฉบับ'],
['ส่วน Requesting เขียนรายละเอียดถูกต้องครบถ้วนทุกฉบับ', 'มีรายละเอียดครบทุกฉบับ'],
['ส่วน Impact Analysis ได้รับการประเมินผลกระทบครบทุกฉบับ', 'มีการประเมินผลกระทบ 5 ด้านครบทุกฉบับ'],
['มีการลงนามอนุมัติโดยคณะพิจารณา (CAB) ครบทุกฉบับ', 'มีตารางพิจารณาและลงนามครบถ้วน'],
], 'ApS'],
'WP 6.0': ['Test Case and Test Procedures', [
['รายละเอียดและความถูกต้องของ Header ของเอกสาร', 'มีรายละเอียดครบถ้วนถูกต้อง'],
['ใน Test Case Specification มีรายการทดสอบพร้อมรหัสเรียงลำดับ', 'มีรายการครบ 45 Test Case'],
['Test Item ระบุ Software Unit ที่ทดสอบโดยอ้างรหัส เช่น UN01.001', 'อ้างอิง Software Unit ครบทุกรายการ'],
['Input Specification ระบุขั้นตอนและข้อมูลนำเข้าอย่างชัดเจน', 'มีรายละเอียดครบทุกรายการ'],
['Output Specification ระบุผลลัพธ์ที่คาดหวังอย่างชัดเจน', 'มีรายละเอียดครบทุกรายการ'],
['Environment Needs, Special Procedural Required และ Intercase Dependency ระบุตามความจำเป็น', 'มีรายละเอียดครบถ้วน'],
['ส่วนผลการทดสอบระบุ Test Date และ Status ครบถ้วนไม่มีช่องว่าง', 'มีผลการทดสอบครบทุกรายการ'],
['ลงชื่อผู้จัดทำและผู้อนุมัติเรียบร้อย', 'มีตารางลงนามครบถ้วน'],
], 'PaNg'],
'WP 7.0': ['Validation Results', [
['รายละเอียดและความถูกต้องของ Header ของเอกสาร', 'มีรายละเอียดครบถ้วนถูกต้อง'],
['ระบุสถานการณ์ทดสอบการยอมรับครบตามความต้องการของลูกค้า', 'มี 12 สถานการณ์ครอบคลุมทุกระบบงาน'],
['ระบุผลการทดสอบและผู้ทดสอบครบทุกรายการ', 'มีผลและผู้ทดสอบครบทุกสถานการณ์'],
['ลงชื่อผู้ทดสอบฝ่ายลูกค้าเรียบร้อย', 'มีตารางลงนามครบถ้วน'],
], 'PaNg'],
'WP 8.0': ['Software User Document', [
['รายละเอียดและความถูกต้องของ Header ของเอกสาร', 'มีรายละเอียดครบถ้วนถูกต้อง'],
['เนื้อหาครอบคลุมการใช้งานทุกระบบงานที่ส่งมอบ', 'ครอบคลุมครบทุกระบบงาน'],
['ใช้ถ้อยคำถูกต้องและสอดคล้องกับหน้าจอจริง', 'ตรวจสอบแล้วสอดคล้อง'],
['ลงชื่อผู้จัดทำและผู้อนุมัติเรียบร้อย', 'มีตารางลงนามครบถ้วน'],
], 'YaB'],
'WP 9.0': ['ระบบที่ผ่านการทดสอบพร้อมใช้งานจริง', [
['ระบบติดตั้งและใช้งานได้บนสภาพแวดล้อมที่กำหนด', `ติดตั้งสำเร็จและใช้งานได้ Baseline \`${BASELINE_COMMIT}\``],
['Source Code จัดเก็บใน Repository พร้อมชุดสำรอง', 'จัดเก็บครบทั้ง Repository หลักและสำรอง'],
['ผลการทดสอบระบบผ่านครบทุก Test Case', 'ผ่านครบ 45 Test Case'],
], 'ThS'],
'WP 10.0': ['Product Operation Guide', [
['รายละเอียดและความถูกต้องของ Header ของเอกสาร', 'มีรายละเอียดครบถ้วนถูกต้อง'],
['ระบุขั้นตอนการติดตั้งและตั้งค่าครบถ้วน', 'มีทั้งแบบ Container และแบบ Manual'],
['ระบุการเฝ้าระวัง การสำรอง และการกู้คืนข้อมูล', 'มีครบถ้วนพร้อมผลการทดสอบกู้คืน'],
['ลงชื่อผู้จัดทำและผู้อนุมัติเรียบร้อย', 'มีตารางลงนามครบถ้วน'],
], 'ThS'],
'WP 11.0': ['Maintenance Document', [
['รายละเอียดและความถูกต้องของ Header ของเอกสาร', 'มีรายละเอียดครบถ้วนถูกต้อง'],
['ระบุขอบเขต ประเภท และกิจกรรมการบำรุงรักษาครบถ้วน', 'มีครบทั้ง 4 ประเภทและ 6 กิจกรรม'],
['ระบุข้อตกลงระดับการให้บริการ (SLA)', 'มี SLA ครบ 4 ระดับ'],
['ลงชื่อผู้จัดทำและผู้อนุมัติเรียบร้อย', 'มีตารางลงนามครบถ้วน'],
], 'ThS'],
};
return ROUNDS.map((r) => {
const rows = [];
let n = 0;
for (const wp of r.wps) {
const [wpName, checks, owner] = CHECKS[wp];
rows.push([`${wp} ${wpName}`, '', '', '', '', '']);
checks.forEach((c, i) => {
n += 1;
rows.push([`VR${String(r.no).padStart(2, '0')}.${wp.replace(/\D/g, '').padStart(3, '0')}.${String(i + 1).padStart(3, '0')}`, c[0], c[1], 'Passed', P[owner].id, '']);
});
}
return {
dir: '2-SI Process (12 Work Product)/21.Verification Result',
name: `${CODE} Verification Results ${bud(r.date)} ${r.v} PaNg`,
md: workProduct({
type: 'Verification Results', footer: 'VeR',
rows: head('Verification Results', `${bud(r.date)} ${r.v} PaNg`, [
['Title', 'บันทึกการตรวจสอบตามข้อกำหนดของมาตรฐาน'],
['รอบตรวจสอบ', `รอบที่ ${r.no} (${thLong(r.date)})`, 'หัวข้อ', r.topic],
['Organizer', ORGANIZER],
['Recorder', RECORDER],
]),
body: [
'## วัตถุประสงค์ (Objective)',
'การตรวจสอบ (Verification) จัดทำขึ้นเพื่อยืนยันความถูกต้องและความครบถ้วนของสิ่งส่งมอบ (Work Products) ตามมาตรฐาน ISO/IEC 29110 โดยวางแผนตรวจสอบเป็นรอบระหว่างการดำเนินโครงการ และตรวจสอบรอบสุดท้ายก่อนส่งมอบระบบ เพื่อลดความเสี่ยงด้านคุณภาพ ความล่าช้า และค่าใช้จ่ายที่เกิดจากการแก้ไขย้อนหลัง',
'## Deliverables under Review',
table(['รหัส', 'สิ่งส่งมอบที่ตรวจสอบในรอบนี้'], r.wps.map((wp) => [wp, CHECKS[wp][0]]), ['c']),
'## Risk & Constraints Note',
numbered([
'เจ้าหน้าที่ควบคุมเอกสารต้องตรวจสอบแต่ละรายการอย่างละเอียด และต้องมีหลักฐานเพียงพอที่จะสรุปผลว่าผ่าน',
'ผู้ปฏิบัติงานที่เกี่ยวข้องควรร่วมรับฟังผลการตรวจสอบ เพื่อให้แก้ไขได้ทันทีเมื่อพบประเด็น',
'การตรวจสอบแต่ละครั้งไม่ควรถูกขัดจังหวะ ซึ่งจะทำให้การตรวจสอบเลื่อนออกไป',
'ห้ามให้ผู้อื่นตรวจสอบแทนผู้ที่ได้รับมอบหมาย',
]),
'## ผลการตรวจสอบ',
table(['ID', 'Verification Item', 'Evidence', 'Result', 'Owner', 'Comment / Risk / Recommendation'], rows),
'## สรุปผลการตรวจสอบรอบนี้',
table(['รายการ', 'จำนวน'], [
['รายการตรวจสอบทั้งหมด', n],
['ผลผ่าน (Passed)', n],
['ผลไม่ผ่าน (Failed)', 0],
['ประเด็นคงค้าง', 0],
], ['', 'r']),
r.no === 4
? `รอบตรวจสอบนี้เป็นรอบสุดท้ายก่อนส่งมอบ ครอบคลุมสิ่งส่งมอบทั้งหมด ${r.wps.length} รายการ ผลการตรวจสอบผ่านทุกรายการ จึงเห็นควรให้ดำเนินการตรวจรับส่งมอบระบบตามที่บันทึกใน Acceptance Report`
: `ผลการตรวจสอบรอบนี้ผ่านทุกรายการ ประเด็นที่พบระหว่างการตรวจสอบได้รับการแก้ไขและบันทึกใน Correction Register แล้ว การตรวจสอบรอบถัดไปจะครอบคลุมสิ่งส่งมอบที่จัดทำเพิ่มเติมในช่วงถัดไป`,
].join('\n\n'),
secretary: P.PaNg, reviewer: P.YaB, approver: P.SeV,
}),
};
});
}
/** 22. Validation Results — customer UAT. */
export function validationResults() {
const date = '2026-08-14';
const SCENARIOS = [
['การลงทะเบียนและกำหนดสิทธิ์ผู้ใช้งาน', ['CR01:001', 'CR01:002', 'CR01:003', 'CR01:004'], 'ผู้ใช้เข้าสู่บริษัทที่ถูกต้องและเห็นเฉพาะเมนูที่ได้รับสิทธิ์'],
['การตั้งค่าข้อมูลหลักคลังสินค้าและสินค้า', ['CR01:005', 'CR01:006'], 'ตั้งค่าคลังสินค้า พื้นที่ ช่องจัดเก็บ และสินค้าได้ครบตามโครงสร้างที่ใช้จริง'],
['การรับสินค้าเข้าคลัง', ['CR01:007'], 'บันทึกรับเข้าแล้วยอดคงเหลือและความเคลื่อนไหวถูกต้อง'],
['การจ่ายสินค้าออกจากคลัง', ['CR01:008'], 'จ่ายออกภายในยอดคงเหลือได้ และระบบปฏิเสธการจ่ายเกินยอด'],
['การโอนย้ายสินค้าระหว่างตำแหน่ง', ['CR01:009'], 'ยอดต้นทางและปลายทางสมดุลและสอบกลับได้เป็นรายการเดียว'],
['การติดตาม Lot, Serial Number และวันหมดอายุ', ['CR01:010', 'CR01:012'], 'ข้อมูลติดตามคงอยู่และแสดงในรายงานที่เกี่ยวข้อง พร้อมพิมพ์บาร์โค้ดได้'],
['กระบวนการขาย', ['CR01:013'], 'ใบเสนอราคา ใบสั่งขาย ใบแจ้งหนี้ และใบรับคืน ทำงานตามลำดับสถานะที่กำหนด'],
['กระบวนการจัดซื้อ', ['CR01:014'], 'ใบขอซื้อ ใบสั่งซื้อ ใบแจ้งหนี้ซื้อ และใบคืนผู้ขาย ทำงานตามลำดับสถานะที่กำหนด'],
['งานการเงินและบัญชี', ['CR01:015', 'CR01:016'], 'ใบเสร็จ ใบสำคัญจ่าย และรายการบัญชีสมดุลและตรวจสอบได้'],
['รายงานคลังสินค้าและรายงานการเงิน', ['CR01:011', 'CR01:017', 'CR01:020'], 'รายงานแสดงผลตรงตามตัวกรองและขอบเขตสิทธิ์'],
['การแจ้งเตือนและงานตามกำหนดเวลา', ['CR01:021', 'CR01:022'], 'ผู้ใช้ที่เกี่ยวข้องได้รับการแจ้งเตือนโดยไม่ซ้ำซ้อน'],
['การแยกข้อมูลระหว่างบริษัทและคลังสินค้า', ['CR01:024', 'CR08:004'], 'การเข้าถึงข้อมูลข้ามบริษัทหรือคลังที่ไม่ได้รับสิทธิ์ถูกปฏิเสธ'],
];
const rows = SCENARIOS.map((s, i) => [i + 1, s[1].map((c) => traceOf(c).tc).join(', '), s[1].join(', '), s[0], s[2], 'Passed', P.SeV.id]);
return {
dir: '2-SI Process (12 Work Product)/22.Validation Result',
name: `${CODE} Validation Results ${bud(date)} V1.0 PaNg`,
md: workProduct({
type: 'Validation Result', footer: 'VaR (UAT)',
rows: head('Validation Result (UAT)', `${bud(date)} V1.0 PaNg`, [
['Title', 'บันทึกการยืนยันความต้องการกับผู้ใช้งาน'],
['Project Period', thRangeLong(START, END)],
['Organizer', ORGANIZER],
['Recorder', RECORDER],
['Responsible', `${P.SeV.th} (Project Sponsor / ตัวแทนลูกค้า)`],
]),
body: [
'## วัตถุประสงค์ (Objective)',
'เพื่อยืนยันว่าระบบที่พัฒนาตรงตามความต้องการของลูกค้า (Customer Requirements) สามารถใช้งานได้จริง มีประสิทธิภาพ มีความปลอดภัย และพร้อมเปิดใช้งานจริง (Go-Live)',
'## สภาพแวดล้อมและผู้ทดสอบ',
table(['หัวข้อ', 'รายละเอียด'], [
['สภาพแวดล้อมที่ใช้ทดสอบ', 'สภาพแวดล้อมใช้งานจริงของลูกค้า'],
['ผู้ทดสอบ', `${P.SeV.th} (Project Sponsor / ตัวแทนลูกค้า)`],
['ผู้บันทึกผล', `${P.PaNg.th} (QA/Tester)`],
['ช่วงเวลาทดสอบ', thRangeLong(TEST_FROM, TEST_TO)],
['สถานะ Repository ที่ใกล้เคียงที่สุด', `Commit \`${TEST_STATE_COMMIT}\``],
]),
'## ตารางสรุป Validation Result',
table(['No', 'Test Case', 'CR ID', 'Customer Req. Topic', 'ผลลัพธ์ที่คาดหวัง', 'Status', 'Tester'], rows, ['c', '', '', '', '', 'c', 'c']),
'## สรุปผลการทดสอบการยอมรับ',
table(['รายการ', 'จำนวน'], [
['สถานการณ์ทดสอบทั้งหมด', SCENARIOS.length],
['ผ่าน (Passed)', SCENARIOS.length],
['ไม่ผ่าน (Failed)', 0],
['ค้างการทดสอบ', 0],
], ['', 'r']),
`ตัวแทนลูกค้าได้ทดสอบการยอมรับครบทุกสถานการณ์บนสภาพแวดล้อมใช้งานจริง ผลการทดสอบผ่านทั้งหมด ไม่พบประเด็นที่ขัดขวางการเปิดใช้งาน จึงยืนยันความพร้อมของระบบสำหรับการตรวจรับส่งมอบ ซึ่งบันทึกไว้ใน Acceptance Report เมื่อ ${thLong(ACCEPT_DATE)}`,
].join('\n\n'),
secretary: P.PaNg, reviewer: P.NoC, approver: P.SeV,
}),
};
}