สารบัญ

📘 คู่มือการใช้งาน MobileHub v2

ระบบจัดการร้านมือถือ Multi-Tenant SaaS

เวอร์ชัน 2.0 | อัปเดตล่าสุด: 14 พฤษภาคม 2569 (รับเครื่อง 3-step guided flow: intake → checklist → receipt + auto-preview / print colors fix / intake & warranty 1-page / SMALL_RECEIPT logo / repair-intake required fields)

📋 สารบัญ

หัวข้อรายละเอียด
1. บทนำภาพรวมระบบ, ความสามารถหลัก, บทบาท, ตารางสิทธิ์
2. เริ่มต้นใช้งานสมัครใช้งาน, ยืนยัน OTP, เข้าสู่ระบบ, แดชบอร์ด, แนะนำระบบ (Tour), โปรไฟล์
3. คลังสินค้าสต็อกมือถือ, อุปกรณ์เสริม, รอบนับสต็อก, โอนระหว่างสาขา
4. รับซื้อ-ตีราคารับซื้อมือถือ, ตีราคา, Checklist อุปกรณ์, เกรด A/B/C/D
5. งานซ่อมรับเครื่อง, งานช่าง, รายการทั้งหมด, คลังอะไหล่, Template ราคาซ่อม, ผู้จัดหา + สั่งอะไหล่, Checklist, เอกสาร, ติดตามออนไลน์ลูกค้า, ประกัน
6. ขายสินค้า (POS)ตะกร้าสินค้า, รับเทรดเครื่องเก่า, วิธีชำระเงิน, PromptPay, หน้าจอลูกค้า, พักบิล, ประวัติ + reprint + void + refund + Z report, ใบแจ้งหนี้ B2B
7. ประกันสินค้าเพิ่มประกัน, ติดตามหมดอายุ, ประวัติ
8. ลูกค้าเพิ่ม/แก้ไข/ค้นหาลูกค้า, ประวัติการซื้อ
9. ลงเวลาทำงานบันทึกเวลาเข้า-ออก, QR Code Kiosk
10. เงินเดือนคำนวณเงินเดือน, อนุมัติ, บันทึกการจ่าย
10A. ค่าใช้จ่ายดำเนินงานบันทึก rent / utility / fuel / marketing — feed PIT ACTUAL + ภ.พ.30 input VAT + WHT
10B. กะการขาย (Cashier Shift)เปิด-ปิดกะ + ลิ้นชักเงินสด — variance ระหว่าง expected vs actual + บังคับเปิดกะก่อนขาย (CASHIER/SALES default, ปรับได้)
11. รายงานยอดขาย, การซ่อม, การรับซื้อ, สินค้าคงเหลือ, การเงิน
11A. ภาษี (เมนูใหม่)ภาพรวม + ภ.ง.ด.94/90 (PIT) + ภ.ง.ด.50/51 (CIT) + ภ.พ.30 (VAT) + ภ.ง.ด.3/53 (WHT) + ตั้งค่าภาษี
12. เอกสารพิมพ์ในระบบใบเสร็จขาย/รับซื้อ/ซ่อม, สลิปเงินเดือน, ใบเครม, ใบสรุปการมาทำงาน, ใบเบิก/รับเข้าอะไหล่
13. Portal (Tenant Self-Service)Support Tickets, ประกาศ, Billing, อัปเกรดแพ็กเกจ
14. การจัดการระบบ (Admin)สาขา, ผู้ใช้งาน, ข้อมูลหลัก, ตั้งค่า, Audit Log
15. การแจ้งเตือนNotification Center แบบ Real-time + Push Notifications แม้ปิดเว็บ + ติดตั้งเป็นแอป (PWA)
16. Multi-Tenant และ Multi-BranchTenant Isolation, Branch Selector
17. ภาคผนวกAPI Endpoints, Tech Stack, Deployment, Backup & Restore, Security

1. บทนำ

1.1 ภาพรวมระบบ

MobileHub v2 เป็นระบบจัดการร้านมือถือแบบ Multi-Tenant SaaS ที่ออกแบบมาสำหรับร้านมือถือทุกขนาด ตั้งแต่ร้านสาขาเดียวจนถึงเชนร้านค้าหลายสาขา ระบบครอบคลุมการทำงานตั้งแต่การรับซื้อมือถือมือสอง การซ่อมบำรุง การขายสินค้าแบบ POS ไปจนถึงการจัดการบุคลากรและรายงานทางการเงิน

ระบบพัฒนาด้วย Next.js 16 + React 19 + Mantine v8 ทางฝั่งหน้า และ Fastify + Prisma + PostgreSQL ทางฝั่งหลัง รองรับการใช้งานแบบ Real-time ผ่าน Socket.IO และออกแบบตามมาตรฐาน Mobile-First เพื่อให้ใช้งานสะดวกบนมือถือ

โดเมน: mobilehub.ajsoftwaredev.com

1.2 ความสามารถหลัก

🔧 ความสามารถ📝 รายละเอียด
📦 คลังสินค้าจัดการสต็อกมือถือและอุปกรณ์เสริม พร้อมอัปโหลดรูปภาพ
🛒 รับซื้อ-ตีราคาบันทึกการรับซื้อมือถือมือสอง พร้อม Checklist อุปกรณ์
🔧 งานซ่อมระบบรับเครื่องซ่อม ติดตามสถานะ แจ้งลูกค้าแบบ Real-time
💰 POS ขายสินค้าระบบขายสินค้าพร้อม PromptPay QR, Credit Card, โอน
🛡️ ประกันสินค้าบันทึกและติดตามประกันสินค้าและงานซ่อม
👥 ลูกค้าจัดการฐานข้อมูลลูกค้า ประวัติการซื้อ-ซ่อม
⏰ ลงเวลาทำงานQR Code Kiosk สำหรับพนักงานลงเวลาเข้า-ออก
💵 เงินเดือนคำนวณ อนุมัติ และบันทึกการจ่ายเงินเดือน
📊 รายงานรายงานยอดขาย, ซ่อม, การเงิน, VAT ออก Excel ได้
🔔 การแจ้งเตือน Real-timeBell notification ทุก role พร้อม Socket.IO
🏢 Multi-Branchรองรับหลายสาขา กรองข้อมูลตามสาขา
🔒 Multi-Tenantแต่ละ Tenant มีข้อมูลแยกกัน (Tenant Isolation)
🎫 Support Ticketsยื่น Ticket สนับสนุนกับทีมงาน
📢 ประกาศรับข่าวสารประกาศจากทีมงาน
💳 Billingจัดการ Subscription และชำระค่าบริการ
📝 Audit Logบันทึกทุกการกระทำในระบบ (ใครทำอะไร เมื่อไหร่)
🖥️ Customer Displayหน้าจอแสดงราคาสำหรับลูกค้า (POS)
🏷️ ข้อมูลหลักจัดการ Master Data — ยี่ห้อ, รุ่น, สี, ความจุ ฯลฯ

1.3 บทบาทในระบบ (7 Roles)

บทบาทชื่อในระบบคำอธิบาย
👑 เจ้าของOWNERสิทธิ์สูงสุด เข้าถึงได้ทุกส่วน รวมถึง Billing
🛠️ ผู้ดูแลระบบADMINจัดการระบบ ผู้ใช้ สาขา ตั้งค่า
📋 ผู้จัดการMANAGERดูรายงาน จัดการสต็อก ดูแลพนักงาน
💰 แคชเชียร์CASHIERรับชำระเงิน ขายสินค้า
🏪 พนักงานขายSALESขายสินค้า ดูสต็อก
🔧 ช่างซ่อมTECHNICIANจัดการงานซ่อม คลังอะไหล่
🔧💰 ช่างขายSALESTECHมีสิทธิ์ทั้ง SALES และ TECHNICIAN

1.4 ตารางสิทธิ์การเข้าถึง

โมดูลOWNERADMINMANAGERCASHIERSALESTECHSALESTECH
แดชบอร์ด
สต็อกมือถือ
อุปกรณ์เสริม
รับซื้อ-ตีราคา
รับเครื่อง (ซ่อม)
งานช่าง
รายการซ่อมทั้งหมด
คลังอะไหล่
Repair Checklist
ออกเอกสารซ่อม
ประกันงานซ่อม
ขายสินค้า (POS)
ประกันสินค้า
ลูกค้า
ลงเวลา
เงินเดือน
รายงาน
Portal Tickets
Portal ประกาศ
Portal Billing
สาขา
ผู้ใช้งาน
ข้อมูลหลัก
ตั้งค่า
Audit Log

1.5 แพ็คเกจ (Plans) และฟีเจอร์

ระบบมี 3 แพ็คเกจ ต่างกันที่ ขีดจำกัด (limits) + ฟีเจอร์ขั้นสูง (advanced features)

แพ็คเกจราคา/เดือนราคา/ปีสาขาผู้ใช้สินค้า
เริ่มต้น (Starter)฿599฿5,99013500
มืออาชีพ (Professional)฿1,499฿14,9903102,000
องค์กร (Enterprise)฿2,499฿24,990ไม่จำกัดไม่จำกัดไม่จำกัด

ฟีเจอร์ตามแพ็คเกจ

ฟีเจอร์StarterProEnterprise
ระบบขายหน้าร้าน (POS)
คลังสินค้า
จัดการลูกค้า
ระบบรับซ่อม
ลงเวลา (พื้นฐาน)
รายงานพื้นฐาน
Export รายงาน Excel/PDF
จอแสดงผลลูกค้า (Customer Display)
โหมด Kiosk ลงเวลา QR
Dashboard หลายสาขา ("ทุกสาขา")
API access
ระบบเงินเดือน (Payroll)
ลบโลโก้ MobileHub (White-label)
ซัพพอร์ต 24/7 (Priority)

💡 เมนูที่ไม่มีในแพ็คเกจของคุณจะถูกซ่อนอัตโนมัติ — ถ้าต้องการใช้งานต้องอัพเกรดแพ็คเกจที่หน้า Portal Billing

พฤติกรรมเมื่อเกินขีดจำกัด

ถ้าสร้างสาขา / ผู้ใช้ / สินค้าเกินจำนวนที่แพ็คเกจกำหนด ระบบจะตอบกลับ:

ถึงขีดจำกัดจำนวนสาขา (แพ็คเกจ มืออาชีพ) 3/3 — กรุณาอัพเกรดแพ็คเกจเพื่อเพิ่ม

→ ต้องลบรายการเก่าออก หรือ อัพเกรดแพ็คเกจ

2. เริ่มต้นใช้งาน

2.1 สมัครใช้งาน

📍 หน้า: /register 👤 สิทธิ์: สาธารณะ (ไม่ต้องเข้าสู่ระบบ)

วัตถุประสงค์: สร้าง Tenant ใหม่ (ร้านค้า) ในระบบ MobileHub

ขั้นตอน:

  1. เปิดเบราว์เซอร์ไปที่ https://mobilehub.ajsoftwaredev.com/register
  2. กรอกข้อมูลร้านค้า:
    • ชื่อร้าน — ชื่อธุรกิจของคุณ
    • อีเมล — ใช้สำหรับเข้าสู่ระบบและรับ OTP
    • รหัสผ่าน — ขั้นต่ำ 8 ตัวอักษร
    • ยืนยันรหัสผ่าน — กรอกซ้ำให้ตรงกัน
  3. กดปุ่ม "สมัครใช้งาน"
  4. ระบบส่ง OTP 6 หลักไปยังอีเมลที่กรอก
  5. ไปยังหน้า ยืนยันอีเมล เพื่อกรอก OTP

⚠️ หมายเหตุ: บัญชีที่สมัครใหม่จะได้รับสิทธิ์ OWNER โดยอัตโนมัติ และเป็น Tenant ใหม่แยกจากกัน

2.2 ยืนยันอีเมล OTP

📍 หน้า: /verify-email 👤 สิทธิ์: ผู้ที่เพิ่งสมัครใหม่

วัตถุประสงค์: ยืนยันความเป็นเจ้าของอีเมลก่อนเข้าใช้งานระบบ

ขั้นตอน:

  1. ตรวจสอบอีเมล (กล่อง Inbox หรือ Spam)
  2. พบอีเมลจาก MobileHub หัวข้อ "ยืนยันอีเมลของคุณ"
  3. คัดลอก OTP 6 หลักจากอีเมล
  4. กรอก OTP ในช่อง PinInput บนหน้า Verify Email
  5. ระบบยืนยันอัตโนมัติเมื่อกรอกครบ 6 หลัก
  6. เปลี่ยนหน้าไปยัง Dashboard โดยอัตโนมัติ
ตัวเลือกรายละเอียด
OTP หมดอายุOTP มีอายุ 10 นาที
ขอ OTP ใหม่กดปุ่ม "ส่งใหม่" ได้หลังจาก 60 วินาที
OTP ผิดระบบแจ้งเตือนและให้กรอกใหม่

💡 เคล็ดลับ: หาก OTP หมดอายุ กดปุ่ม "ส่งรหัสใหม่" เพื่อรับ OTP ชุดใหม่ได้ทันที

2.3 เข้าสู่ระบบ

📍 หน้า: /login 👤 สิทธิ์: สาธารณะ

วัตถุประสงค์: เข้าสู่ระบบด้วยอีเมลและรหัสผ่าน

ขั้นตอน:

  1. ไปที่ https://mobilehub.ajsoftwaredev.com/login
  2. กรอก อีเมล ที่ใช้สมัคร
  3. กรอก รหัสผ่าน
  4. กดปุ่ม "เข้าสู่ระบบ"
  5. ระบบตรวจสอบ JWT Token (อายุ 24 ชั่วโมง)
  6. เปลี่ยนหน้าไปยัง Dashboard

⚠️ หมายเหตุ: Login ใช้เพียง 2 ฟิลด์ (อีเมล + รหัสผ่าน) ไม่ต้องกรอก Tenant Slug

💡 เคล็ดลับ: Token มีอายุ 24 ชั่วโมง หากหมดอายุจะถูก Redirect ไปหน้า Login โดยอัตโนมัติ

2.4 แดชบอร์ด

📍 หน้า: /dashboard 👤 สิทธิ์: ทุก Role

วัตถุประสงค์: ภาพรวมสถิติและข้อมูลสำคัญของร้าน แสดงข้อมูลตาม Role ของผู้ใช้

การแสดงผลตาม Role:

Roleข้อมูลที่เห็น
OWNER / ADMINสถิติทั้งหมด + กราฟรายได้ + Top Products + งานซ่อมรอ + สินค้าใกล้หมด
MANAGERสถิติยอดขาย + รายงานสรุป + Top Products
TECHNICIANงานซ่อมของตัวเอง + สถิติการซ่อม
SALES / CASHIERยอดขายวันนี้ + สินค้าในสต็อก

การ์ดสถิติหลัก (Admin/Owner):

  • 💰 ยอดขายวันนี้ — รายได้จากการขายสินค้า
  • 🔧 งานซ่อมรอ — จำนวนงานซ่อมที่ยังไม่เสร็จ
  • 📦 สินค้าในสต็อก — จำนวนมือถือทั้งหมด
  • 👥 ลูกค้าใหม่ — ลูกค้าที่เพิ่มวันนี้
  • 📈 กราฟรายได้ — แสดงรายได้ย้อนหลัง
  • 🏆 สินค้าขายดี — Top Products ประจำเดือน
  • ⚠️ สินค้าใกล้หมด — สินค้าที่ Stock ต่ำ
  • 🕐 ประกันใกล้หมดอายุ — แสดง Expiring Warranties

💡 เคล็ดลับ: แดชบอร์ดกรองข้อมูลตาม สาขาที่เลือก ในส่วนบน เปลี่ยนสาขาได้จาก Branch Selector ด้านบน

2.5 แนะนำระบบ (Onboarding Tour)

📍 เปิดได้ที่: เด้งเองครั้งแรกหลังเข้าสู่ระบบ + ปุ่ม "แนะนำระบบ" ในเมนูซ้าย (มี Badge "ใหม่" สีฟ้า) 👤 สิทธิ์: ทุก Role (เนื้อหาแตกต่างกันตาม Role)

วัตถุประสงค์: ช่วยผู้ใช้ใหม่เริ่มต้นใช้งานเร็ว — ระบบจะแสดง Welcome Modal พร้อม Checklist สิ่งที่ควรทำก่อน + Guided Tour พาไล่ดูเมนูสำคัญทีละข้อ

Welcome Modal — เด้งครั้งเดียวต่อ User:

ครั้งแรกที่ Login จะเห็น Modal สีเทา-ฟ้า กลางจอ ประกอบด้วย:

  1. หัวข้อต้อนรับ + คำอธิบายตาม Role (เช่น OWNER เห็น "ตั้งค่าระบบและจัดการร้านของคุณ" / TECHNICIAN เห็น "รับงานซ่อม เบิกอะไหล่ และอัปเดตสถานะ")
  2. Checklist 2-4 รายการ — สิ่งที่ควรตั้งค่า/เปิดใช้ก่อน (เช่น ตั้งค่าร้าน → เพิ่มสาขา → เพิ่มผู้ใช้ → ข้อมูลหลัก สำหรับ OWNER)
    • คลิกแต่ละรายการ → ระบบจะ navigate ไปหน้านั้นทันที + mark ว่า "เสร็จแล้ว" (Badge เขียว)
  3. 2 ปุ่ม:
    • "ข้ามไปก่อน" — ปิด Modal ชั่วคราว (ไม่เด้งซ้ำ)
    • "เริ่ม Tour แนะนำ" — เริ่ม Guided Tour พาไล่ดูเมนูทีละข้อ

Guided Tour — Spotlight แต่ละเมนู:

เมื่อเริ่ม Tour ระบบจะ:

  • ทำให้พื้นหลังดำลง (overlay)
  • Highlight เมนูทีละข้อ ตามลำดับ พร้อม Popover คำอธิบายภาษาไทย
  • มีปุ่ม ก่อนหน้า / ถัดไป / เสร็จสิ้น + แสดงความคืบหน้า "ขั้นตอน N จาก M"
  • ถ้า Role ของผู้ใช้ไม่มีเมนูนั้น (เช่น TECHNICIAN ไม่เห็น POS) ระบบจะ ข้าม step นั้นอัตโนมัติ

Tour ตาม Role (สรุป):

Roleจำนวน Stepsเมนูที่ Tour พาไล่
OWNER / ADMIN7-8 ข้อDashboard → POS → รับเครื่อง → รายงาน → สาขา → ผู้ใช้ → ตั้งค่า → 🔔
MANAGER6-7 ข้อDashboard → POS → รายการซ่อม → ลงเวลา → รายงาน → ข้อมูลหลัก → 🔔
CASHIER4-5 ข้อDashboard → POS → สต็อก → ลูกค้า → 🔔
SALES5-6 ข้อDashboard → POS → สต็อก → รับซื้อ → ลูกค้า → 🔔
TECHNICIAN2-3 ข้องานช่าง → คลังอะไหล่ → 🔔

เปิดดูซ้ำได้ตลอด:

ถ้าปิดไปแล้วต้องการดูใหม่ — คลิก "แนะนำระบบ" ในเมนูซ้าย (อยู่ด้านล่างใกล้กับ "คู่มือการใช้งาน") → Welcome Modal เปิดอีก

💡 เคล็ดลับ: ระบบบันทึกว่าคุณดูแล้วลง localStorage ของเบราว์เซอร์ — ถ้าเปลี่ยนเครื่อง / เคลียร์ cache จะเด้งใหม่อีกครั้ง

2.6 โปรไฟล์ส่วนตัว

📍 หน้า: /profile 👤 สิทธิ์: ทุก Role

วัตถุประสงค์: ดูและแก้ไขข้อมูลส่วนตัว เปลี่ยนรหัสผ่าน อัปโหลดรูปโปรไฟล์

ฟิลด์ที่แก้ไขได้:

ฟิลด์คำอธิบาย
ชื่อ-นามสกุลชื่อที่แสดงในระบบ
เบอร์โทรเบอร์ติดต่อ
รูปโปรไฟล์อัปโหลดรูปภาพ (สูงสุด 5MB)
รหัสผ่านเก่าต้องกรอกเพื่อเปลี่ยนรหัสผ่าน
รหัสผ่านใหม่ขั้นต่ำ 8 ตัวอักษร

3. คลังสินค้า

3.1 สต็อกมือถือ

📍 หน้า: /stock 👤 สิทธิ์: OWNER, ADMIN, MANAGER, CASHIER, SALES, SALESTECH

วัตถุประสงค์: จัดการสินค้ามือถือในคลัง — เพิ่ม แก้ไข ดูสต็อก

คุณสมบัติหน้านี้:

  • ดูรายการสต็อกทั้งหมด พร้อมกรองตามสาขา
  • ค้นหาสินค้าด้วยชื่อ รุ่น บาร์โค้ด
  • เพิ่ม/แก้ไข/ลบสินค้า
  • อัปโหลดรูปภาพสินค้าหลายรูป (Carousel)
  • แสดง Badge สาขาเพื่อระบุที่อยู่ของสินค้า
  • ดู Cross-branch availability (สต็อกจากสาขาอื่น)

ขั้นตอนเพิ่มสินค้าใหม่:

  1. กดปุ่ม "+ เพิ่มสินค้า" มุมบนขวา
  2. กรอกข้อมูลสินค้า:
ฟิลด์คำอธิบายจำเป็น
ยี่ห้อเลือกจาก Master Brands (Apple, Samsung ฯลฯ)
รุ่นเลือกจาก Master Models
ความจุ64GB, 128GB, 256GB ฯลฯ
สีเลือกจาก Master Colors
IMEI/Serialหมายเลขเครื่อง
สภาพNEW (ใหม่) / LIKE_NEW (เหมือนใหม่) / GRADE_A (สภาพดีมาก) / GRADE_B (สภาพดี) / GRADE_C (มีตำหนิ) / GRADE_D (ตำหนิเยอะ — ราคาถูก)
ราคาทุนราคาที่รับซื้อมา
ราคาขายราคาที่ตั้งขาย
สถานะIN_STOCK, RESERVED, SOLD
สาขาเลือกสาขาที่เก็บสินค้า
หมายเหตุรายละเอียดเพิ่มเติม
รูปภาพอัปโหลดสูงสุดหลายรูป (5MB/ไฟล์)
  1. กดปุ่ม "บันทึก"

การสแกน Barcode:

  • กดไอคอน Barcode เพื่อเปิด Camera Scanner
  • สแกน IMEI/Serial Number โดยอัตโนมัติ
  • รองรับทั้ง QR Code และ Barcode

มุมมองมือถือ:

  • แสดงเป็น Card แทนตาราง
  • Card แสดงรูปภาพ, ยี่ห้อ/รุ่น, ราคา, สถานะ, สาขา
  • ปุ่มแก้ไข/ลบแสดงเป็นไอคอน

⚠️ หมายเหตุ: IMEI/Serial Number ต้องไม่ซ้ำกันในระบบ (Unique ต่อ Tenant)

3.2 อุปกรณ์เสริม

📍 หน้า: /accessories 👤 สิทธิ์: OWNER, ADMIN, MANAGER, CASHIER, SALES, SALESTECH

วัตถุประสงค์: จัดการสินค้าประเภทอุปกรณ์เสริม เช่น เคส สายชาร์จ หูฟัง กระจก

คุณสมบัติ:

  • จัดการสินค้าอุปกรณ์เสริมพร้อม Stock จำนวน
  • แบ่งหมวดหมู่ตาม Category
  • กำหนดยี่ห้อจาก Master Brands
  • ตั้งราคาทุน/ราคาขาย

ฟิลด์สินค้าอุปกรณ์เสริม:

ฟิลด์คำอธิบายจำเป็น
ชื่อสินค้าชื่อสินค้า
ยี่ห้อเลือกจาก Master Brands
หมวดหมู่เคส, สายชาร์จ, หูฟัง ฯลฯ
จำนวน (Stock)จำนวนชิ้นในคลัง
ราคาทุนต้นทุนสินค้า
ราคาขายราคาที่ตั้งขาย
สาขาสาขาที่เก็บสินค้า
สีสีของอุปกรณ์
บาร์โค้ดรหัสสินค้า
หมายเหตุรายละเอียดเพิ่มเติม

ประเภทธุรกรรมอุปกรณ์เสริม:

  • IN — รับสินค้าเข้าคลัง
  • OUT — ตัดสต็อกออก
  • SELL — ขายสินค้า (ผ่าน POS)

💡 เคล็ดลับ: Category เริ่มต้นของระบบ ได้แก่ เคส, ฟิล์ม/กระจก, สายชาร์จ, หูฟัง, Power Bank, อื่นๆ

3.3 รอบนับสต็อก (Stock Count) ⭐ NEW

📍 หน้า: /stock-count (list) + /stock-count/[id] (counting) 👤 สิทธิ์: OWNER, ADMIN, MANAGER

วัตถุประสงค์: ตรวจสต็อกจริง vs ระบบ — ตรวจของหาย, ตรวจ data integrity, audit trail สำหรับผู้สอบบัญชี (มาตรฐาน auditor ขอ stock count log เป็นปกติ)

3 ประเภทการนับ:

ประเภทใช้เมื่อไหร่
FULLนับสิ้นปี — ทุกรายการในร้าน
CYCLEนับเฉพาะหมวด/ยี่ห้อ/location — ทำได้ทุกเดือน
SPOT_CHECKตรวจสุ่ม

Workflow:

  1. เริ่มรอบ ที่ /stock-count → กด + เริ่มรอบนับใหม่ → เลือกประเภท
  2. ระบบ snapshot สต็อกในระบบ ณ ตอนนั้น → list ทุกรายการ (Product + Accessory + SparePart) ของสาขาให้นับ
  3. ไป /stock-count/[id] (mobile-first interface):
    • search box (พิมพ์ / สแกน barcode)
    • แต่ละ row แสดง: ชื่อ + expected qty + ช่องกรอกนับจริง + สีตามสถานะ (เทา/เขียว/ส้ม/แดง)
    • กรอกนับ → auto-save (debounce 400ms) → คำนวณ variance ทันที
    • ถ้า variance ≠ 0 → ช่อง "เหตุผล" โผล่ขึ้นใน inline (กรอกเหตุผล เช่น "ของหาย / ปลอม / นับผิดเดิม")
  4. Progress bar แสดง x/total นับแล้ว
  5. กด ปิดรอบนับ เมื่อนับครบ:
    • Alert ฟ้องถ้ามี variance ที่ยังไม่กรอกเหตุผล
    • ระบบบันทึก totals snapshot: expected/counted/missing/extra
    • ปิดเป็น COMPLETED ไม่สามารถแก้ได้อีก (audit trail)

ข้อดี:

  • หา cashier ที่ขาย off-the-book (เครื่องไม่ได้บันทึก SOLD แต่หาย)
  • หา shrinkage rate (% ของสินค้าที่หาย)
  • ใช้คุยกับ supplier ตอนรับของไม่ครบ (เปรียบใบส่งของกับสต็อกจริง)

⚠️ ห้ามมี 2 รอบนับเปิดพร้อมกันที่สาขาเดียวกัน — ระบบจะ block + redirect ไป รอบเก่า

3.4 โอนสินค้าระหว่างสาขา (Stock Transfer) ⭐ NEW

📍 หน้า: /stock-transfer 👤 สิทธิ์: ขอโอน = ทุก role; อนุมัติ/ยกเลิก = MANAGER+

วัตถุประสงค์: Multi-branch ใช้ได้แล้ว แต่ก่อนหน้านี้ โอนของระหว่างสาขาไม่ได้ — ของอยู่สาขา A ลูกค้าอยากซื้อที่สาขา B → ต้องลบ-สร้างใหม่ (ไม่มี audit trail). ระบบ Stock Transfer แก้ปัญหานี้

Workflow 3 stages:

สถานะคำอธิบายAction
PENDINGขอโอน รอ manager ของสาขาต้นทางอนุมัติmanager กด อนุมัติ + ส่ง → IN_TRANSIT
IN_TRANSITส่งของแล้ว — สาขาต้นทางตัดสต็อก/RESERVED ไว้manager ปลายทางกด รับเข้า เมื่อของมา → RECEIVED
RECEIVEDของมาถึงปลายทาง — สาขาปลายทางได้สต็อกเพิ่ม(จบ — เลขที่ใบโอน TR-XXX-XXXX-XXXX จบ lifecycle)
CANCELLEDยกเลิก (PENDING → cancel ได้ทันที / IN_TRANSIT → restore stock ที่ต้นทาง)(จบ)

สร้างคำขอโอน:

  1. ไป /stock-transfer → กด ขอโอนสินค้า (ต้องมี ≥ 2 สาขา)
  2. เลือกสาขาปลายทาง
  3. เพิ่มรายการจาก stock ที่สาขาปัจจุบัน — มี 3 tabs (อุปกรณ์ / อะไหล่ / มือถือ)
  4. กรอก qty (มือถือ = 1 เครื่อง = 1 row, อุปกรณ์/อะไหล่ปรับได้ตาม max stock)
  5. หมายเหตุ + บันทึก → status = PENDING
  6. ส่ง notification ไปที่ manager ของสาขาต้นทาง

Auto stock movement:

  • Approve (PENDING → IN_TRANSIT): มือถือ status=RESERVED, อุปกรณ์/อะไหล่ qty -= n
  • Receive (IN_TRANSIT → RECEIVED):
    • มือถือ: เปลี่ยน branchId + status=AVAILABLE
    • อุปกรณ์/อะไหล่: upsert ที่สาขาปลายทาง (match by name+sku)

transferNumber format: TR-{branchCode}-{BEyear}-{seq:04} — running serial ตาม docSerial system

Tabs: ทั้งหมด / ขาเข้า (รับ) / ขาออก (ส่ง) — filter ดูตามทิศทาง

4. รับซื้อ-ตีราคา

📍 หน้า: /purchase 👤 สิทธิ์: OWNER, ADMIN, MANAGER, CASHIER, SALES, SALESTECH

วัตถุประสงค์: บันทึกการรับซื้อมือถือมือสองจากลูกค้า พร้อมตีราคา และออกใบรับซื้อ

ขั้นตอนรับซื้อมือถือ:

  1. กดปุ่ม "+ รับซื้อสินค้า"
  2. เลือกลูกค้า (หรือเพิ่มลูกค้าใหม่ในฟอร์มเดียวกัน)
  3. กรอกข้อมูลอุปกรณ์:
ฟิลด์คำอธิบายจำเป็น
ลูกค้าเลือกจากฐานข้อมูล หรือเพิ่มใหม่
ประเภทอุปกรณ์มือถือ, แท็บเล็ต ฯลฯ
ยี่ห้อยี่ห้อสินค้า
รุ่นรุ่นสินค้า
ความจุหน่วยความจำ
สีสีสินค้า
IMEI/Serialหมายเลขเครื่อง (สแกน Barcode ได้)
สภาพสภาพเครื่อง
ราคารับซื้อราคาที่จ่ายให้ลูกค้า
ราคาตั้งขายราคาที่จะขายต่อ
Checklist อุปกรณ์ตรวจสอบอุปกรณ์แนบมา
รูปภาพถ่ายรูปสภาพเครื่อง
หมายเหตุเงื่อนไขพิเศษ
  1. กรอก Checklist อุปกรณ์ เพื่อบันทึกว่ามาพร้อมอะไรบ้าง:
    • กล่อง, ที่ชาร์จ, หูฟัง, สายชาร์จ, คู่มือ ฯลฯ
  2. กดปุ่ม "บันทึกรับซื้อ"
  3. ระบบเพิ่มสินค้าเข้า Stock อัตโนมัติ

คุณสมบัติเพิ่มเติม:

  • สแกน IMEI ด้วยกล้อง Barcode Scanner
  • อัปโหลดรูปสภาพเครื่องหลายรูป
  • ดูประวัติการรับซื้อย้อนหลัง
  • กัน IMEI ซ้ำในร้าน — เครื่องที่เคยรับเข้าระบบแล้ว ระบบไม่ให้บันทึกซ้ำ (ภายในร้านตัวเองเท่านั้น)

⚠️ ข้อควรระวัง — ตรวจเครื่องด้วยตนเองก่อนรับ

ระบบ MobileHub ไม่ได้ ตรวจ iCloud lock / Find My iPhone / blacklist global โดยอัตโนมัติ — checklist "ปลด Apple ID แล้ว" / "Factory Reset แล้ว" ในฟอร์มเป็นการ ยืนยันจากผู้ขาย เท่านั้น (self-declaration)

กรุณาตรวจด้วยตนเองก่อนจ่ายเงินรับเครื่อง:

  1. Settings → Apple ID → กดออกจากระบบ (Sign Out) — ต้องสำเร็จไม่ติดรหัส
  2. Find My iPhone — ต้องปิด (status = Off)
  3. Settings → General → Transfer or Reset → Erase All Content and Settings — ลองเริ่ม flow แต่ไม่ต้องกดยืนยัน เพื่อยืนยันว่าไม่ติดล็อค
  4. ถ้ามีข้อสงสัย iCloud lock / สถานะ blacklist — ใช้บริการตรวจ IMEI ภายนอก (เช่น IMEI24, SickW) ก่อนตัดสินใจรับ

หลักฐานทางกฎหมาย: ใบรับซื้อมือถือมือสองมีคำรับรองผู้ขาย 5 ข้อ (ไม่ใช่ของโจร / ไม่ติด iCloud / ไม่ติดผ่อน / IMEI ไม่ blacklist / ยินยอมรับผิดทางอาญา ม.357 ถ้าเป็นเท็จ) + ลายเซ็น 3 ฝ่าย + สำเนาบัตรประชาชน — ใช้ป้องกันร้านจากข้อหา "รับของโจร" ได้

💡 เคล็ดลับ: หลังรับซื้อสำเร็จ สินค้าจะปรากฏในหน้า สต็อกมือถือ โดยอัตโนมัติ พร้อมข้อมูลครบถ้วน

5. งานซ่อม

5.1 รับเครื่อง (3-step guided flow) ⭐ ปรับปรุง 2026-05-14

📍 เส้นทาง: /repair-intake/repair-checklist/repair-documents (preview) 👤 สิทธิ์: OWNER, ADMIN, MANAGER, SALESTECH (ช่างธรรมดา ไม่เห็น เมนูรับเครื่อง)

วัตถุประสงค์: รับเครื่องจากลูกค้า บันทึกข้อมูล + เช็คสภาพก่อนซ่อม + ออกใบรับซ่อมพร้อมพิมพ์ ภายในชุดเดียวกัน (ไม่ต้องสลับหน้าหลายครั้ง)

ขั้นที่ 1 — รับเครื่อง (กรอกข้อมูล + เซ็น)

ที่ /repair-intake กด "+ รับเครื่อง" → modal เปิด

ฟิลด์ในฟอร์ม:

ฟิลด์คำอธิบายจำเป็น
ลูกค้าเลือกหรือเพิ่มใหม่ (ค้นหาด้วยชื่อ/เบอร์)
🚀 Quick-pick template(ไม่บังคับ) เลือก template งานยอดฮิต → auto-fill ยี่ห้อ/รุ่น/ค่าแรง/อาการ
ประเภทเครื่องมือถือ / แท็บเล็ต / สมาร์ทวอทช์ / หูฟัง / อื่นๆ
ยี่ห้อจาก Master Brands ของสาขา
รุ่นจาก Master Models (กรองตามยี่ห้อ)
IMEI / Serialตัวเลข 15 หลัก (มี 3-layer guard กันพิมพ์ตัวอักษร)❌ — สมาร์ทวอทช์/หูฟังไม่มี IMEI ก็เว้นได้
รูปถ่ายเครื่องสูงสุด 10 รูป (ลาก-วาง ขนาด ≤ 5MB/รูป)
อาการเสีย / ปัญหาที่พบลูกค้าแจ้ง (Textarea)
ราคาประเมิน (เบื้องต้น)ช่างปรับภายหลังตามอาการจริง
หมายเหตุเงื่อนไขพิเศษ
ลายเซ็นลูกค้าcanvas เซ็น (mouse/touch) — เก็บใน Repair.intakeSignature❌ — แนะนำให้เซ็น

Validation: ถ้าฟิลด์ที่บังคับขาด → toast แดง "ข้อมูลไม่ถูกต้อง" รวมทุกฟิลด์ที่ขาดเป็น bullet list + แต่ละ Select มี error message ใต้ label. แก้ไขฟิลด์ใดก็ตาม → error ของฟิลด์นั้นหายอัตโนมัติ

กด "บันทึก" → ระบบสร้างงานซ่อม → toast เขียว "รับเครื่องสำเร็จ — ต่อไปเช็คสภาพเครื่องก่อนซ่อม" → redirect อัตโนมัติไปขั้นที่ 2

ขั้นที่ 2 — เช็คสภาพเครื่อง (PRE_REPAIR checklist)

ระบบพาไป /repair-checklist?repairId=...&autoOpen=PRE_REPAIR — modal เปิดเองทันที (ไม่ต้องคลิก)

สิ่งที่ทำ:

  • 24 รายการ default (Bluetooth / WiFi / กล้อง / แบตเตอรี่ / ลำโพง / Face ID / สแกนลายนิ้วมือ ... ตาม master items ของสาขา)
  • แต่ละรายการเลือก: ✅ ปกติ / ❌ ไม่ปกติ / — ไม่เกี่ยวข้อง
  • ถ้าเลือก ไม่ปกติ ต้องกรอกหมายเหตุอธิบาย (ระบบบังคับ ห้าม save ทิ้งไว้)
  • หมายเหตุภาพรวม (ถ้ามี) — เช่น "เคสมีรอย", "หน้าจอมีรอยเล็กน้อย"
  • ลายเซ็นลูกค้า อีกครั้ง — ยืนยันสภาพที่เห็นด้วยกัน (เก็บใน RepairChecklist.customerSignature)

กด "บันทึก" → toast "บันทึกสำเร็จ — เช็คก่อนซ่อม + ออกใบรับซ่อมเรียบร้อย" → redirect ไปขั้นที่ 3

ขั้นที่ 3 — preview ใบรับซ่อม (พร้อมพิมพ์)

ระบบพาไป /repair-documents?repairId=...&autoPreview=intake — modal ตัวอย่างเอกสารเปิดเองพร้อมเนื้อหาครบ:

  • 🏪 logo + ชื่อร้าน + ที่อยู่ + เลขประจำตัวผู้เสียภาษี
  • 🏷️ Title bar "ใบรับซ่อม" (สี slate gray)
  • 👤 ข้อมูลลูกค้า + 📱 ข้อมูลเครื่อง 2-col
  • 📷 รูปถ่ายเครื่องตอนรับ (สูงสุด 6 รูป)
  • 📋 สภาพเครื่องตอนรับ (ลูกค้ายืนยัน) — 24-item checklist 3-col + badge สีเขียว/แดง
  • ⚠️ Note "ราคาซ่อมจะแจ้งในใบเสนอราคาภายหลัง" (กล่องเหลือง)
  • 📜 เงื่อนไขและข้อตกลง 4 ข้อ
  • ✍️ ลายเซ็นพนักงาน + ลายเซ็นลูกค้า (รูปลายเซ็นจาก checklist embed อัตโนมัติ)
  • 📦 QR tracking code (Kerry-style) — สำหรับให้ลูกค้าติดตามสถานะออนไลน์
  • 🙏 footer "ขอบคุณที่ใช้บริการ"

ทั้งหมด อยู่ใน 1 หน้า A4 (ใช้ .intake-receipt CSS scope compactions) → กดปุ่ม "พิมพ์" → printer dialog เปิด

ทำไมต้อง 3 ขั้น:

  • ขั้น 1 = บันทึก identity ของงาน (ใคร / อะไร / ปัญหา)
  • ขั้น 2 = หลักฐานยืนยัน "สภาพที่รับมา" — ป้องกันข้อพิพาทตอนคืนเครื่อง ("ตอนนั้นแบตปกติ ตอนนี้แบตเสีย!")
  • ขั้น 3 = เอกสารส่งให้ลูกค้า — มีลายเซ็น 2 จุด (intake + checklist) + checklist embed = ลูกค้าและร้านมีหลักฐานชุดเดียวกัน

💡 Tip — Skip checklist: ถ้างานเร่งและไม่ต้องการ checklist (เช่น เปลี่ยนสาย charger 5 นาที) ขั้น 2 ปิด modal ทิ้งได้ — ระบบยังคงสร้างงานซ่อมไว้ที่ /repair แล้ว แค่ไม่มี checklist + ไม่ออกใบให้อัตโนมัติ. สามารถออกใบรับซ่อมเองภายหลังที่ /repair-documents (ใบจะไม่มี checklist section)

⚠️ หมายเหตุ: ช่างที่มี Role TECHNICIAN เท่านั้น ไม่เห็น เมนูรับเครื่อง — เห็นเฉพาะงานที่ถูกมอบหมายในเมนู งานช่าง

5.2 งานช่าง

📍 หน้า: /technician-repairs 👤 สิทธิ์: OWNER, ADMIN, MANAGER, TECHNICIAN, SALESTECH

วัตถุประสงค์: ดูงานซ่อมที่ได้รับมอบหมาย อัปเดตสถานะ เบิกอะไหล่

สถานะงานซ่อม:

สถานะสีความหมาย
PENDING (รับเครื่อง)เทารับเครื่องแล้ว รอดำเนินการ
QUOTED (เสนอราคาแล้ว)ม่วงประเมินราคา รอลูกค้าอนุมัติ
APPROVED (อนุมัติแล้ว)ส้มลูกค้าอนุมัติแล้ว พร้อมซ่อม
IN_PROGRESS (กำลังซ่อม)ฟ้ากำลังซ่อมอยู่
WAITING_PARTS (รออะไหล่)เหลืองรออะไหล่ส่งมาก่อนซ่อมต่อ
COMPLETED (เสร็จแล้ว)เขียวซ่อมเสร็จ รอลูกค้ามารับ
DELIVERED (ส่งมอบแล้ว)ฟ้าทะเลส่งคืนลูกค้าแล้ว
CANCELLED (ยกเลิก)แดงยกเลิก

💡 ระบบแสดง badge สถานะเป็นภาษาไทยทั้งระบบ (/repair, /repair-intake, /technician-repairs, /repair-documents, /repair-warranty, /reports ฯลฯ) — ทำผ่านไฟล์กลาง lib/statusLabels.js

ขั้นตอนอัปเดตงานซ่อม:

  1. คลิกที่รายการงานซ่อม
  2. เปลี่ยนสถานะตามความเป็นจริง
  3. เพิ่มรายละเอียดการซ่อม (อะไหล่ที่ใช้ ค่าใช้จ่าย)
  4. กดปุ่ม "บันทึก"
  5. ระบบแจ้งเตือน Real-time ไปยังเจ้าของร้านและ Manager

การเบิกอะไหล่:

  1. คลิกปุ่ม "เบิกอะไหล่" ในรายการงาน
  2. เลือกอะไหล่จากคลังอะไหล่
  3. กรอกจำนวนที่ใช้
  4. ระบบตัด Stock อะไหล่อัตโนมัติ

💡 เคล็ดลับ: ช่างเห็นเฉพาะงานซ่อมที่มอบหมายให้ตัวเอง ส่วน Manager และ Admin เห็นงานทั้งหมด

5.3 รายการทั้งหมด

📍 หน้า: /repair 👤 สิทธิ์: OWNER, ADMIN, MANAGER, SALESTECH (ช่างธรรมดา ไม่เห็น)

วัตถุประสงค์: ดูรายการงานซ่อมทั้งหมด กรอง/ค้นหา สร้างงานซ่อมใหม่

ฟีเจอร์:

  • ดูรายการงานซ่อมทั้งหมดของสาขา
  • ค้นหาด้วยชื่อลูกค้า, ยี่ห้อ, รุ่น, หมายเลขงาน
  • กรองตามสถานะ
  • เพิ่มงานซ่อมใหม่ (เหมือน Repair Intake)
  • อัปเดตสถานะและรายละเอียด
  • ดูประวัติการซ่อมย้อนหลัง
  • แสดงรูปภาพก่อน-หลังซ่อม

5.4 คลังอะไหล่

📍 หน้า: /spare-parts 👤 สิทธิ์: OWNER, ADMIN, MANAGER, TECHNICIAN, SALESTECH

วัตถุประสงค์: จัดการคลังอะไหล่สำหรับงานซ่อม — เพิ่ม, รับเข้า, เบิกออก

ฟิลด์อะไหล่:

ฟิลด์คำอธิบายจำเป็น
ชื่ออะไหล่ชื่อ Part
หมวดหมู่ประเภทอะไหล่
ยี่ห้อยี่ห้อที่รองรับ
รุ่นรุ่นที่รองรับ
จำนวนคงเหลือStock ปัจจุบัน
ราคาทุน (Unit Price)ราคาต้นทุนต่อชิ้น
ราคาขายราคาที่คิดลูกค้า
ตำแหน่งจัดเก็บLocation ในคลัง
หมายเหตุรายละเอียดเพิ่มเติม

การจัดการสต็อกอะไหล่:

  • รับเข้า: กดปุ่ม "รับอะไหล่เข้า" เพื่อเพิ่ม Stock (manual)
  • สั่งจาก Supplier: ใช้หน้า /reorders (§5.4B) — track DRAFT → SENT → RECEIVED + auto bump stock
  • เบิกออก: ระบบตัดอัตโนมัติเมื่อใช้ในงานซ่อม
  • แจ้งเตือน Stock ต่ำ: ระบบแจ้งเตือนเมื่อ Stock ต่ำกว่าขั้นต่ำ

5.4A Template ราคาซ่อม (Repair Pricing Template) ⭐ NEW

📍 หน้า: /masters/repair-price-templates (CRUD) + quick-pick ใน /repair-intake 👤 สิทธิ์: OWNER, ADMIN

วัตถุประสงค์: ทุกร้านมีงานซ่อมยอดฮิต 20-30 รายการที่ทำซ้ำทุกวัน เช่น "iPhone 13 จอแตก = ฿2,500" — Template ทำให้ช่าง quick-pick แทนการพิมพ์ทุกครั้ง

สร้าง template:

  1. ไป /masters → กด Template ราคาซ่อม
  2. กดปุ่ม + เพิ่ม template
  3. กรอก: ชื่อ template (เช่น "iPhone 13 จอแตก") + ยี่ห้อ/รุ่น (เว้น = ทุกยี่ห้อ) + ประเภทซ่อม + ค่าแรง + ค่าอะไหล่ + อาการ default + ระยะประกัน
  4. กด บันทึก

ใช้งาน:

  • ไป /repair-intake รับเครื่อง
  • บนสุดของส่วน "ข้อมูลเครื่อง" → Select 🚀 Quick-pick template
  • เลือก template → ระบบ auto-fill: ยี่ห้อ + รุ่น + ค่าแรง + ค่าอะไหล่ + อาการ
  • ช่างยังแก้ field แต่ละช่องได้ก่อนบันทึก
  • ทุกครั้งที่ใช้ template → popularityScore += 1 (เรียงขึ้นบนใน list ครั้งถัดไป)
  • 🔥 Badge สำหรับ template ใช้ > 5 ครั้ง (popular)

ประโยชน์:

  • ลดเวลารับเครื่องจาก 2-3 นาที → 30 วินาที
  • ราคามาตรฐานทั้งร้าน (ลูกค้าไม่งง)
  • analytics: รู้งานยอดฮิตของร้านจาก popularityScore

5.4B ผู้จัดหา (Suppliers) + สั่งซื้ออะไหล่ (Reorders) ⭐ NEW

📍 หน้า: /suppliers (CRUD ผู้จัดหา) + /reorders (สั่งซื้อ + ติดตาม) 👤 สิทธิ์: OWNER, ADMIN (suppliers); + MANAGER (reorders)

วัตถุประสงค์: ก่อนหน้านี้สั่งอะไหล่ต้องจดเองใน LINE → จำเลขส่งของไม่ได้ → ส่งมาแล้วลืมเช็ค → stockout ตอนช่างต้องการ. ระบบ Reorder ช่วย:

  1. Auto-detect อะไหล่ที่เหลือต่ำกว่า min stock
  2. Track lifecycle: DRAFT → SENT → RECEIVED + auto bump stock
  3. เก็บประวัติทุก order ผูกกับ supplier

5.4B.1 Suppliers (/suppliers)

จัดการ supplier ที่สั่งอะไหล่ประจำ:

  • ชื่อร้าน/บริษัท + ผู้ติดต่อ + เบอร์/email/LINE/ที่อยู่
  • เลขประจำตัวผู้เสียภาษี
  • เงื่อนไขการชำระ: เงินสด / net-7 / net-15 / net-30 / net-60
  • หมายเหตุ + active toggle

ลบ supplier ไม่ได้ถ้ายังมีอะไหล่ผูกอยู่ — ต้องตั้ง active=false แทน

5.4B.2 ผูก Supplier กับอะไหล่

ใน /spare-parts form:

  • เพิ่ม field: supplierId (Select), reorderQuantity (จำนวนที่ควรสั่งทุกครั้ง), leadTimeDays (กี่วันถึง), unitCost (ราคาต่อหน่วยจาก supplier)

5.4B.3 Reorders (/reorders) — Workflow

Tab "ใกล้หมด" — auto-detect:

  • list อะไหล่ที่ quantity ≤ minStock
  • แสดง suggested quantity = max(reorderQuantity, minStock × 2 - currentQty)
  • กด + สร้างคำสั่ง → modal เปิดพร้อมรายการ pre-fill

Workflow 3 stages:

สถานะคำอธิบายAction
DRAFTสร้างแล้ว ยังไม่ส่งกด ส่งคำสั่ง → SENT
SENTส่ง LINE/email ให้ supplier แล้วกด รับเข้า เมื่อของมาถึง → RECEIVED
RECEIVEDของมาแล้ว — auto bump SparePart.quantity(จบ)
CANCELLEDยกเลิก (ก่อน RECEIVED)(จบ)

Create modal — มี search/picker แบบ:

  • เลือก supplier
  • list ที่ pre-fill จาก low-stock + สามารถเพิ่มอื่น ๆ จาก list ใต้
  • แต่ละ row: name + qty + unitCost + total (auto-calc)
  • หมายเหตุ
  • บันทึกเป็น DRAFT → ส่งทีหลัง

Performance: modal ใช้ uncontrolled refs (qty/unitCost) — ไม่ lag แม้มีหลายรายการ

5.5 Repair Checklist (เช็คสภาพก่อน/หลังซ่อม + ลายเซ็นลูกค้า)

📍 หน้า: /repair-checklist 👤 สิทธิ์: OWNER, ADMIN, MANAGER, SALESTECH (ช่างธรรมดา ไม่เห็น)

วัตถุประสงค์: เก็บหลักฐานสภาพเครื่องก่อน/หลังซ่อม พร้อมลายเซ็นลูกค้า — ป้องกัน customer dispute ("ของผมก่อนเอามาซ่อมไม่เป็น พอซ่อมเสร็จกลับเป็น") + เป็นใบ QC ก่อนส่งมอบ

🔄 Workflow ที่ถูกต้อง (ตามขั้นตอน — สำคัญมาก!)

ระบบบังคับลำดับการเช็คตามมาตรฐานร้านมือถือสากล — ห้ามข้ามขั้นตอน:

1. รับเครื่อง (status = รับเครื่อง / PENDING)
   ↓
2. ✅ เช็คก่อนซ่อม (PRE_REPAIR) ← ทำตอนนี้! ก่อนเริ่มซ่อม + ขอลายเซ็นลูกค้า
   ↓
3. ประเมินราคา (status = เสนอราคา)
   ↓
4. ลูกค้าอนุมัติ (status = อนุมัติ)
   ↓
5. ช่างซ่อม (status = กำลังซ่อม / รออะไหล่)
   ↓
6. ซ่อมเสร็จ (status = เสร็จแล้ว) ← ปุ่ม pre จะ lock ตอนนี้แล้ว!
   ↓
7. ✅ เช็คหลังซ่อม (POST_REPAIR) ← ทำตอนนี้ + ขอลายเซ็นลูกค้ารับเครื่อง
   ↓
8. ส่งเครื่อง (status = ส่งคืนแล้ว)
   ↓
9. ✅ ปุ่ม "เปรียบเทียบ" pre vs post จะโผล่ที่ตาราง

กฎเหล็ก 3 ข้อ:

  1. PRE check ทำได้เฉพาะก่อนงานเสร็จ — สถานะ รับเครื่อง / เสนอราคา / อนุมัติ / กำลังซ่อม / รออะไหล่ เท่านั้น. พอซ่อมเสร็จ (เสร็จแล้ว / ส่งคืนแล้ว) ปุ่ม pre จะกลายเป็นเทา (disabled) ตลอดกาล
  2. POST check ทำได้หลังงานเสร็จ — ต้องเปลี่ยนสถานะเป็น เสร็จแล้ว หรือ ส่งคืนแล้ว ก่อน ปุ่ม post ถึงจะกดได้
  3. เปรียบเทียบ ต้องครบทั้ง 2 ฝั่ง — ถ้าทำแค่ฝั่งเดียว (pre หรือ post อย่างเดียว) ปุ่มเปรียบเทียบจะไม่โผล่

เหตุผลของกฎ (ทำไมเข้มขนาดนี้):

  • กฎหมาย/หลักฐาน: ลายเซ็นลูกค้าใน PRE = สภาพเครื่อง "ตอนรับเข้า" → ถ้าให้แก้ย้อนหลังหลังซ่อมเสร็จ ลายเซ็นนี้จะไม่ valid (ลูกค้าไม่ได้อยู่ตอนนั้น)
  • กัน fraud: ช่างไม่สามารถ "เพิ่ม" รายการ NOT_OK ย้อนหลังเพื่อ avoid claim ได้
  • มาตรฐาน QC: PRE = baseline ก่อนแตะเครื่อง / POST = สภาพหลังแก้ — ต้องบันทึก pre ก่อนเริ่มซ่อม ถึงจะมี baseline เปรียบเทียบ

ผลถ้าลืมเช็ค PRE: ถ้าซ่อมเสร็จแล้วเพิ่งนึกได้ว่าลืมเช็ค PRE → ทำไม่ได้แล้ว ระบบ lock ตลอดกาล. แถวนี้จะไม่มีปุ่มเปรียบเทียบเลย เป็นบทเรียนให้ครั้งหน้าเช็คก่อน

💡 Guided flow จาก /repair-intake (ปรับปรุง 2026-05-14): เมื่อใช้ flow รับเครื่องที่หน้า /repair-intake ระบบจะ redirect มา /repair-checklist?autoOpen=PRE_REPAIR ทันที — modal PRE_REPAIR เปิดเองโดย user ไม่ต้องกดอะไร. เมื่อ save checklist เสร็จ ระบบจะ auto-issue ใบรับซ่อม + redirect ไป preview พิมพ์ — ไม่ต้องกลับมาที่ /repair-documents เอง. ดูรายละเอียดที่ §5.1

โครงสร้าง 2 แท็บ:

แท็บที่ 1: งานซ่อม

  • แสดงรายการงานซ่อมทั้งหมดในตาราง 9 คอลัมน์ (Desktop) / Card (Mobile):
    • เลขที่ + วันที่รับ — id + ตอนที่รับเครื่อง
    • ลูกค้า + เบอร์ — ชื่อ + เบอร์โทรกดเพื่อโทรได้ทันที
    • เครื่อง + IMEI — ยี่ห้อ/รุ่น + IMEI
    • อาการ — สิ่งที่ลูกค้าแจ้ง (มี Tooltip ดูเต็มถ้ายาว)
    • ช่าง — Avatar + ชื่อช่างที่รับผิดชอบ
    • สถานะ — Badge สีตามสถานะ
    • เช็คก่อนซ่อม — ปุ่ม + timestamp ที่เช็ค
    • เช็คหลังซ่อม — ปุ่ม + timestamp ที่เช็ค
    • เปรียบเทียบ — เปิด modal เทียบ pre vs post

กลไก lock-edit: เมื่อเช็คครบทั้ง pre + post แล้ว ปุ่มแก้ไขจะหายไป — เหลือแค่ "✓ เช็คแล้ว" + ปุ่ม "เปรียบเทียบ" — กันแก้หลักฐานย้อนหลัง

แท็บที่ 2: รายการเช็ค (Master List — admin only)

  • จัดการรายการที่ต้องเช็ค (เช่น: หน้าจอ, ลำโพง, กล้อง, USB, Wi-Fi, แบตเตอรี่)
  • หมวดหมู่: DISPLAY, AUDIO, CAMERA, CONNECTIVITY, BATTERY, ฯลฯ
  • Sort order ปรับลำดับการแสดง
  • Active/Inactive toggle

ขั้นตอนการเช็ค (ใน modal):

  1. คลิกปุ่ม "เช็คก่อนซ่อม" หรือ "เช็คหลังซ่อม" → modal เปิดมาพร้อมรายการที่ admin ตั้งไว้ทั้งหมด
  2. แต่ละรายการมี 3 สถานะให้เลือก:
    • ปกติ (เขียว) — ทำงานได้
    • ไม่ปกติ (แดง) — มีปัญหา → บังคับใส่หมายเหตุ อธิบายว่าผิดปกติยังไง (เช่น "จอแตกที่มุมซ้ายบน") — กดบันทึกไม่ได้ถ้าเลือก NOT_OK แล้วไม่ใส่ note
    • ไม่เกี่ยวข้อง (เทา) — ไม่ตรวจรายการนี้
  3. กรอก หมายเหตุรวม (ถ้ามี — เช่น "ลูกค้าแจ้งว่าจอกระพริบเป็นช่วงๆ")
  4. ลายเซ็นลูกค้า — ลูกค้าเซ็นในกรอบบน touchscreen (มือถือ/iPad) หรือใช้เมาส์ (PC):
    • ลูกค้าจะ "เซ็นลายเซ็นจริง" หรือ "เขียนชื่อ" ก็ได้ — เก็บเป็นรูป PNG อัตโนมัติ
    • มีปุ่ม "ล้างลายเซ็น" ถ้าเซ็นผิดต้องการเซ็นใหม่
    • บันทึกแล้วลายเซ็นจะปรากฏในเอกสาร (ใบรับซ่อม, ใบเสร็จซ่อม, ใบส่งคืนหลังเครม)
  5. กด บันทึก → ระบบเก็บผลพร้อม timestamp + ชื่อช่างที่เช็ค

Compare modal (เทียบก่อน/หลัง):

  • ตารางเทียบรายการต่อรายการ — ก่อนซ่อม | หลังซ่อม | เปลี่ยนแปลง
  • รายการที่สถานะเปลี่ยน → highlight bg เหลือง + Badge "เปลี่ยนแปลง"
  • รายการที่ NOT_OK → แสดงหมายเหตุที่ช่างจดไว้ใต้ Badge (กรอบแดงอ่อน italic)

ผลกับเอกสารที่พิมพ์:

เอกสารใช้ Checklist อะไร
ใบรับซ่อม (intake)PRE_REPAIR — แสดงสภาพเครื่องตอนรับ + ลายเซ็นลูกค้ายืนยัน
ใบเสร็จซ่อม / SMALL_RECEIPTPOST_REPAIR — แสดงผลตรวจ QC หลังซ่อม + ลายเซ็นลูกค้ารับเครื่อง
ใบส่งคืนหลังเครม (resolution)POST_REPAIR — แทนรายการ Final QC แบบ generic ด้วยรายการจริงที่ช่างเช็ค + ลายเซ็นลูกค้ารับเครื่อง

Mobile-friendly:

  • Modal เช็ครายการ: ปุ่ม 3 สถานะ stack vertically + full-width grow บนมือถือ (Desktop เป็น row)
  • ลายเซ็น canvas: รองรับนิ้วบน iPad/iPhone (touchAction: none กัน scroll ตอนเซ็น)
  • Card view บนมือถือ: ปุ่มอยู่ล่างเสมอ (consistent layout — ไม่กระโดดขึ้นบนเหมือน wrap)

5.6 ออกเอกสาร

📍 หน้า: /repair-documents 👤 สิทธิ์: OWNER, ADMIN, MANAGER, SALESTECH (ช่างธรรมดา ไม่เห็น)

วัตถุประสงค์: ออกเอกสารเกี่ยวกับงานซ่อม 5 ประเภท — รับเครื่อง / เสนอราคา / เสร็จรับเงิน / ใบเล็ก / ประกัน

ประเภทเอกสาร 5 แบบ:

เอกสารเลขที่ formataccentเนื้อหา
ใบรับซ่อม (INTAKE_RECEIPT)RCV-{branch}-{BEyear}-{seq:04}slate #475569ข้อมูลลูกค้า + เครื่อง + อาการ + checklist PRE_REPAIR + รูปถ่ายเครื่องตอนรับ + QR tracking. ฟิตหน้า A4 เดียว
ใบเสนอราคา (QUOTATION)QUO-{branch}-{BEyear}-{seq:04}blue #2563ebรายการอะไหล่ + ค่าแรง + ราคา (พร้อม/ไม่พร้อม VAT) — ขอลูกค้าอนุมัติก่อนเริ่มซ่อม
ใบเสร็จรับเงิน (RECEIPT)RCP-{branch}-{BEyear}-{seq:04}green #16a34aเอกสารทางการเงิน — A4 พร้อม VAT/ไม่ VAT
ใบเสร็จเล็ก (SMALL_RECEIPT)SLP-{branch}-{BEyear}-{seq:04}teal #0d9488ขนาด 80mm thermal สำหรับ POS slip printer + มี logo ร้าน
ใบประกัน (WARRANTY_CARD)WRT-{branch}-{BEyear}-{seq:04}orange #ea580cbanner 30 วัน + ความคุ้มครอง/ข้อยกเว้น + วิธีเคลม. ฟิตหน้า A4 เดียว

เปิดเอกสาร 2 วิธี:

  1. Auto จาก guided intake flow (default) — เมื่อ /repair-intake save + /repair-checklist save → ใบรับซ่อมออกเอง + preview เปิดทันที (ดู §5.1)
  2. Manual — ไปหน้า /repair-documents → กดแถว repair ที่ต้องการ → modal "ออกเอกสาร" เปิด → เลือกชนิดเอกสาร → กรอกข้อมูลเฉพาะ (VAT / ค่าแรง / ระยะประกัน) → กด "สร้างเอกสาร" → preview เปิดให้พิมพ์

Soft workflow ordering: ระบบมี order แนะนำ INTAKE → QUOTATION → RECEIPT → WARRANTY. ถ้าจะข้ามขั้น (เช่น ออก RECEIPT โดยยังไม่ได้ออก QUOTATION) → card จะเทาๆ + Badge "ข้ามลำดับ" + คลิกได้แต่ confirm modal ขึ้นก่อน. ใบรับซ่อมออกได้เสมอ (ไม่มี prereq)

สีพิมพ์: ทุก doc type ใช้ print-color-adjust: exact — สีพื้นหลัง title bar + table header + accent borders จะพิมพ์ออกสีครบแม้ผู้ใช้ไม่ติ๊ก "Background graphics" ใน print dialog ของ Chrome

ลายเซ็นลูกค้า (Priority chain — ใช้ตัวที่มีตามลำดับ):

  1. ลายเซ็นที่กรอกใน modal สร้างเอกสารตอนนั้น (ถ้ามี)
  2. ลายเซ็นจาก checklist (PRE สำหรับใบรับซ่อม / POST สำหรับใบเสร็จ)
  3. ลายเซ็น repair.intakeSignature (สำหรับใบรับซ่อม) / repair.deliverySignature (สำหรับใบเสร็จ)

💡 ลูกค้าเซ็นครั้งเดียวแล้วใช้ได้ทุกใบ — ระบบ resolve ลายเซ็นเองอัตโนมัติจาก priority chain ด้านบน. ในใช้งานจริง ลูกค้ามักเซ็น 2 ครั้ง: 1 ครั้งตอนรับเครื่อง (/repair-intake) + 1 ครั้งตอนเช็คสภาพ (/repair-checklist)

5.7 ติดตามสถานะออนไลน์สำหรับลูกค้า (Customer Tracking) — สาธารณะ

📍 หน้า (ลูกค้าใช้): /track และ /track/{slug}/{repairId} 👤 สิทธิ์: ลูกค้า — ไม่ต้องล็อกอิน (public, anyone with link)

วัตถุประสงค์: ให้ลูกค้าติดตามสถานะการซ่อมแบบเรียลไทม์เอง ไม่ต้องโทรถามร้าน — เหมือนติดตามพัสดุ Kerry/Flash

กลไก 3 ช่องทางที่ลูกค้ารู้ URL:

ช่องทางวิธีครอบคลุม
1. QR Code บนใบรับเครื่องสแกน QR ด้วยกล้องมือถือ95% case
2. กรอกเลขใน /trackกรอก เลขเดียว (8 ตัวอักษร เช่น F340-38A4) — เหมือนเช็คพัสดุไปรษณีย์ ไม่ต้องระบุชื่อร้านกรณีทำใบหาย
3. White Label custom domain (ENT)repair.ชื่อร้าน.comPhase 2

Single-field UX (เหมือน Kerry/Flash/ไปรษณีย์):

  • ใบรับซ่อมจะแสดง หมายเลขติดตาม ตัวใหญ่ (เช่น F340-38A4) ในกรอบ cyan/teal เด่นชัด
  • ลูกค้ากรอกเลขเดียวที่ /track → ระบบค้นข้าม tenant (UUID unique ทั้งระบบ) → redirect ไปหน้า detail อัตโนมัติ
  • ถ้าซ้ำ (rare) ระบบขอเลขเพิ่มจนกว่าจะ unique
  • รองรับทั้ง F34038A4, F340-38A4, f34038a4 (case + dash insensitive)

ข้อมูลที่ลูกค้าเห็น (ก่อนยืนยัน):

  • Timeline 6 ขั้นตอน (รับเครื่อง → เสนอราคา → อนุมัติ → ซ่อม → เสร็จ → ส่งมอบ) พร้อมเวลา + animation pulse ขั้นตอนปัจจุบัน
  • ยี่ห้อ/รุ่นเครื่อง + IMEI 4 ตัวท้าย (mask)
  • ชื่อช่างที่รับผิดชอบ
  • ชื่อลูกค้า masked (ส*****น) + เบอร์ masked (******1234)

ข้อมูลเพิ่ม (หลังยืนยันด้วย 4 ตัวท้ายเบอร์โทร):

  • ราคาประเมิน + รายการอะไหล่ + ค่าแรง
  • IMEI เต็ม + ชื่อ-เบอร์ลูกค้าเต็ม
  • อาการที่แจ้ง + การวินิจฉัย
  • ที่อยู่สาขา + เบอร์โทรร้าน (กดโทรได้)

การออกแบบใบรับซ่อม:

  • ใบรับซ่อม (INTAKE_RECEIPT) มี block QR + URL ที่ footer (cyan/teal gradient) แสดง:
    • QR encode https://โดเมน/track/{tenant.slug}/{repairId} (สแกนเปิดได้เลย)
    • 3 ขั้นตอน manual fallback (สแกน QR / เข้าเว็บ /track / กรอกชื่อร้าน + เลขใบ)
    • Note ว่าใส่ 4 ตัวท้ายเบอร์เพื่อดูราคา

ความปลอดภัย:

  • Rate limit: 30 req/นาที ต่อ IP — ป้องกัน scraping
  • Phone verify: 4 ตัวท้ายเบอร์เท่านั้น — ไม่ต้องเก็บ session/JWT
  • Generic error message — ไม่บอกว่าเลขใบมีหรือไม่ ป้องกัน enumeration
  • Backend exclude internal fields (cost basis, internal notes, signature)

💡 ข้อแนะนำ: ตอนรับเครื่อง ให้พนักงานบอกลูกค้าว่า "สแกน QR บนใบนี้เพื่อติดตามได้ตลอด 24 ชม." จะลดสายโทรเข้าได้มาก

5.8 ประกันงานซ่อม

📍 หน้า: /repair-warranty 👤 สิทธิ์: OWNER, ADMIN, MANAGER, SALESTECH (ช่างธรรมดา ไม่เห็น)

วัตถุประสงค์: บันทึกและติดตามประกันงานซ่อม รับเรื่องเคลมประกัน

ฟิลด์ประกันงานซ่อม:

ฟิลด์คำอธิบาย
งานซ่อมเชื่อมกับรายการซ่อมที่บันทึกไว้
วันเริ่มประกันวันที่เริ่มต้นประกัน
วันหมดประกันวันที่สิ้นสุดประกัน
เงื่อนไขประกันรายละเอียดความครอบคลุม
สถานะACTIVE, EXPIRED, CLAIMED

การเคลมประกัน:

  1. ลูกค้าแจ้งปัญหาภายในระยะประกัน
  2. พนักงานค้นหาใบประกันด้วยเลขงานซ่อม
  3. ตรวจสอบวันหมดอายุและเงื่อนไข
  4. บันทึกการเคลมพร้อมรายละเอียด
  5. สร้างงานซ่อมใหม่แบบ "เคลมประกัน"

💡 เคล็ดลับ: ระบบแจ้งเตือนอัตโนมัติเมื่อประกันงานซ่อมใกล้หมดอายุ

6. ขายสินค้า (POS)

📍 หน้า: /sales 👤 สิทธิ์: OWNER, ADMIN, MANAGER, CASHIER, SALES, SALESTECH

วัตถุประสงค์: ระบบขายสินค้าหน้าร้าน (Point of Sale) รองรับสินค้าทั้งมือถือและอุปกรณ์เสริม

6.1 การขายสินค้า

⚠️ ก่อนเริ่มขาย — เปิดกะการขาย (ถ้าจำเป็น)

ตามมาตรฐาน POS สากล (Microsoft Dynamics, Shopify, Lightspeed) — บทบาท CASHIER + SALES (default) ต้อง เปิดกะการขาย (กรอกเงินสดตั้งต้นในลิ้นชัก) ก่อนรับเงินจากลูกค้า. หน้า /sales จะแสดง banner สีส้ม + ปุ่ม "ไปเปิดกะการขาย" ถ้ายังไม่เปิด — กดเข้าไปที่ /shift กรอก openingFloat + กดเปิดกะ แล้วกลับมาขายได้.

OWNER / ADMIN / MANAGER / TECHNICIAN ขายได้ตรง ไม่ต้องเปิดกะ (default config). เจ้าของร้านปรับนโยบายได้ที่ /settings → "นโยบายกะการขาย" — เลือกบทบาทที่ต้องบังคับ หรือเคลียร์ทั้งหมดเพื่อปิดการบังคับ.

ดูรายละเอียดการเปิด-ปิดกะ + variance check ที่ §10B.

Layout — Split Screen (Shopify POS pattern):

หน้าจอแบ่งเป็น 2 คอลัมน์ — ตะกร้าอยู่ขวาเสมอ ไม่ต้อง scroll หาข้อมูล

┌─ ซ้าย (lg=8) ─────────────┐ ┌─ ขวา (lg=4) ──────┐
│ [ทั้งหมด][โทรศัพท์][อุปกรณ์] │ │ ตะกร้าสินค้า (3) [⛌][🗑]│
│ 🔍 ค้นหา...           [สแกน]│ │ ────────────────│
│ ┌──────────────────────┐ │ │ ► iPhone 13     │
│ │ 📱 iPhone 13 ┃ ฿17,900│ │ │ ► เคสกัน        │
│ │   IMEI ...   ┃ พร้อมขาย│ │ │ ────────────────│
│ │ 📱 iPhone 14 ┃ ฿24,900│ │ │ สรุปการชำระเงิน  │
│ │ 🎧 เคสกัน    ┃ ฿690   │ │ │ ลูกค้า: ...      │
│ │              ┃ 5 ชิ้น│ │ │ ยอดรวม ฿xxx     │
│ └──────────────────────┘ │ │ ส่วนลด: 0       │
│   (scroll ในกล่องผลค้นหา)  │ │ ─────────────── │
└──────────────────────────┘ │ ยอดชำระ ฿xxx    │
                              │ [เงินสด][PP][โอน]│
                              │ [ ยืนยันการขาย ] │
                              └─────────────────┘

ขั้นตอนการขาย:

  1. ค้นหาสินค้าด้วยชื่อ / IMEI / SKU หรือสแกน Barcode
  2. คลิกรายการในผลค้นหา → เพิ่มเข้าตะกร้า (เห็นทันทีในการ์ดขวา)
  3. ปรับจำนวน (อุปกรณ์เสริม) จากปุ่ม +/ ในตะกร้า
  4. เลือกลูกค้า หรือใช้ "ลูกค้าทั่วไป (Walk-in)" default
  5. ใส่ส่วนลดถ้ามี
  6. เลือกวิธีชำระ (เงินสด / PromptPay / โอน / บัตร)
  7. กรอกรับเงิน (ถ้าเงินสด) → ดูเงินทอน
  8. กด "ยืนยันการขาย" → ใบเสร็จเปิดอัตโนมัติให้พิมพ์

ค้นหาสินค้า — 3 ทาง:

  • พิมพ์ค้นหา — ชื่อสินค้า / IMEI / SKU / รหัส (debounce 300ms — debug ได้ทันทีไม่ต้องรอ Enter) + ปุ่ม × ล้างคำค้นหา
  • สแกน Barcode/QR — ปุ่ม "สแกน" ข้างช่องค้นหา → ใช้กล้องโทรศัพท์/แท็บเล็ต
  • Filter ประเภท — ทั้งหมด / โทรศัพท์ / อุปกรณ์เสริม (SegmentedControl ใต้ช่องค้นหา)

Visual Catalog Grid (โหลดสินค้าทั้งหมดไว้ตั้งแต่เริ่ม):

ระบบ pre-load สินค้าพร้อมขาย + อุปกรณ์เสริมทั้งหมดของสาขาไว้แล้ว แสดงเป็น การ์ดรูปภาพ ทันทีที่เปิดหน้า — cashier ไม่ต้องพิมพ์ก็เห็นทุกอย่าง — เลือกแตะได้เลย หรือพิมพ์เพื่อกรอง

Header แสดงจำนวน:

  • ก่อนค้นหา: สินค้าทั้งหมด N รายการ
  • ขณะค้นหา: ผลการค้นหา N รายการ

Card layout (compact 2-4 cols ตามขนาดจอ):

ส่วนสิ่งที่แสดง
รูปสินค้า (height 96px)รูปจริง (cover) / fallback IconDeviceMobile หรือ IconHeadphones บน gradient เทา
Badge ขวาบนจำนวนคงเหลือ (numeric เสมอ): 🟢 N ชิ้น (≥5) · 🟠 N ชิ้น (<5) · 🔴 หมดคำนวณจาก stock − ที่อยู่ใน cart เห็นยอดที่ใส่ตะกร้าได้จริง
Badge ซ้ายล่างประเภทสินค้า: cyan "มือถือ" · grape "อุปกรณ์"
ชื่อสินค้า2-line clamp, dark.8 fw 600
IMEI/SKU9px monospace gray-6
ราคาsm fw 700 cyan-7 + tabular-nums

Interaction:

  • Hover การ์ด → border cyan-4 + bg cyan-0 (ไม่มี scale = ไม่ขยับ layout)
  • Click → addToCart ทันที, การ์ด cart ขวาอัพเดทเรียลไทม์
  • สินค้าหมด (สต็อก = 0) → opacity 55% + cursor not-allowed + กดไม่ได้
  • ↑↓ Enter — keyboard nav

ตะกร้าสินค้าขวา (Cart Card):

  • หัว: "ตะกร้าสินค้า (N ชิ้น)" + ActionIcon พักบิล (ส้ม) + ล้างตะกร้า (แดง)
  • Body: scrollable list ของรายการในตะกร้า (mah=320px) — ปรับจำนวนได้ + ลบทีละอัน
  • Empty state: "ไม่มีสินค้าในตะกร้า" + คำแนะนำ

สรุปการชำระเงิน (Summary Card — ใต้ตะกร้า):

  • ลูกค้า dropdown + ปุ่มเพิ่มลูกค้าใหม่
  • ยอดรวม (auto จากตะกร้า)
  • ส่วนลด (NumberInput)
  • ยอดชำระ (xl cyan)
  • ปุ่มเลือกวิธีชำระ 4 ปุ่ม
  • Cash: NumberInput รับเงิน + ปุ่ม +20/+50/+100/+500/+1000 + พอดี/ล้าง + กล่องเงินทอน
  • PromptPay: QR Code 200×200 + ยอดเงิน
  • ปุ่มใหญ่ "ยืนยันการขาย" (disabled ถ้าตะกร้าว่างหรือยังไม่เลือกวิธีชำระ)

Empty + Loading states:

  • กำลังโหลด catalog → Loader + "กำลังโหลดสินค้า..."
  • กำลังค้นหา → Loader + "กำลังค้นหา..."
  • ค้นหาแล้วไม่พบ → IconSearch + "ไม่พบสินค้าตรงกับ '{query}' — ลอง IMEI / SKU / ชื่อรุ่น หรือกดปุ่มสแกน"
  • สาขายังไม่มีสินค้า → IconInbox + "ไม่มีสินค้าในสาขานี้ — เพิ่มสินค้าได้ที่ สต็อกมือถือ หรือ อุปกรณ์เสริม"

Auto-refresh + Cart-aware:

  • หลังขายสำเร็จ (checkout) → catalog reload อัตโนมัติ — IMEI ที่ขายไปแล้วหายจาก grid ทันที
  • ระหว่างคีย์ (real-time): ใส่สินค้าลงตะกร้าแล้ว → grid hide รายการนั้นทันที (มือถือ unique IMEI หายเลย / อุปกรณ์ลดยอดเหลือ N − cart) — ไม่ขายซ้ำ + cashier เห็นยอดแม่นยำ
  • ลบจาก cart → กลับมาแสดงใน grid อีกครั้ง

Performance optimizations (สำหรับร้านที่สต็อกเยอะ):

  • โหลด 60 ตัวต่อประเภท สูงสุด (120 รวม) — สมัยใหม่หา IMEI/SKU ผ่าน search box ได้
  • รูปภาพ loading="lazy" — โหลดเฉพาะการ์ดที่อยู่ใน viewport (ลดภาระ network ลง 80% สำหรับร้านสต็อก 100+)
  • Hover ใช้ DOM mutation ไม่ผ่าน React state — ไม่ re-render การ์ดอื่นเวลา cursor เคลื่อนไหว

6.2 วิธีชำระเงิน

วิธีไอคอนรายละเอียด
เงินสด (Cash)💵รับเงินสด — กรอกจำนวนรับ ระบบคำนวณเงินทอน
โอนเงิน (Transfer)🏦โอนผ่านธนาคาร — บันทึกเลขอ้างอิง
บัตรเครดิต (Credit Card)💳รูดบัตร — บันทึกเลขอนุมัติ
PromptPay📱สร้าง QR Code PromptPay อัตโนมัติ

6.3 PromptPay QR Code

ขั้นตอน:

  1. เลือกวิธีชำระ "PromptPay"
  2. ระบบสร้าง QR Code จากหมายเลข PromptPay ของร้าน (ตั้งค่าใน Settings)
  3. แสดง QR Code บนหน้าจอ
  4. ลูกค้าสแกนด้วยแอป Banking
  5. ยืนยันการรับเงิน กดปุ่ม "ยืนยันชำระ"

⚠️ หมายเหตุ: ตั้งค่าเบอร์ PromptPay ได้ที่ ตั้งค่า → ข้อมูลร้านค้า → PromptPay Phone

6.4 หน้าจอแสดงราคาลูกค้า (Customer Display) — Pro+

📍 หน้า: /customer-display 📦 แพ็คเกจ: Professional หรือ Enterprise (ฟีเจอร์นี้ถูกล็อคในแพ็คเกจ Starter)

  • เปิดหน้าจอแยกบนจอที่หันหาลูกค้า
  • แสดงรายการสินค้าในตะกร้าแบบ Real-time (Socket.IO)
  • แสดงราคารวมและส่วนลด
  • แสดง QR Code PromptPay เมื่อเลือกชำระ

การใช้งาน:

  1. ที่หน้า ขายสินค้า (POS) → กดปุ่ม "เปิดจอลูกค้า" มุมขวาบน
  2. ระบบเปิดหน้าต่างใหม่ขนาดเต็มจอ
  3. ตั้งจอที่ 2 / แท็บเล็ตหันหาลูกค้า
  4. ระบบจะแสดงข้อมูลตะกร้าแบบ Real-time โดยอัตโนมัติ + Badge "เชื่อมต่อแล้ว"

⚠️ ถ้าแพ็คเกจของคุณยังไม่รวม ปุ่ม "เปิดจอลูกค้า" จะถูกซ่อนอัตโนมัติ — ต้องอัพเกรดเป็น Professional ขึ้นไป

💡 เคล็ดลับ: ใช้ได้ทั้งจอ Monitor เพิ่มเติม หรือแท็บเล็ตที่ตั้งหันหาลูกค้า

6.5 พักบิล (Park / Hold Bill)

📍 เปิดได้ที่: ปุ่ม "พักบิล" ในตะกร้า + ปุ่ม "บิลที่พักไว้ (N)" มุมขวาบน

วัตถุประสงค์: เก็บตะกร้าค้างไว้ก่อนชำระ — เช่น ลูกค้าเดินไปดูเคสเพิ่ม, หาเงินก่อน, ขอเปลี่ยนใจ → cashier กดพักบิลเพื่อรับลูกค้าคนถัดไปได้ทันที, ตอนกลับมาเปิด "บิลที่พักไว้" → restore cart → ชำระต่อ

ขั้นตอน:

  1. คีย์ตะกร้าตามปกติ → กดปุ่ม "พักบิล" (สีส้ม)
  2. ใส่ note (ไม่บังคับ) เช่น "ลูกค้าไปดู iPhone อีกอัน" หรือ "รอลูกค้ากลับมาจ่าย"
  3. กด "พักบิล" ยืนยัน → ตะกร้าเคลียร์ทันที พร้อมรับลูกค้าคนถัดไป
  4. ตอนลูกค้ากลับมา → กดปุ่ม "บิลที่พักไว้ (N)" มุมขวาบน → Drawer แสดงรายการ
  5. กด "เปิดบิลนี้" → ตะกร้าถูก restore ทุกรายการ + ลูกค้า + ส่วนลด → ชำระต่อตามปกติ

สิ่งที่บันทึก:

  • รายการสินค้าทั้งหมด (มือถือ + อุปกรณ์เสริม)
  • ส่วนลดที่กรอกไว้
  • ลูกค้าที่เลือก (ถ้ามี)
  • ผู้พักบิล + เวลา
  • Note

สิ่งที่ ยังไม่ทำ ตอนพักบิล:

  • ไม่ตัดสต็อก — สินค้ายังขายให้คนอื่นได้ปกติ (ตัดเฉพาะตอน checkout จริง)
  • ไม่สร้าง Sale record — ไม่นับยอดในรายงาน

ข้อสังเกต:

  • จำนวนบิลที่พักไว้แสดงในปุ่มที่มุมขวาบนตลอดเวลา ([พัก 0] / [พัก 3])
  • บิลที่พักไว้ เห็นข้าม cashier — Cashier A พักไว้, Cashier B เปิดต่อได้
  • กรอง ตามสาขา อัตโนมัติ — สาขาอื่นไม่เห็นบิลของสาขานี้
  • Real-time refresh ผ่าน Socket.IO เมื่อ cashier อื่นพักหรือเปิดบิล
  • ลบบิลที่พักไว้โดยตรงได้จาก Drawer (กดถังขยะข้างปุ่ม "เปิดบิลนี้")

💡 เคล็ดลับ: ทุกคืนปิดร้านควรเช็ค "บิลที่พักไว้" → ถ้ามีค้างให้ตัดสินใจว่าจะ checkout หรือลบ ไม่ปล่อยค้างหลายวัน

6.6 ประวัติการขาย (Sales History)

📍 หน้า: /sales-history 👤 สิทธิ์: OWNER, ADMIN, MANAGER, CASHIER, SALES, SALESTECH

วัตถุประสงค์: รวมงาน post-checkout ทั้งหมดในที่เดียว — ดูประวัติบิล / พิมพ์ใบเสร็จซ้ำ / ยกเลิกบิล / คืนเงิน / ปิดยอดสิ้นวัน

เลขที่ใบเสร็จ: ทุกบิลใหม่จะได้เลขรูปแบบ RC-{branchCode}-{BEyear}-{seq:04} (เช่น RC-HQ-2569-0001 = บิลใบแรกของสาขา HQ ปี พ.ศ. 2569) — เลขรันต่อเนื่อง ทั้งปีภาษี (reset 1 ม.ค.) แยกต่อสาขา ตามกฎสรรพากร (ประกาศอธิบดี ว.196/2553) ดูรายละเอียดที่ §12.0

หน้าหลัก /sales-history

ตัวกรอง:

  • ช่วงวันที่ (date range — Thai พ.ศ.)
  • สถานะบิล: ทุกสถานะ / ใช้งาน / ยกเลิก / คืนเงินทั้งบิล / คืนเงินบางส่วน
  • วิธีชำระ: ทุกวิธี / เงินสด / โอนเงิน / บัตรเครดิต
  • ค้นหา: เลขใบเสร็จ / IMEI / ชื่อลูกค้า / เบอร์โทรลูกค้า (debounce 300ms)

ตาราง (desktop) / Card (mobile):

  • เลขใบเสร็จ (cyan)
  • วันที่ + เวลา
  • ชื่อลูกค้า + เบอร์
  • จำนวนรายการ + ยอดรวม
  • วิธีชำระ + ผู้ขาย
  • Badge สถานะ: 🟢 ใช้งาน / 🔴 ยกเลิก / 🟠 คืนเงินทั้งบิล / 🟡 คืนเงินบางส่วน
  • กดแถว → SaleDetailModal

พิมพ์ใบเสร็จซ้ำ (Reprint)

ใน SaleDetailModal → ปุ่ม "พิมพ์ใบเสร็จ" (สีฟ้า) → เปิด Receipt modal เดียวกับตอนขาย → เลือก thermal 80mm หรือ A4 → พิมพ์

💡 ใช้กรณี: ลูกค้ากลับมาบอกว่า "หาใบเสร็จไม่เจอขอใหม่" → ค้นหาบิลด้วยเบอร์โทร / IMEI → กดพิมพ์ซ้ำ

ยกเลิกบิล (Void) — ADMIN เท่านั้น

📍 ปุ่ม "ยกเลิกบิล" (สีแดง) ใน SaleDetailModal — แสดงเฉพาะบิลสถานะ ใช้งาน + role ADMIN/OWNER

ขั้นตอน:

  1. กด "ยกเลิกบิล" → Modal เตือน
  2. กรอก เหตุผลการยกเลิก (บังคับ — เช่น "คีย์ผิดบิล", "ลูกค้าเปลี่ยนใจ")
  3. กด "ยืนยันยกเลิกบิล"
  4. ระบบ: คืนสต็อก (มือถือ → AVAILABLE, อะไหล่ → +quantity) + บันทึก audit log + Badge เปลี่ยนเป็น 🔴 "ยกเลิก"

บิลที่ยกเลิกแล้ว: ดูได้ตลอด แต่พิมพ์ใบเสร็จไม่ได้ + ไม่นับยอดในรายงาน + ไม่นับใน Z report

คืนเงิน / รับคืนสินค้า (Refund) — MANAGER+

📍 ปุ่ม "คืนเงิน" (สีส้ม) ใน SaleDetailModal — role MANAGER/ADMIN/OWNER

Wizard 3 ขั้นตอน:

Step 1 — เลือกรายการที่คืน:

  • Checkbox + จำนวน + ปุ่ม "คืนเข้าสต็อก" (toggle)
  • ถ้าสินค้าเสียหาย/ใช้แล้ว → ปิด toggle "คืนเข้าสต็อก" → ระบบจะคืนเงินแต่ไม่เพิ่มสต็อกกลับ

Step 2 — วิธี + เหตุผล:

  • เลือกวิธีคืน: เงินสด / โอนคืนเข้าบัญชี / เก็บเครดิตร้าน
  • กรอกเหตุผล (บังคับ)

Step 3 — ตรวจสอบ:

  • แสดงสรุปก่อนยืนยัน
  • กด "ยืนยันคืนเงิน" → ระบบสร้าง Refund record + คืนสต็อก + ออก ใบลดหนี้ (Credit Note) อัตโนมัติให้พิมพ์

สถานะหลังคืนเงิน:

  • คืนทุกชิ้น → 🟠 "คืนเงินทั้งบิล" (REFUNDED)
  • คืนบางชิ้น → 🟡 "คืนเงินบางส่วน" (PARTIALLY_REFUNDED) — ยังคืนเงินเพิ่มได้ในชิ้นที่เหลือ
  • รายการ Refund ปรากฏในประวัติของ SaleDetailModal (Alert สีส้ม)

⚠️ คืนเงินไม่ได้ถ้าบิลสถานะ: ยกเลิกแล้ว / คืนเงินทั้งบิลแล้ว

ปิดยอดสิ้นวัน (Z Report)

📍 ปุ่ม "ปิดยอดวันนี้" มุมขวาบนของหน้า /sales-history

ใช้ทำอะไร: สรุปยอดทุกอย่างของวันนั้น สำหรับเช็คเงินสดในลิ้นชัก / นำส่งหัวหน้า / เก็บเป็นหลักฐาน — มาตรฐาน retail ทั่วโลก เรียกว่า "Z Report"

เนื้อหา:

ส่วนรายละเอียด
3 KPIบิลทั้งหมด + บิลยกเลิก + ครั้งที่คืนเงิน
สรุปยอดยอดขายรวม − VAT − คืนเงิน = รายได้สุทธิ
แยกตามวิธีชำระ (รับเข้า)เงินสด / โอน / บัตร — แต่ละแบบ บิลกี่ใบ ยอดเท่าไหร่
แยกตามวิธีคืนเงิน (จ่ายออก)เงินสด / โอน / เครดิต — แต่ละแบบ ครั้งกี่ครั้ง ยอดเท่าไหร่
ยอดเงินสดคงเหลือในลิ้นชัก (คาดหมาย)= เงินสดเข้า − เงินสดคืน → ตัวเลขที่ควรนับเจอตอนปิดร้าน

พิมพ์ Z Report: A4 — มี 2 ช่องลายเซ็น (Cashier ผู้ปิดยอด + ผู้ตรวจสอบ) เก็บไว้เป็นเอกสารตอนปิดร้าน

เลือกวันได้: Default เป็นวันนี้ — เปลี่ยนวันที่เพื่อดู Z Report ย้อนหลังได้

💡 เคล็ดลับ: ปิดร้านทุกคืนให้พิมพ์ Z Report → นับเงินสดในลิ้นชัก → เทียบกับ "ยอดเงินสดคงเหลือคาดหมาย" → ถ้าไม่ตรง ต้องหาสาเหตุก่อนเลิกงาน

6.7 รับเทรดเครื่องเก่า (Trade-in) ⭐ NEW

📍 ตำแหน่ง: ปุ่มในหน้า /sales POS (ใต้ cart summary) 👤 สิทธิ์: ทุก role ที่ขายได้

วัตถุประสงค์: ลูกค้าที่ซื้อเครื่องใหม่มักอยากเอาเครื่องเก่ามาตีเครดิต. ก่อนหน้านี้ cashier ต้องทำ 2 transactions แยก (Purchase + Sale) → cashier งง + ตีเงินไปกลับไปกลับมา + ไม่มี link ระหว่างเครื่องเก่ากับ sale

Workflow ใหม่ — เซลเดียว:

  1. ขายเครื่องใหม่ → เพิ่มสินค้าลงตะกร้าตามปกติ (เช่น iPhone 15 ฿35,000)
  2. กดปุ่ม + รับเทรดเครื่องเก่า ใต้ summary
  3. Modal เปิด → กรอก:
    • ยี่ห้อ + รุ่นเครื่องเก่า (Select จาก master)
    • IMEI (ไม่บังคับ — ระบบ auto-gen ถ้าเว้น)
    • สภาพ (NEW / LIKE_NEW / GRADE_A/B/C/D)
    • ราคาตั้งต้น (basePrice) + หัก (deductions) → ราคาสุทธิ auto-calc
  4. Preview card สีฟ้าแสดง:
    • ยอดเครื่องใหม่ ฿35,000
    • − ตีเครดิตเครื่องเก่า ฿10,000
    • = ลูกค้าจ่ายเพิ่ม ฿25,000
    • (ถ้าตีเครดิตมากกว่าเครื่องใหม่ → Alert orange เตือนต้องคืนเงินส่วนต่าง)
  5. กด ใช้ตีเครดิต ฿X → modal ปิด → ใน cart มีบรรทัด violet "เครื่องเทรด" + ราคาติดลบ
  6. ยอดชำระ (total) แสดงเฉพาะ net amount due = สิ่งที่ลูกค้าต้องจ่ายเพิ่ม
  7. กด checkout → backend atomic transaction:
    • สร้าง Purchase (เครื่องเก่าเข้าระบบ)
    • สร้าง Product ใหม่จาก purchase (status=AVAILABLE in stock, source=TRADE_IN)
    • สร้าง Sale ของเครื่องใหม่ + เซ็ต tradeInPurchaseId, tradeInValue, netAmountDue
    • คืน sale record + เปิดใบเสร็จ

ข้อดี:

  • Cashier ทำขั้นตอนเดียว ไม่งง
  • Audit trail: ต้นทุน iPhone 12 เก่า = ฿10,000 (จาก trade-in) — ตอนขายต่อในอนาคต กำไรคิดถูกต้อง
  • Sale receipt มีทั้ง 2 รายการ (เครื่องใหม่ + ตีเครดิต) + net amount due
  • Reduce double-counting ในรายงานกำไร

ลบเครื่องเทรด: กดไอคอนถังขยะที่บรรทัด violet → ลบออกก่อน checkout (ก่อน save = แก้ได้)

6.8 การคืนเงิน — Analytics (Refunds list) ⭐ NEW

📍 หน้า: /refunds 👤 สิทธิ์: OWNER, ADMIN, MANAGER

วัตถุประสงค์: ระบบ Refund มีอยู่แล้วฝังใน /sales-history (refund per sale) แต่ไม่มีหน้า list รวม + analytics — ตอนนี้มี

Stat cards:

  • จำนวนรายการ refund
  • เงินที่คืนรวม

Filters:

  • ค้นหา: receipt number / customer name / phone
  • ช่วงวันที่ (default 30 วันล่าสุด)
  • วิธีคืน: ทุกวิธี / CASH / TRANSFER / CREDIT_CARD / STORE_CREDIT / EXCHANGE

List view:

  • แต่ละ row: badge วิธีคืน + receipt number + status (คืนเต็ม/บางส่วน) + customer + วันที่ + เหตุผล + ผู้ทำ refund + จำนวนเงินคืน
  • คลิก → modal detail แสดง returnedItems + เหตุผลเต็ม

ใช้สำหรับ:

  • Audit trail (auditor ขอ refund log บ่อย)
  • Detect fraud — cashier ทำ refund บ่อยผิดปกติ
  • Detect quality issues — มือถือยี่ห้อ X รุ่น Y refund เยอะ → อาจมีปัญหา

6.9 ใบแจ้งหนี้ B2B (SalesInvoice) ⭐ NEW

📍 หน้า: /invoices 👤 สิทธิ์: OWNER, ADMIN

วัตถุประสงค์: ลูกค้าบุคคลจ่ายทันที — ลูกค้าบริษัท (ตัวแทน, ออฟฟิศซื้อยกล็อต) อยากได้ "ใบแจ้งหนี้" + เครดิต net-30/60 จ่ายภายหลัง. ระบบนี้รองรับ B2B workflow ครบ

Customer setup ก่อน: ใน /customers form เพิ่ม fields ใหม่:

  • type: INDIVIDUAL (default) / CORPORATE
  • taxId (13 หลัก)
  • contactPerson
  • paymentTerms: cash / net-7 / net-15 / net-30 / net-60
  • creditLimit (วงเงินเครดิต)
  • currentDebt — ยอดค้างทั้งหมด (auto-update)

6.9.1 ออก Invoice (/invoices → ออก invoice)

Workflow:

  1. กด ออก invoice
  2. เลือกลูกค้า (B2B จะมี badge "B2B")
  3. เพิ่มรายการ — มี 2 modes:
    • ค้นหา product/accessory — type ≥2 chars → search → click result → auto-fill ชื่อ + ราคา + qty=1
    • + รายการเอง — สำหรับ service/labor ที่ไม่มีในสต็อก (พิมพ์เอง)
  4. ปรับ qty / unitPrice ที่ NumberInput (lag-free — uncontrolled refs)
  5. กรอก VAT (ถ้ามีใบกำกับเต็มรูป) + เลือก payment terms
  6. Subtotal / VAT / รวม auto-calc
  7. กด ออก invoice → ระบบ:
    • Auto-detect dueDate จาก paymentTerms (net-30 → +30 วัน)
    • ตั้ง status=ISSUED + เลขที่ INV-{branchCode}-{BEyear}-{seq:04}
    • Increment Customer.currentDebt
    • ตรวจ creditLimit — ถ้าเกิน → block + Alert (เฉพาะ CORPORATE)

6.9.2 รับเงิน (Payment)

ใน detail modal กด บันทึกรับเงิน:

  • กรอก: จำนวนเงิน + วันที่ + วิธีชำระ (cash/transfer/cheque/credit_card) + อ้างอิง (เลขที่เช็ค/slip)
  • ระบบ:
    • สร้าง InvoicePayment record
    • Update Invoice.paidAmount += amount
    • Auto status: PARTIAL_PAID (ถ้า paidAmount < totalAmount) / PAID (ถ้าเต็ม)
    • Decrement Customer.currentDebt
  • รับเงินได้หลายครั้ง — ทุกครั้งบันทึก

6.9.3 Status & Aging

สถานะคำอธิบาย
DRAFTร่าง (ปัจจุบันไม่ได้ใช้ — ออก invoice = ISSUED ทันที)
ISSUEDออกแล้ว รอจ่าย
PARTIAL_PAIDจ่ายแล้วบางส่วน
PAIDจ่ายเต็มแล้ว
OVERDUEเลยกำหนด (ระบบ flag color แดง — manual update หรือ cron)
CANCELLEDยกเลิก

4 Stat cards บน list: จำนวน / รวมยอด / รับเงินแล้ว / คงค้าง (สีส้มถ้า > 0)

Tabs: ทั้งหมด / รอจ่าย / เกินกำหนด / จ่ายแล้ว

UI hints:

  • ครบกำหนดในอีก ≤ 7 วัน → text สีส้ม "เหลือ X วัน"
  • Overdue → text สีแดง "เกิน X วัน"

💡 Tip: ตั้ง creditLimit ให้ลูกค้า CORPORATE ทุกราย — ป้องกันออก invoice ใหม่ตอน debt เกินวงเงิน → หลีกเลี่ยง bad debt

7. ประกันสินค้า

📍 หน้า: /warranty 👤 สิทธิ์: OWNER, ADMIN, MANAGER, CASHIER, SALES, SALESTECH

วัตถุประสงค์: บันทึกและติดตามประกันสินค้าที่ขายออกไป (มือถือและอุปกรณ์เสริม)

ขั้นตอนเพิ่มประกัน:

  1. กดปุ่ม "+ เพิ่มประกัน"
  2. เลือกลูกค้า
  3. เลือกประเภท: มือถือ หรือ อุปกรณ์เสริม
  4. เลือกสินค้าที่ต้องการออกประกัน
  5. เลือกระยะเวลาประกัน (เลือกจาก Master Warranty Periods)
  6. วันเริ่มต้น — วันหมดอายุ (คำนวณอัตโนมัติ)
  7. กรอกหมายเหตุเงื่อนไขประกัน
  8. กดปุ่ม "บันทึก"

สถานะประกัน:

สถานะสีความหมาย
ACTIVEเขียวยังอยู่ในระยะประกัน
EXPIREDแดงหมดอายุแล้ว
CLAIMEDส้มมีการเคลมแล้ว
VOIDเทายกเลิกประกัน

Expiring Warranties Widget:

  • แสดงอยู่ใน Dashboard
  • แจ้งเตือนประกันที่จะหมดอายุใน 30 วัน
  • คลิกเพื่อดูรายละเอียดและติดต่อลูกค้า

8. ลูกค้า

📍 หน้า: /customers 👤 สิทธิ์: OWNER, ADMIN, MANAGER, CASHIER, SALES, SALESTECH

วัตถุประสงค์: จัดการฐานข้อมูลลูกค้า ค้นหา เพิ่ม แก้ไข และดูประวัติ

ขั้นตอนเพิ่มลูกค้าใหม่:

  1. กดปุ่ม "+ เพิ่มลูกค้า"
  2. กรอกข้อมูล:
ฟิลด์คำอธิบายจำเป็น
ชื่อชื่อ-นามสกุล
เบอร์โทรหมายเลขโทรศัพท์
อีเมลอีเมลลูกค้า
ที่อยู่ที่อยู่สำหรับส่งของ
LINE IDสำหรับติดต่อ
วันเกิดสำหรับโปรโมชั่นวันเกิด
หมายเหตุข้อมูลเพิ่มเติม
  1. กดปุ่ม "บันทึก"

ฟีเจอร์ค้นหาลูกค้า:

  • ค้นหาด้วยชื่อ, เบอร์โทร, อีเมล
  • Debounce Search (รอ input หยุดก่อนค้นหา)
  • ค้นหาจากตัวอักษรแรก

ประวัติลูกค้า:

  • คลิกที่ลูกค้าเพื่อดูประวัติ
  • ประวัติการซื้อ (Sales)
  • ประวัติการซ่อม (Repairs)
  • ประกันที่ยังใช้งาน
  • ยอดซื้อทั้งหมด

9. ลงเวลาทำงาน

9.1 หน้าลงเวลา

📍 หน้า: /attendance 👤 สิทธิ์: OWNER, ADMIN, MANAGER

วัตถุประสงค์: ดูรายการการลงเวลาของพนักงาน กรอง ค้นหา และแก้ไข

ฟีเจอร์:

  • ดูรายการการลงเวลาทั้งหมดตาม Branch
  • กรองตามวันที่, พนักงาน
  • ดูเวลาเข้า-ออกงาน
  • ตรวจสอบ Late (สาย) และ Early Leave (ออกก่อนเวลา)
  • แก้ไขการลงเวลาด้วยตนเอง (เมื่อระบบผิดพลาด)
  • Export รายงานการลงเวลา

การลงเวลาผ่านระบบ (Admin):

  1. กดปุ่ม "เปิดสแกน QR" เพื่อสแกน QR Code พนักงาน
  2. เลือก ลงเวลาเข้า หรือ ลงเวลาออก
  3. ระบบบันทึกเวลาอัตโนมัติพร้อม Timestamp

ฟิลด์การลงเวลา:

ฟิลด์คำอธิบาย
พนักงานชื่อ-นามสกุล
เวลาเข้างานCheck-in Time
เวลาออกงานCheck-out Time
ชั่วโมงทำงานคำนวณอัตโนมัติ
สายisLate flag
ออกก่อนเวลาisEarlyLeave flag พร้อม leaveReason
หมายเหตุRemark

9.2 Kiosk Attendance (QR Code) — Pro+

📍 หน้า: /kiosk/login/kiosk 👤 สิทธิ์: ระบบแยกสำหรับพนักงาน (ไม่ต้อง Login หลัก) 📦 แพ็คเกจ: Professional หรือ Enterprise (ฟีเจอร์นี้ถูกล็อคในแพ็คเกจ Starter)

วัตถุประสงค์: หน้าจอ Kiosk สำหรับพนักงานสแกน QR Code เพื่อลงเวลาเข้า-ออก โดยไม่ต้องล็อกอินระบบหลัก — เหมาะกับ tablet/iPad วางหน้าร้าน

การเปิดใช้งาน Kiosk:

  1. ไปที่หน้า ลงเวลา (/attendance) ในฐานะ Admin/Manager
  2. ดูแถบ "โหมด Kiosk ลงเวลา" ด้านบนของหน้า
  3. กดปุ่ม "คัดลอก URL" เพื่อ copy ลิงก์ Kiosk (เช่น https://shop.com/kiosk/login)
  4. หรือกดปุ่ม "เปิด Kiosk" เปิดในแท็บใหม่
  5. นำ URL ไปเปิดบนแท็บเล็ตที่หน้าร้าน → login ครั้งเดียวด้วยบัญชีร้าน

⚠️ ถ้าแพ็คเกจของคุณยังไม่รวม Kiosk panel จะแสดง badge "PRO+" + ปุ่ม "อัพเกรด" → คลิกไปหน้า Billing

ขั้นตอนลงเวลาพนักงาน:

  1. เปิดหน้า /kiosk บนแท็บเล็ตหรือคอมพิวเตอร์หน้าร้าน
  2. พนักงานสแกน QR Code ส่วนตัว (ดูได้จากหน้าผู้ใช้งานหรือโปรไฟล์)
  3. ระบบแสดงชื่อพนักงาน
  4. กดปุ่ม "ลงเวลาเข้า" หรือ "ลงเวลาออก"
  5. ระบบบันทึกเวลาและแจ้งผล (เสียงและ Visual)

QR Code พนักงาน:

  • แต่ละพนักงานมี QR Code เฉพาะตัว
  • ดูได้จากหน้า ผู้ใช้งาน → คลิกพนักงาน → QR Code
  • พิมพ์ QR Code เป็นบัตรลงเวลาได้

💡 เคล็ดลับ: ตั้งแท็บเล็ตไว้ที่ทางเข้าออกร้าน ให้พนักงานสแกนเองทุกวัน ประหยัดเวลาและแม่นยำกว่าการลงเวลาแบบกระดาษ

10. เงินเดือน

📍 หน้า: /payroll 👤 สิทธิ์: OWNER, ADMIN, MANAGER 📦 แพ็คเกจ: ENTERPRISE (PAYROLL feature)

วัตถุประสงค์: คำนวณเงินเดือนพนักงาน เพิ่ม/หักรายการ อนุมัติ บันทึกการจ่าย และพิมพ์สลิป

10.1 การเตรียมข้อมูล (ทำก่อนใช้งานครั้งแรก)

  1. ตั้งเงินเดือนพื้นฐานของพนักงาน ที่ /users → แก้ไข → ช่อง "เงินเดือนพื้นฐาน" → บันทึก. ระบบจะสร้าง EmployeeSalary record อัตโนมัติเมื่อ baseSalary > 0

  2. (แนะนำ) ตั้งค่าประเภทรายการเงินเดือน ที่ /masters/deduction-types:

    • รายได้เพิ่ม (toggle "เป็นรายการหัก" = ปิด): OT, ค่าคอมมิชชั่น, โบนัส, ค่าเดินทาง, เบี้ยขยัน
    • รายการหัก (toggle "เป็นรายการหัก" = เปิด): ภาษีหัก ณ ที่จ่าย, ประกันสังคม, กองทุนสำรอง, มาสาย, ขาดงาน

10.2 ขั้นตอนคำนวณเงินเดือน

  1. กดปุ่ม "คำนวณเงินเดือน" มุมขวาบน
  2. เลือก เดือน + ปี (พ.ศ.) + พนักงาน (เว้นว่าง = คำนวณทุกคน)
  3. กด "คำนวณ" → ระบบสร้าง record Payroll สำหรับพนักงานที่ยังไม่มีรอบนี้
  4. Toast จะรายงานสาเหตุ ถ้าพนักงานบางคนถูกข้าม (ยังไม่ตั้งเงินเดือนพื้นฐาน · มีรอบนี้แล้ว) — ตามเหตุผลแล้วลองใหม่

10.3 เพิ่ม/หักรายการ (Adjustments) — สถานะ PENDING เท่านั้น

ตาราง 4 columns: เงินเดือนพื้นฐาน · รายได้เพิ่ม · รายการหัก · รวมสุทธิ — ค่าจริงดึงจาก totalAdditions / totalDeductions

  1. กด ไอคอน 📊 "รายละเอียด" ในแถวพนักงาน
  2. ใน Modal:
    • Hero card — ชื่อ + รอบเดือน + status badge
    • 3 KPI cards — เงินเดือนพื้นฐาน / รายได้เพิ่ม / รายการหัก
    • Form เพิ่ม adjustment (เห็นเฉพาะ PENDING):
      • ประเภท — เลือกจาก master ที่ตั้งใน /masters/deduction-types (auto-detect รายได้เพิ่ม/หัก จาก isDeduction ของประเภท)
      • รายละเอียด — เช่น "OT 8 ชม. วันที่ 15"
      • จำนวนเงิน — บาท
      • กด "+ เพิ่ม" → backend recompute totalAdditions/totalDeductions/netSalary ทันที
    • List แยก 2 sections — ▲ รายได้เพิ่ม (เขียว) · ▼ รายการหัก (แดง) — แต่ละ row มีปุ่ม 🗑️ ลบ (PENDING เท่านั้น)
    • Net Pay box — สีฟ้าเข้ม + จำนวนเงินใหญ่ + breakdown formula

10.4 สถานะเงินเดือน + Workflow

สถานะสีความหมายทำได้พิมพ์สลิป?
PENDINGเหลืองรอดำเนินการ — ตัวเลขแก้ได้เพิ่ม/ลบ adjustment, อนุมัติ❌ disabled (กันสับสน)
APPROVEDน้ำเงินอนุมัติแล้ว รอจ่าย — lockedบันทึกการจ่าย, พิมพ์สลิป preview
PAIDเขียวจ่ายแล้ว — finalพิมพ์สลิป official (ใช้ขอ visa/loan)

ขั้นตอน:

  1. ตรวจ adjustments ใน detail modal → กด "อนุมัติ" → status APPROVED (ตัวเลข lock)
  2. หลังจ่ายเงินจริง (โอนเข้าบัญชีพนักงาน) → กด "จ่ายเงิน" → ใส่ note (เลขอ้างอิง/วันที่จริง) → status PAID
  3. กด ไอคอน 🖨️ "พิมพ์สลิปเงินเดือน" ในแถว → เปิด Modal preview สลิป A4 → กด "พิมพ์"

10.5 พิมพ์สลิปเงินเดือน (Payslip)

  • เปิดผ่านปุ่ม 🖨️ ในแถว หรือใน detail modal (ปุ่ม "พิมพ์สลิป")
  • รูปแบบ A4 — Hero header + ข้อมูลพนักงาน + 2-col earnings/deductions + Net Pay พร้อมข้อความไทย ("สามหมื่นห้าพันบาทถ้วน") + 2 ลายเซ็น (HR/พนักงาน)
  • บนมือถือ — เลื่อนแนวนอนได้ (slip เป็น A4 width — ห้ามบีบเป็น mobile)

⚠️ กฎทั่วไป: PENDING ปุ่มพิมพ์ disabled — เพราะตัวเลขยังเปลี่ยนได้ พิมพ์ตอนนี้พนักงานเซ็นรับ แล้วแก้ ทำให้สลิปไม่ตรงกับเงินที่จ่ายจริง

10A. ค่าใช้จ่ายดำเนินงาน (Operating Expenses)

📍 เส้นทาง: เมนูซ้าย → "พนักงาน & การเงิน" → ค่าใช้จ่าย (/expenses) 👤 สิทธิ์: OWNER, ADMIN

วัตถุประสงค์: บันทึกค่าใช้จ่ายดำเนินงาน (ค่าเช่าร้าน, ค่าน้ำ-ไฟ, ค่าน้ำมัน, marketing, ฯลฯ) ที่ไม่ใช่ค่าซื้อสินค้าหรือเงินเดือน — เพื่อให้:

  1. PIT ACTUAL deduction ครบถ้วน — ภ.ง.ด.94/90 วิธี ACTUAL ต้องบวก expense รายการนี้เข้าด้วย ไม่งั้นหักได้น้อยเกินจริง
  2. ภาษีซื้อใน ภ.พ.30 — ค่าใช้จ่ายที่มีใบกำกับเต็มรูป (เช่น ค่าน้ำ-ไฟ-เน็ต) ใช้เป็น input VAT ลด net VAT ที่ต้องส่ง
  3. WHT (ภ.ง.ด.3/53) — ถ้าจ่ายค่าจ้าง freelance / outsource → กรอก hasWht + อัตรา → ระบบเก็บข้อมูลเตรียม export ภ.ง.ด.3
  4. CIT (ภ.ง.ด.50/51) — บริษัทใช้คำนวณกำไรสุทธิ (รายได้ − รายจ่าย)

10A.1 หมวดเริ่มต้น (9 หมวด)

ระบบ auto-seed 9 หมวดเมื่อสร้าง tenant ใหม่:

Codeชื่อตัวอย่าง
RENTค่าเช่าร้าน/สำนักงานค่าเช่าตึก, ค่าเช่าโกดัง
UTILITYค่าน้ำ-ค่าไฟ-ค่าน้ำประปาบิลค่าไฟทุกเดือน
INTERNETค่าอินเทอร์เน็ต/โทรศัพท์True/3BB, ค่ามือถือพนักงาน
FUELค่าน้ำมันเชื้อเพลิงปั๊ม PTT, BCP, ส่งของ
MARKETINGค่าโฆษณา/การตลาดFacebook Ads, ป้ายไวนิล
SUPPLIESค่าวัสดุสิ้นเปลือง/ออฟฟิศกระดาษ, หมึก, ถุงพลาสติก
OUTSOURCEค่าจ้างซ่อม/Outsourceส่งศูนย์ซ่อม mainboard
PROFESSIONALค่าทำบัญชี/ที่ปรึกษาสำนักงานบัญชี, ทนาย
OTHERอื่นๆกรณีไม่เข้าหมวดใด

จัดการเพิ่ม/แก้ไข/ลบหมวดได้ที่ /masters/expense-categories

10A.2 บันทึกค่าใช้จ่ายใหม่

  1. กดปุ่ม + เพิ่มค่าใช้จ่าย
  2. กรอกข้อมูล:
ฟิลด์คำอธิบายจำเป็น
วันที่วันที่จ่ายเงินจริง (หรือวันที่ในใบกำกับภาษี)
หมวดเลือกหมวด (RENT/UTILITY/...)
ผู้ขายชื่อร้าน/บริษัท เช่น "การไฟฟ้านครหลวง"
จำนวนเงิน (ก่อน VAT)ราคาก่อนภาษีมูลค่าเพิ่ม
ภาษีซื้อ (VAT)ใส่เฉพาะใบกำกับเต็มรูป — ใช้ใน ภ.พ.30
เลขที่ใบกำกับสำหรับใบกำกับเต็มรูป
วิธีชำระเงินสด / โอน / PromptPay / บัตร
รายละเอียดบันทึกเพิ่มเติม
ใบเสร็จ/สลิปถ่ายรูปแนบ (jpg/png)
หัก ณ ที่จ่ายtoggle เปิด-ปิด
  1. ถ้าเปิด หัก ณ ที่จ่าย → กรอกเพิ่ม:
    • อัตรา WHT: 1% ดอกเบี้ย / 3% บริการ / 5% เช่า / 15% วิชาชีพอิสระ
    • ชื่อผู้รับเงิน + เลขประจำตัวผู้เสียภาษี — ใช้สำหรับกรอก ภ.ง.ด.3/53
    • ระบบคำนวณ whtAmount อัตโนมัติ (amount × rate ÷ 100)
  2. กด บันทึก

10A.3 รายงาน + Export

  • Stat cards 4 ใบบนหน้า /expenses — จำนวนรายการ / รวมก่อน VAT / ภาษีซื้อ / WHT รวม
  • Filter — ค้นหา + หมวด + เดือน/ปี + WHT toggle
  • Export to /tax/pit — ค่าใช้จ่ายในช่วงเวลานั้นถูกรวมเข้า "ACTUAL deduction" อัตโนมัติเมื่อ tenant ใช้วิธี ACTUAL
  • Export to /tax/vat — ค่าใช้จ่ายที่มี vatAmount > 0 ถูกรวมเข้า "ภาษีซื้อ" ของ ภ.พ.30 อัตโนมัติ

💡 เคล็ดลับ: บันทึกทันทีหลังจ่ายเงินทุกครั้ง — ไม่ต้องรอสิ้นเดือน. แนบรูปใบเสร็จด้วยจะใช้เป็น audit trail ตอน RD มาตรวจ

⚠️ คำเตือน: ค่าใช้จ่ายที่หมวด isDeductible=false (ลดหย่อนไม่ได้) จะ ไม่ ถูกรวมใน ACTUAL deduction — ใช้สำหรับค่าใช้จ่ายส่วนตัว/นอกธุรกิจที่อยากบันทึกแต่ไม่อยากให้กระทบภาษี

10B. กะการขาย + ลิ้นชักเงินสด (Cashier Shift)

📍 เส้นทาง: เมนูซ้าย → "ขาย & ลูกค้า" → กะการขาย (/shift) 👤 สิทธิ์: ทุก role ที่ขายได้ (CASHIER, SALES, MANAGER, ADMIN, OWNER) — เปิด-ปิดกะของตัวเอง; ADMIN/MANAGER ดูประวัติของพนักงานคนอื่นได้

วัตถุประสงค์: ทุกร้าน POS ต้องนับเงินสดในลิ้นชักตอนเปิด-ปิดงาน เทียบกับยอดที่ระบบบันทึก เพื่อ:

  • จับ cashier ที่นับผิด/ทอนผิด/ลืมรับ → variance
  • จับการขโมยเงินจากลิ้นชัก
  • มี audit trail ละเอียด ตามข้อกำหนดของผู้สอบบัญชี (CIT/PIT)

10B.0 นโยบายการบังคับเปิดกะ (Shift Enforcement)

ตามมาตรฐาน POS สากล (Microsoft Dynamics 365 Commerce, Shopify POS, Lightspeed) — "POS requires that users have an active and open shift to perform any operations that produce a financial transaction"

กฎ default ใน MobileHub:

Roleต้องเปิดกะก่อนขาย?เหตุผล
CASHIER✅ ใช่คนรับเงินหลัก — accountability + variance check
SALES✅ ใช่พนักงานขายที่รับเงินด้วย — accountability เดียวกัน
MANAGER❌ ไม่ผู้รับผิดชอบสาขา — bypass ได้
ADMIN❌ ไม่ผู้ดูแลระบบ — bypass ได้
OWNER❌ ไม่เจ้าของร้าน — bypass ได้ (มักทำเองคนเดียวในร้านเล็ก)
TECHNICIAN❌ ไม่ช่างซ่อมไม่ได้ขายเอง

ปรับแก้นโยบายได้ที่ /settings → "นโยบายกะการขาย (POS Shift)" — MultiSelect ให้เลือกบทบาทใดบ้างที่ต้องบังคับ. เคลียร์ทั้งหมด = ปิดการบังคับ (ทุก role ขายได้ตรง).

สิ่งที่เกิดถ้าบังคับ + ยังไม่เปิดกะ:

  • หน้า /sales แสดง banner สีส้ม + ปุ่ม "ไปเปิดกะการขาย" → กดเข้า /shift
  • ปุ่ม "ยืนยันการขาย" ถูกซ่อน (Grid ของ POS UI ถูก hide)
  • ถ้ายิง POST /sales ตรง API → backend ตอบ 403 SHIFT_REQUIRED พร้อม message ภาษาไทย
  • การคืนเงิน (refund) ก็ถูก block เหมือนกัน (เงินออกจากลิ้นชัก → ต้อง audit)

10B.1 Workflow 3 ขั้นตอน

(1) เปิดกะ — ตอนเริ่มงาน

  1. นับเงินสดในลิ้นชัก ณ ตอนเริ่มงาน
  2. ไป /shift → กดปุ่ม เปิดกะ
  3. กรอก เงินทอนเริ่มต้น (จำนวนเงินสดที่นับได้) → Submit
  4. ระบบสร้าง CashierSession (status=OPEN) — sale ใหม่ที่ user นี้ขายในสาขานี้จะ link เข้า session อัตโนมัติ

(2) ระหว่างกะ — POS ทำงานปกติ

  • ขายผ่าน /sales ตามปกติ — ไม่ต้องคิดเรื่อง shift
  • ทุก checkout จะถูก link เข้า session ของ user (ถ้ามีกะที่เปิดอยู่)
  • บทบาทที่อยู่ใน list บังคับ (default = CASHIER/SALES) — ถ้ายังไม่เปิดกะจะขายไม่ได้ ตามนโยบาย §10B.0
  • บทบาทที่ bypass (OWNER/ADMIN/MANAGER) — ขายได้ตรง; ถ้าบังเอิญเปิดกะไว้ก็ link เข้า session ของตัวเองอัตโนมัติ; ถ้าไม่เปิด — sale ลอย (ไม่ link)

(3) ปิดกะ — ตอนเลิกงาน

  1. ไป /shift → กดปุ่ม ปิดกะ ที่ card "กะที่เปิดอยู่"
  2. ระบบโชว์ ยอดที่ควรจะมี (Expected) — breakdown:
    เงินทอนเริ่มต้น        ฿ 2,000.00
    + เงินสดที่ขาย (15 ออเดอร์)  ฿ 18,500.00
    − เงินสดที่ refund     ฿     500.00
    ─────────────────────
    = ที่ควรจะมี           ฿ 20,000.00
    
    พร้อมยอดอื่น (โอน/PromptPay/บัตร) ที่ ไม่ต้องนับในลิ้นชัก
  3. นับเงินสดในลิ้นชักจริง → กรอกในช่อง "เงินสดที่นับจริง"
  4. ระบบคำนวณ variance อัตโนมัติ:
    • variance = 0 → 🟢 OK ยอดตรง
    • ±฿1 ขึ้นไป → 🟠 ต้องระบุเหตุผล
    • >฿100 → 🔴 alert สีแดง (อาจมีปัญหาจริง)
  5. กรอกเหตุผล (ถ้ามี variance) → ยืนยันปิดกะ
  6. ระบบบันทึก expected/actual/variance + snapshot ของ totalCashSales/totalTransferSales/totalCardSales/totalCashRefunds + saleCount

10B.2 ความสัมพันธ์กับ Z Report

กะ (Shift)Z Report (end-of-day)
ระดับper cashier (ของพนักงาน 1 คน)ทั้งร้าน (รวมทุกคน)
เปิดต่อวันหลายคนเปิดคนละเวลาได้1 ครั้งสิ้นวัน
ที่อยู่/shift/sales-history?type=z-report
ทำงานคู่กันใช่ — Z Report รวมยอดของทุก shift ในวัน

10B.3 Variance threshold

ระบบเตือนเมื่อ variance > ฿1 แต่ไม่ block — ยังปิดกะได้ถ้ากรอกเหตุผล. เหตุผลทั่วไป:

  • ลูกค้าจ่ายเกินไม่รับเงินทอน
  • เงินทอนเริ่มต้นกะก่อนนับผิด
  • ลืมบันทึก sale ในระบบ (จ่ายเงินสดแต่ไม่ออกใบเสร็จ — discouraged)
  • เก็บเงินไว้ในกระเป๋าตัวเอง (เคยมีกรณีที่ใช้คำนี้ → admin ต้องสอบสวน)

10B.4 Best practices

  • เปิด-ปิดกะ ทุกวัน 1 ครั้ง — ไม่ใช่หลายวันต่อกะ (variance สะสมยากตรวจ)
  • นับเงินจริงด้วยตา — อย่า assume = expected (ระบบ pre-fill เพื่อความเร็ว แต่ต้องนับจริง)
  • Variance > ฿100 → admin ต้องเรียกมาคุย ไม่ปล่อย
  • Audit trail ไม่สามารถลบ/แก้กะที่ปิดแล้ว — ต้องสร้าง adjustment entry ภายหลัง

11. รายงาน

📍 หน้า: /reports 👤 สิทธิ์: OWNER, ADMIN, MANAGER

วัตถุประสงค์: ดูรายงานสรุปในรูปแบบต่างๆ เลือกช่วงวันที่ Export Excel ได้

ประเภทรายงาน:

รายงานคำอธิบาย
📊 รายงานยอดขายสรุปยอดขายสินค้า ยอดรวม จำนวนรายการ
🔧 รายงานการซ่อมสรุปงานซ่อม ค่าซ่อม สถิติตามช่าง
🛒 รายงานการรับซื้อสรุปการรับซื้อสินค้า ต้นทุน
📦 รายงานสินค้าคงเหลือStock มือถือและอุปกรณ์เสริมปัจจุบัน
💰 สรุปการเงินกำไร-ขาดทุน รายรับ-รายจ่ายรวม
🧾 สรุปภาษี VAT (ภ.พ.30)ยอด VAT ที่เก็บได้ สำหรับร้านที่จด VAT
🧮 ภาษีเงินได้ (ภ.ง.ด.94/90)คำนวณภาษีบุคคลธรรมดา + ตารางอัตราก้าวหน้า 8 ขั้น

ขั้นตอนดูรายงาน:

  1. เลือก ประเภทรายงาน จาก Dropdown
  2. เลือก ช่วงวันที่ ด้วย CustomDatePicker (ปฏิทินพุทธศักราช)
  3. กดปุ่ม "โหลดรายงาน"
  4. ดูข้อมูลในตาราง (Desktop) หรือ Card (Mobile)
  5. กดปุ่ม "Export Excel" เพื่อดาวน์โหลดไฟล์ .xlsx (📦 Pro+ เท่านั้น)

📦 Export Excel/PDF เป็นฟีเจอร์ของแพ็คเกจ Professional ขึ้นไป — ในแพ็คเกจ Starter ปุ่มจะ disable แสดงข้อความ "PRO+ เท่านั้น"

💡 เคล็ดลับ: เลือกช่วงวันที่เป็น "เดือนปัจจุบัน" เพื่อดูยอดรวมประจำเดือน

11.1 ภาษีเงินได้บุคคลธรรมดา (ภ.ง.ด.94/90) ⭐ ใหม่

📍 เลือก: /reports → ภาษีเงินได้บุคคลธรรมดา (ภ.ง.ด.94/90) 👤 สำหรับ: ร้านที่ไม่ได้จดเป็นนิติบุคคล (บุคคลธรรมดา) — ทั้งร้านที่จด VAT และไม่จด VAT

วัตถุประสงค์: คำนวณภาษีเงินได้สำหรับเจ้าของกิจการที่เป็น<strong>บุคคลธรรมดา</strong> ภายใต้มาตรา 40(8) (เงินได้จากการพาณิชย์) — ครอบคลุมทั้ง ภ.ง.ด.94 (กลางปี) และ ภ.ง.ด.90 (เต็มปี)

ก่อนใช้งาน — ตั้งค่าที่ /settings → ภาษีเงินได้ (ภ.ง.ด.):

  1. ประเภทผู้เสียภาษี — เลือก "บุคคลธรรมดา" (นิติบุคคลยังไม่รองรับ)
  2. วิธีหักค่าใช้จ่าย — เลือก:
    • หักเหมา 60% (แนะนำ) — ระบบหักให้อัตโนมัติ ไม่ต้องเก็บใบเสร็จรายจ่าย
    • หักตามจริง — ใช้ต้นทุนจริง (รับซื้อ + อะไหล่ที่เบิก + เงินเดือนพนักงาน) เหมาะถ้ารายจ่าย > 60%
  3. เลขผู้เสียภาษี 13 หลัก (ใช้บัตรประชาชนเจ้าของ — optional แต่จะแสดงในเอกสาร)
  4. ค่าลดหย่อน — แบ่ง 4 กลุ่ม ตามแบบ ภ.ง.ด.90 ปี 2568:
    • กลุ่ม 1 ส่วนตัวและครอบครัว: ส่วนตัว 60k, คู่สมรส, จำนวนบุตร, จำนวนพ่อแม่
    • กลุ่ม 2 การออมและการลงทุน: ประกันสังคม, ประกันชีวิต/สุขภาพ, RMF, SSF, กองทุนสำรองเลี้ยงชีพ
    • กลุ่ม 3 สินทรัพย์และมาตรการรัฐ: ดอกเบี้ยบ้าน, Thai ESG, ช้อปดีมีคืน/Easy E-Receipt, Solar rooftop
    • กลุ่ม 4 เงินบริจาค: บริจาคทั่วไป, บริจาคการศึกษา (×2), พรรคการเมือง

ขั้นตอนดูรายงาน:

  1. เลือก ประเภทรายงาน: "ภาษีเงินได้บุคคลธรรมดา (ภ.ง.ด.94/90)"
  2. เลือก ช่วงเวลา: ครึ่งปีแรก (ภ.ง.ด.94) / ทั้งปี (ภ.ง.ด.90) / ช่วงที่กำหนด
  3. เลือก ปีภาษี (ปฏิทินพุทธ-คริสต์)
  4. กด "โหลดรายงาน"

ผลลัพธ์ที่แสดง:

  • 4 การ์ดสรุป — รายได้รวม / หักค่าใช้จ่าย / หักค่าลดหย่อน / ภาษีต้องชำระ (สีฟ้าเด่น)
  • คอลัมน์ซ้าย — math chain: รายได้ → หักค่าใช้จ่าย → หักค่าลดหย่อน → เงินได้สุทธิที่ต้องเสียภาษี
    • ค่าลดหย่อนแสดงแบ่งตาม 4 กลุ่ม ตามแบบ ภ.ง.ด.90 ราชการ
    • กรณีรายได้เกิน 1 ล้าน — มีกล่องเปรียบเทียบ ม.48(2) (วิธีก้าวหน้า vs 0.5%) แสดงว่าใช้วิธีไหน
  • คอลัมน์ขวา — ตารางอัตราภาษีก้าวหน้า 8 ขั้น (0/5/10/15/20/25/30/35%) แต่ละช่วงแสดงฐาน + ภาษีในช่วงนั้น
  • กล่องสรุปสุดท้าย — ภาษีรวมสีฟ้า cyan-7 + ฉลาก ภ.ง.ด.94/90 ปีภาษี + วิธีคำนวณที่ใช้

📜 กฎ ม.48(2): ผู้มีรายได้จาก ม.40(8) เกิน <strong>1,000,000 บาท/ปี</strong> ต้องเปรียบเทียบ 2 วิธี และเสียภาษีตามวิธีที่<strong>ได้ตัวเลขสูงกว่า</strong>: (a) อัตราก้าวหน้า 8 ขั้น vs (b) 0.5% × รายได้รวม ระบบเปรียบเทียบและเลือกวิธีที่ถูกต้องให้อัตโนมัติ

พิมพ์เอกสาร ภ.ง.ด. (ใหม่):

  1. กดปุ่ม "พิมพ์ ภ.ง.ด.94" หรือ "พิมพ์ ภ.ง.ด.90" ที่มุมขวา
  2. หน้าต่าง Modal preview เปิดขึ้น — A4 portrait, accountant-summary style
  3. มี 4 sections: ก. รายได้ / ข. ค่าใช้จ่าย / ค. ค่าลดหย่อน / ง. การคำนวณภาษีก้าวหน้า
  4. กล่องสรุปสุดท้าย "ภาษีที่ต้องชำระ" สีฟ้า + ลายเซ็น 2 ช่อง (ผู้เสียภาษี / ผู้ทำบัญชี)
  5. กด "พิมพ์" → เปิด print dialog ของเบราว์เซอร์

⚠️ ข้อสำคัญ: เอกสารฉบับนี้เป็น<strong>เอกสารอ้างอิง</strong>เท่านั้น — การยื่นภาษีจริงต้องผ่าน <strong>e-Filing</strong> ของกรมสรรพากรที่ <a href="https://efiling.rd.go.th/">efiling.rd.go.th</a> ตัวเลขในเอกสารคำนวณจากข้อมูลในระบบ MobileHub และต้องตรวจสอบโดยผู้เสียภาษีอีกครั้งก่อนยื่น

กำหนดการยื่นจริง:

  • ภ.ง.ด.94 (ครึ่งปีแรก ม.ค.–มิ.ย.) — ยื่นช่วง 1 ก.ค. – 30 ก.ย.
  • ภ.ง.ด.90 (เต็มปี) — ยื่นช่วง 1 ม.ค. – 31 มี.ค. ของปีถัดไป

ทำไมเหมาะกับร้านมือถือ?

  • ร้านส่วนใหญ่รายได้ต่ำกว่า 1.8 ล้าน/ปี ไม่ต้องจด VAT แต่<strong>ยังต้องยื่นภาษีเงินได้</strong>
  • การหักเหมา 60% ช่วยให้คำนวณง่าย ไม่ต้องเก็บใบเสร็จรายจ่ายแยก
  • ใช้ข้อมูลจากระบบ MobileHub ที่มีอยู่แล้ว (Sale + Repair → รายได้, Purchase + Parts + Payroll → รายจ่าย)
  • ตารางอัตราก้าวหน้าโชว์ให้เห็นชัด: คุณจ่าย 35% เฉพาะส่วนเกิน 5 ล้าน ไม่ใช่ทั้งก้อน

11A. ภาษี (เมนูใหม่ — /tax) ⭐ NEW

📍 เมนูใหม่บน sidebar: "ภาษี" — section header + 4 sub-items 👤 สิทธิ์: ADMIN, OWNER

วัตถุประสงค์: รวบรวมเมนูที่เกี่ยวกับ<strong>ภาษี</strong>ทั้งหมดไว้ที่เดียว — ตั้งค่า, คำนวณ, พิมพ์เอกสาร เพื่อใช้งานในช่วงเตรียมยื่นภาษี

โครงสร้างเมนู

📊 ภาษี
├── 🏛 ภาพรวม                /tax           — Dashboard + กำหนดยื่น + Quick stats
├── 🧮 ภ.ง.ด.94/90 (PIT)      /tax/pit       — คำนวณภาษีเงินได้บุคคลธรรมดา (8-tier progressive + ม.48(2))
├── 🏢 ภ.ง.ด.50/51 (CIT)      /tax/cit       — คำนวณภาษีเงินได้นิติบุคคล (SME 0/15/20% หรือ Non-SME 20%)
├── ⚖️  ภ.พ.30 (VAT)           /tax/vat       — สรุปภาษีมูลค่าเพิ่มรายเดือน
├── 💰 ภ.ง.ด.3/53 (WHT)       /tax/wht       — สรุปหัก ณ ที่จ่ายตามผู้รับ + Export CSV
└── ⚙️  ตั้งค่าภาษี              /tax/settings  — entityType + วิธีหักค่าใช้จ่าย + ค่าลดหย่อน 4 กลุ่ม

11A.1 ภาพรวมภาษี (/tax)

หน้าศูนย์กลางสำหรับงานภาษี แสดง:

  • Status alert — แจ้งเตือนถ้าตั้งค่ายังไม่ครบ (entityType / taxId / ค่าลดหย่อน)
  • 4 stat cards — รายได้ YTD / ภาษีเงินได้ประมาณการ / VAT สุทธิเดือนนี้ / สถานะการตั้งค่า
  • กำหนดยื่นถัดไป — รายการ ภ.พ.30 / ภ.ง.ด.94 / ภ.ง.ด.90 พร้อมวันที่ + จำนวนวันที่เหลือ (สีแดงถ้า ≤ 7 วัน)
  • เครื่องมือภาษี 4 cards — คลิกไป sub-page ตามต้องการ

11A.2 ภ.ง.ด.94/90 (/tax/pit)

หน้าคำนวณภาษีเงินได้บุคคลธรรมดา (รายละเอียดเดียวกับ §11.1 ก่อนแยกเมนู) — กดปุ่มภายในหน้าเพื่อพิมพ์เอกสารอ้างอิง

11A.3 ภ.ง.ด.50/51 — ภาษีเงินได้นิติบุคคล (/tax/cit) ⭐ NEW

📍 เส้นทาง: /tax/cit (sub-menu ของ /tax) 👤 เงื่อนไข: tenant.entityType = CORPORATION เท่านั้น (เปลี่ยนได้ที่ /tax/settings)

คำนวณภาษีจากกำไรสุทธิ (Net Profit = รายได้ − รายจ่าย) ตามอัตรา:

ประเภทเกณฑ์อัตรา
SMEรายได้ ≤ 30,000,000 บาท/ปี0–300k = 0% · 300k–3M = 15% · เกิน 3M = 20%
Non-SMEรายได้ > 30 ล้านflat 20% ทั้งหมด

Workflow:

  1. ไปที่ /tax/cit
  2. เลือกรอบบัญชี (H1 = ภ.ง.ด.51 ครึ่งปี / FULL = ภ.ง.ด.50 ทั้งปี) + ปี
  3. ระบบโหลดข้อมูลและแสดง:
    • 4 stat cards: รายได้รวม / รายจ่ายรวม / กำไรสุทธิ (เขียวถ้า > 0, แดงถ้าขาดทุน) / ภาษีต้องชำระ + SME badge
    • งบกำไรขาดทุน (P&L) — แยก revenue 2 ตัว (ขาย + ซ่อม) − expense 4 ตัว (ต้นทุนสินค้า + อะไหล่ + เงินเดือน + operating)
    • Tax bracket table — แสดงทุก bracket พร้อม taxable + tax — เห็นชัดว่าเสียในแต่ละช่วงเท่าไร
  4. ถ้าขาดทุน → Alert แจ้งว่าไม่ต้องเสียภาษี + ข้อแนะนำ loss carry forward 5 ปี
  5. ถ้าครึ่งปี (ภ.ง.ด.51) → Alert แจ้งว่าใช้เป็นเครดิตหักจาก ภ.ง.ด.50 ตอนสิ้นปี

Deadline:

  • ภ.ง.ด.51: ภายใน 2 เดือนหลังสิ้นรอบครึ่งปีบัญชี (ปกติ 31 ส.ค.)
  • ภ.ง.ด.50: ภายใน 150 วันหลังสิ้นรอบบัญชี (ปกติ 30 พ.ค.)

⚠️ คำเตือน: ผลคำนวณนี้เป็นการประมาณการเบื้องต้น — รายการค่าใช้จ่ายบางตัวอาจเป็น "ค่าใช้จ่ายต้องห้าม" ตาม ม.65 ทวิ (เช่น ค่ารับรองเกิน 0.3% ของรายได้, ค่าเสื่อมราคารถยนต์ส่วนเกิน 1 ล้าน, ฯลฯ) ต้อง บวกกลับ ในการคำนวณภาษีจริง — ปรึกษาผู้สอบบัญชีก่อนยื่น

⚠️ ข้อจำกัด: ระบบยังไม่รองรับ:

  • Loss carry forward อัตโนมัติ (ขาดทุนยกมาจากปีก่อน)
  • Add-back ค่าใช้จ่ายต้องห้าม (ม.65 ทวิ) อัตโนมัติ
  • BOI / IBC / RD privilege rates
  • Half-year prepayment credit (ต้องบันทึกเอง)

11A.4 ภ.พ.30 (/tax/vat)

หน้าสรุปภาษีมูลค่าเพิ่มรายเดือน สำหรับร้านที่จดทะเบียน VAT — เลือกช่วงเดือน + ปุ่มพิมพ์ ภ.พ.30 + Card รายเดือน

11A.5 ภ.ง.ด.3/53 — หัก ณ ที่จ่าย (/tax/wht) ⭐ NEW

📍 เส้นทาง: /tax/wht 👤 สิทธิ์: ADMIN, OWNER

สรุปการหัก ณ ที่จ่ายรายเดือน สำหรับยื่น ภ.ง.ด.3 (จ่ายให้บุคคลธรรมดา) และ ภ.ง.ด.53 (จ่ายให้นิติบุคคล)

ใช้ข้อมูลจาก: /expenses ที่กรอก hasWht=true + whtRate + whtPayeeName + whtPayeeTaxId

การจำแนกแบบ:

มี taxId 13 หลักตัวเลขแรกแบบ
ใช่"0"ภ.ง.ด.53 (นิติบุคคล)
ใช่อื่นๆภ.ง.ด.3 (บุคคลธรรมดา)
ไม่มีภ.ง.ด.3 (default)

Workflow:

  1. ไป /tax/wht → เลือก เดือน + ปี + กรองแบบ (ทั้งหมด/ภ.ง.ด.3/ภ.ง.ด.53)
  2. ระบบแสดง:
    • 4 stat cards: จำนวนรายการ / เงินที่จ่าย / ภาษีที่หัก (สีส้มเด่น) / จำนวนผู้รับ unique
    • สรุปตามอัตรา (1% / 3% / 5% / 15%)
    • Tab "ตามผู้รับเงิน" — group by payee + taxId พร้อม badge แบบ
    • Tab "รายการทั้งหมด" — transaction list
  3. กดปุ่ม CSV → ดาวน์โหลด CSV format ที่ใช้กรอก e-Filing ได้
  4. ยื่นที่ https://efiling.rd.go.th ภายในวันที่ 7 ของเดือนถัดไป

💡 เคล็ดลับ: กรอก whtPayeeTaxId ในรูปแบบ 13 หลัก ขีด/ไม่ขีดก็ได้ — ระบบ strip non-digit ก่อนเก็บ

11A.6 ตั้งค่าภาษี (/tax/settings)

หน้าฟอร์มตั้งค่าภาษี (entityType + deduction method + 4-group allowance) — เดิมอยู่ใน /settings ย้ายมาที่นี่เพื่อให้เป็นกลุ่มเดียวกัน

📝 ประวัติการ migration:

  • ก่อน 11 พ.ค. 2569: PIT + VAT อยู่ใน /reports dropdown และ tax settings อยู่ใน /settings
  • หลัง: ทุกอย่างย้ายมาอยู่ใน /tax — URL เก่าจะ redirect อัตโนมัติ (/reports?type=pit/tax/pit)

12. เอกสารพิมพ์ในระบบ

ระบบ MobileHub ออกเอกสารพิมพ์ A4/Thermal ได้ทั้งหมด 12 ประเภท ใช้รูปแบบ design system เดียวกัน (header 2-col + accent color cascade ผ่าน CSS variable + ลายเซ็นมาตรฐาน + ฟอนต์ Kanit). ทุกเอกสารพิมพ์ผ่านเบราว์เซอร์ — ไม่ต้องลง driver พิเศษ

12.0 เลขที่เอกสาร (Document Numbering)

ทุกเอกสารทางการเงินในระบบใช้เลขที่ running serial ต่อเนื่องตลอดปีภาษี ตามประกาศอธิบดีสรรพากร ว.196/2553 (ใบกำกับภาษีต้องมีเลขเรียงต่อเนื่อง)

Format มาตรฐาน: {PREFIX}-{branchCode}-{BEyear}-{seq:04}

ช่องคำอธิบายตัวอย่าง
PREFIXรหัสประเภทเอกสารRC (ใบเสร็จขาย), RCV (รับซ่อม), QUO (เสนอราคา), INV (ใบแจ้งหนี้ซ่อม), RCP (ใบเสร็จซ่อม), SLP (สลิปย่อ), WRT (ใบประกัน), CLM (ใบเคลม)
branchCodeรหัสสาขา (จาก Branch.code)HQ, CM01, BKK01
BEyearปี พ.ศ.2569, 2570
seqลำดับ 4 หลัก0001, 0023, 1547

ตัวอย่าง:

  • RC-HQ-2569-0001 — ใบเสร็จขายใบแรกของสาขา HQ ปี 2569
  • RCV-CM01-2569-0042 — ใบรับซ่อมใบที่ 42 ของสาขาเชียงใหม่ ปี 2569
  • WRT-HQ-2569-0015 — ใบประกันใบที่ 15 ของสาขา HQ ปี 2569

กฎการ reset:

  • Counter reset อัตโนมัติทุก 1 มกราคม (เริ่ม 0001 ใหม่ในปี พ.ศ. ถัดไป)
  • แยก counter ต่อสาขา — สาขา HQ กับ CM01 มีลำดับเลขของตัวเอง ไม่กวนกัน
  • แยก counter ต่อประเภทเอกสารRC กับ RCV คนละ counter

ป้องกัน race condition:

  • ใช้ Postgres INSERT ... ON CONFLICT DO UPDATE RETURNING (atomic upsert) → 2 POS เปิดพร้อมกันไม่ได้เลขซ้ำกันเลย
  • ตาราง DocumentSerial (tenantId + branchId + docType + year พ.ศ.) เก็บ counter ปัจจุบัน

⚠️ ใบเก่าก่อน 12 พ.ค. 2569 ใช้ format เดิม RC-YYYYMMDD-NNNN (ค.ศ. + reset รายวัน) — ระบบยังเก็บไว้ใน DB เหมือนเดิม ไม่ rewrite. ใบใหม่ตั้งแต่ 12 พ.ค. 2569 ใช้ format ใหม่ทั้งหมด

12.1 เอกสารฝั่งขาย-รับซื้อ

เอกสารที่หน้ารูปแบบสีธีม
ใบเสร็จขายสินค้า (POS)/sales (auto-open หลัง checkout)thermal 80mm + A4 toggleเขียว
ใบรับซื้อโทรศัพท์มือสอง/purchase (ปุ่มพิมพ์ในแต่ละ row)A4 + คำรับรอง 5 ข้อ + ลายเซ็น 3 ฝ่าย + ช่องสำเนาบัตร ปชช.ส้ม-แดง (เน้นกฎหมาย)

12.2 เอกสารงานซ่อม (/repair-documents)

เอกสารเมื่อใช้รูปแบบ
ใบรับซ่อม (INTAKE_RECEIPT)ตอนรับเครื่องเข้าซ่อมA4 — แสดงรูปถ่ายเครื่อง + อาการ + คำเตือน "ราคาแจ้งภายหลัง"
ใบเสนอราคา (QUOTATION)หลังตรวจสอบ ก่อนซ่อมA4 — รายการอะไหล่ + ค่าแรง + VAT
ใบเสร็จรับเงิน (RECEIPT)หลังซ่อมเสร็จ ลูกค้ารับเครื่องA4 — items table + totals + payment + signatures
ใบเสร็จเล็ก (SMALL_RECEIPT)สลิปย่อ (POS thermal)thermal 80mm
ใบประกัน (WARRANTY_CARD)ออกพร้อมส่งคืนเครื่องA4 — banner ระยะประกัน + ✓ ความคุ้มครอง / ✗ ข้อยกเว้น

12.3 ใบเครมประกัน (/repair-warranty)

โหมดเมื่อใช้สีธีม
ใบรับเครื่องเข้าเครม (intake)ตอนลูกค้านำเครื่องมาเครม — ออกได้ทุกสถานะของ claimส้ม
ใบส่งคืนหลังเครม (resolution)ตอนเครมเสร็จส่งคืนลูกค้า — ออกได้เฉพาะ status COMPLETEDเขียว

ทั้ง 2 ใบมี: warranty linkbox + days-remaining badge สี dynamic, ลายเซ็น 2-3 ฝ่าย, QC checklist 6 ข้อ (resolution mode)

12.4 สลิปเงินเดือน (Payslip)

📍 หน้า: /payroll (ปุ่ม 🖨️ "พิมพ์สลิปเงินเดือน" ในแถว + ในปุ่ม detail modal) 👤 สิทธิ์: OWNER, ADMIN, MANAGER 🎨 ธีม: cyan (ตรงกับสีแบรนด์ของแอป)

  • Block: header → ข้อมูลพนักงาน → 2-col earnings/deductions → net pay box (สีฟ้าเข้ม + จำนวนเงินเป็นข้อความไทย เช่น "สามหมื่นห้าพันบาทถ้วน") → ลายเซ็น HR + พนักงาน
  • รายการเพิ่ม/หัก ดึงจาก PayrollAdjustment (split อัตโนมัติด้วย isDeduction)
  • รูปแบบ A4 — บนมือถือเลื่อนแนวนอนได้ (ScrollArea scrollbars="xy")
  • Gate การพิมพ์: ปุ่มจะ disabled เมื่อ status = PENDING (ตัวเลขยังเปลี่ยนได้) — ต้องอนุมัติก่อนถึงพิมพ์ได้ (ดูรายละเอียดเพิ่มในหัวข้อ 10.4-10.5)

12.5 ใบสรุปการมาทำงานรายเดือน (Attendance Summary)

📍 หน้า: /attendance (ปุ่ม "ใบสรุปรายเดือน" ใน header) 👤 สิทธิ์: ADMIN, MANAGER

  • เลือกพนักงาน + เดือน + ปี (พ.ศ.) → ดึง /attendance/report API → พิมพ์ A4 1 หน้า
  • Block: header → KPI 5 cards (วันทำงาน/ชั่วโมง/มาสาย/เลิกก่อน/ขาด) → ตาราง 28-31 rows (1 row = 1 วัน) → ลายเซ็น 3 ฝ่าย (พนักงาน/หัวหน้า/HR)
  • เสาร์-อาทิตย์มี bg เทา, สาย/ขาดแสดงสีแดง bold

12.6 ใบเบิก/รับเข้าอะไหล่ (Spare Part Movement)

📍 หน้า: /spare-partsModal "ประวัติการเคลื่อนไหว" (ปุ่มพิมพ์ในแต่ละ transaction row)

โหมดTriggerสีธีม
ใบเบิกอะไหล่ (issue)transaction type = OUT (เบิกใช้กับงานซ่อม)teal
ใบรับสินค้าเข้าคลัง (receive)transaction type = IN (ซื้อมาจาก supplier)indigo
  • Block: header → reference linkbox (issue: REP-xxx + customer + device + IMEI / receive: supplier + ผู้รับเข้า) → items table (1 row) → totals → reason note → inspection checklist 5 ข้อ (receive only) → ลายเซ็น 3 ฝ่าย

12.7 ใบลดหนี้ (Credit Note) — มาตรา 86/10

📍 เปิดได้ที่: เปิดอัตโนมัติหลังกด "ยืนยันคืนเงิน" ใน RefundWizard (§6.6)

สีธีม: แดง (#dc2626) — แสดงการคืนเงิน/เงินไหลออก ฐานทางกฎหมาย: มาตรา 86/10 แห่งประมวลรัษฎากร (ส่วนที่ 10 ใบกำกับภาษี ใบเพิ่มหนี้ ใบลดหนี้)

ใบลดหนี้ออกได้เมื่อ:

  • ผู้ขายเป็น ผู้จดทะเบียน VAT (ถ้าสาขาไม่จด VAT — เอกสารใช้เป็นหลักฐานภายในร้านเท่านั้น ไม่มีผลทางภาษี)
  • เคยออกใบกำกับภาษีไปแล้ว (มี receiptNumber อ้างอิง)
  • เกิดเหตุการณ์ที่เป็นเหตุให้ ภาษีขายลดลง เช่น ลูกค้าคืนสินค้า / สินค้าชำรุด / ตกลงลดราคา

โครงสร้างเอกสาร (compliance ตามมาตรา 86/10):

  1. คำว่า "ใบลดหนี้" — Banner ใหญ่สีแดง gradient + ระบุ "ออกตามมาตรา 86/10"
  2. เลขที่ใบลดหนี้ (CN-xxxxxxxx) + วันที่ออก
  3. อ้างอิงใบกำกับภาษีเดิม: เลขใบ + วันที่เดิม (กรอบแดงเด่น)
  4. ผู้ออก (ผู้ขาย): ชื่อ + ที่อยู่ + เบอร์ + เลขประจำตัวผู้เสียภาษี (จาก branch.taxId, format X-XXXX-XXXXX-XX-X)
  5. ผู้รับ (ผู้ซื้อ): ชื่อ + ที่อยู่ + เบอร์ + เลขประจำตัวผู้เสียภาษี (จาก customer.idCard 13 หลัก)
  6. รายการที่ลดหนี้ — ตาราง: ชื่อสินค้า/IMEI + จำนวน + ราคา/หน่วย + รวม (ค่าลบ)
  7. โครงสร้าง 3-cell บังคับ:
    • มูลค่าเดิม (ก่อนลด)
    • มูลค่าที่ถูกต้อง (หลังลด)
    • ผลต่าง (ยอดที่คืน)
  8. VAT split (ถ้าสาขาจด VAT):
    • มูลค่าผลต่างก่อน VAT
    • VAT 7% ของผลต่าง (ใช้สูตร amount × rate / (100 + rate) สำหรับราคา VAT-inclusive)
    • ยอดเงินที่คืนรวม (กล่องแดงใหญ่เด่น)
  9. วิธีคืนเงิน (เงินสด/โอน/เครดิตร้าน — pill เขียว)
  10. เหตุผลในการออกใบลดหนี้ (กล่องเหลือง + ข้อความที่ user กรอกใน RefundWizard)
  11. ลายเซ็น 2 ฝ่าย: ลูกค้า + ผู้รับคืนสินค้า (พร้อมช่องวันที่)
  12. Legal note (เฉพาะ VAT-registered): "ผู้ซื้อต้องนำใบลดหนี้นี้ไปใช้ภายในเดือนที่ได้รับ" + "เก็บ 5 ปี (paper) / 10 ปี (electronic)"

💡 สำคัญ: ผู้ซื้อ (ลูกค้าที่จด VAT) ต้องนำใบลดหนี้ไปใช้ ภายในเดือนที่ได้รับ เท่านั้น ไม่สามารถใช้ข้ามเดือนได้

⚠️ ถ้าสาขายังไม่จด VAT — ระบบแสดง Alert "ใบลดหนี้นี้ใช้เป็นเอกสารภายในร้านเท่านั้น" ไม่มีผลทางภาษี

12.8 Z Report (ปิดยอดสิ้นวัน)

📍 เปิดได้ที่: ปุ่ม "ปิดยอดวันนี้" มุมขวาบน /sales-history (§6.6)

สีธีม: ฟ้า (#0891b2) + กล่องเงินสดเขียว มาตรฐาน: Retail Z Report (ทั่วโลก) + Thai VAT compliance สำหรับ ภ.พ.30

โครงสร้างเอกสาร (เรียงลำดับการอ่าน):

  1. Banner — "รายงานปิดยอดสิ้นวัน (Z Report)" + ชื่อร้าน + สาขา
  2. Meta strip — เลขที่รายงาน Z-YYYYMMDD-{branchCode} + วันที่ (ภาษาไทย, พ.ศ.)
  3. กล่องเงินสดในลิ้นชัก (คาดหมาย)เด่นที่สุด เพราะนี่คือเหตุผลหลักของการปิดยอด:
    • ตัวเลขใหญ่ 32px สีเขียว
    • Breakdown: เงินสดเข้า − เงินสดคืน = ยอดคาดหมาย
    • Reminder: "นับเงินสดในลิ้นชักจริง แล้วเทียบกับตัวเลขนี้"
  4. 3 KPI cards — บิลที่ใช้งาน / บิลยกเลิก / ครั้งที่คืนเงิน (พร้อมจำนวน + ยอด)
  5. สรุปยอดเงิน — running total style:
    • ยอดขายรวม (รวม VAT)
    • − VAT รวมในราคา (ถ้าจด VAT)
    • − คืนเงินรวม (ถ้ามี)
    • = รายได้สุทธิ (กล่องฟ้าเด่น)
  6. VAT compliance section (เฉพาะสาขาจด VAT) — สำหรับ ภ.พ.30 reconciliation:
    • มูลค่าก่อน VAT (taxable sales)
    • VAT ขาย (Output VAT)
    • − VAT ของยอดคืน (จากใบลดหนี้ในวันนั้น)
    • = VAT สุทธิที่ต้องนำส่ง (ตรงกับยอดที่ใส่ใน ภ.พ.30)
  7. รายรับ — แยกตามวิธีชำระ — ตาราง: เงินสด/โอน/บัตร พร้อมจำนวนบิล + ยอด + subtotal
  8. จ่ายออก — แยกตามวิธีคืนเงิน — ตาราง: เงินสด/โอน/เครดิตร้าน พร้อมจำนวนครั้ง + ยอด (สีส้ม)
  9. ลายเซ็น 2 ฝ่าย: Cashier ผู้ปิดยอด + ผู้จัดการ/ผู้ตรวจสอบ
  10. Footer note — "เก็บ 5 ปี (paper) / 10 ปี (electronic)"

Workflow ปิดร้านมาตรฐาน:

  1. ก่อนปิดร้าน → กด "ปิดยอดวันนี้" บน /sales-history
  2. ตรวจตัวเลขในระบบ (ทุกบิล/ยกเลิก/คืน) ว่าถูกต้อง
  3. นับเงินสดจริงในลิ้นชัก
  4. เทียบกับ "ยอดเงินสดในลิ้นชัก (คาดหมาย)" สีเขียว
  5. ถ้าตรง → กดพิมพ์ → ลายเซ็น Cashier → เก็บเอกสาร
  6. ถ้าไม่ตรง → ตรวจหาสาเหตุก่อนเลิกงาน (อาจมีบิลยังไม่ปิด, ใบ refund หาย, ฯลฯ)

💡 ภ.พ.30 friendly: VAT section ของ Z Report ตรงกับ map ใน /reports VAT (§11) — ใช้คู่กันได้ตอนยื่นภาษีรายเดือน

⚠️ Z Report ดูย้อนหลังได้ — เลือกวันที่ที่ DatePicker แล้วเรียกข้อมูลใหม่ (เก็บถาวรในระบบ)

12.9 รายงาน Export Excel (/reports)

นอกเหนือจากเอกสารพิมพ์ ระบบยัง export รายงานเป็น Excel ได้ 6 ประเภท:

  • รายงานยอดขาย / การซ่อม / การรับซื้อ / สินค้าคงเหลือ / สรุปการเงิน / ภาษี VAT

💡 เคล็ดลับการพิมพ์

  • ตั้งค่า browser ก่อนพิมพ์ครั้งแรก: Chrome/Edge → ปิด "Headers and footers" + เปิด "Background graphics" (เพื่อให้ accent color + กล่องสีพิมพ์ออก)
  • Thermal printer 80mm (สำหรับ POS): ตั้ง paper size = "80mm × auto" + Margin = "None"
  • A4 documents: ตั้ง paper size = A4, Margin = Default (ระบบมี @page margin: 12mm ในตัวเอง)
  • PDF export: ทุกเอกสารกด "Save as PDF" ใน print dialog ได้

🏷️ White Label (ลบโลโก้ MobileHub) — Enterprise

📦 แพ็คเกจ: Enterprise เท่านั้น

ในแพ็คเกจ Enterprise ระบบจะ ลบเครื่องหมาย "MobileHub" / "AJ Software Dev." อัตโนมัติ จาก:

  • Sidebar footer ("Powered by AJ Software Dev." → ซ่อน)
  • ใบเสร็จขายสินค้า (POS) — A4 footer ลบ "เอกสารนี้พิมพ์โดยระบบ MobileHub POS"
  • ใบรับซื้อโทรศัพท์ — footer เหลือแค่เลขเอกสาร (ลบ "พิมพ์โดยระบบ MobileHub")

→ เอกสารและหน้าจอทั้งหมดจะเหมือน "ระบบของร้านคุณเอง" ไม่มี branding ของ MobileHub ปรากฏให้ลูกค้าเห็น

💡 เหมาะกับธุรกิจขนาดใหญ่ที่ต้องการแบรนด์ดิ้งของตัวเอง (เช่น Aj Mobile Group ใช้ pos.ajmobile.com แทน mobilehub.ajsoftwaredev.com)

13. Portal (Tenant Self-Service)

12.1 Support Tickets

📍 หน้า: /portal/tickets 👤 สิทธิ์: ทุก Role

วัตถุประสงค์: ยื่น Ticket เพื่อขอความช่วยเหลือหรือรายงานปัญหาไปยังทีมงาน MobileHub

ขั้นตอนสร้าง Ticket:

  1. กดปุ่ม "+ สร้าง Ticket ใหม่"
  2. กรอก:
    • หัวข้อ — สรุปปัญหาสั้นๆ
    • ประเภท — Bug Report, Feature Request, ขอความช่วยเหลือ
    • ระดับความสำคัญ — LOW, MEDIUM, HIGH, CRITICAL
    • รายละเอียด — อธิบายปัญหาอย่างละเอียด
  3. กดปุ่ม "ส่ง Ticket"

สถานะ Ticket:

สถานะสีความหมาย
OPENน้ำเงินรอทีมงานรับเรื่อง
IN_PROGRESSเหลืองทีมงานกำลังดำเนินการ
RESOLVEDเขียวแก้ไขแล้ว
CLOSEDเทาปิด Ticket

12.2 ประกาศ

📍 หน้า: /portal/announcements 👤 สิทธิ์: ทุก Role

วัตถุประสงค์: รับข่าวสารประกาศจากทีมงาน MobileHub — อัปเดต, การบำรุงรักษา, โปรโมชั่น

ฟีเจอร์:

  • ดูประกาศล่าสุดจากทีมงาน
  • กรองตามประเภทประกาศ
  • ทำเครื่องหมายว่า "อ่านแล้ว"
  • ประกาศสำคัญแสดงไฮไลท์สีแดง

12.3 Billing

📍 หน้า: /portal/billing 👤 สิทธิ์: OWNER, ADMIN

วัตถุประสงค์: ดูสถานะ Subscription ปัจจุบัน ประวัติการชำระเงิน ดาวน์โหลดใบเสร็จ

ข้อมูลที่แสดง:

  • แพ็กเกจปัจจุบัน (Plan Name)
  • วันหมดอายุ Subscription
  • Storage ที่ใช้/ที่มี
  • จำนวนผู้ใช้งาน/ที่อนุญาต
  • ประวัติ Invoice และการชำระเงิน

ขั้นตอนชำระค่าบริการ:

  1. คลิกที่ Invoice ที่ต้องการชำระ
  2. เลือกวิธีชำระ
  3. อัปโหลด Slip การโอนเงิน
  4. ระบบส่งเรื่องให้ Admin ตรวจสอบ

สถานะการชำระ:

สถานะคำอธิบาย
PENDINGรอชำระเงิน
SLIP_UPLOADEDอัปโหลด Slip แล้ว รอตรวจสอบ
APPROVEDยืนยันแล้ว
REJECTEDปฏิเสธ (Slip ไม่ถูกต้อง)
REFUNDEDคืนเงินแล้ว

การแจ้งเตือน (real-time bell + Web Push):

เมื่อ admin ตรวจสลิปแล้ว — ระบบจะส่ง notification ไปที่ OWNER + ADMIN ของ tenant ทันที (Socket.IO real-time + Web Push ถ้า subscribe):

เหตุการณ์ข้อความที่ tenant ได้รับ
✅ Admin อนุมัติ"การชำระเงินได้รับการอนุมัติ — แพ็คเกจ X ฿Y พร้อมใช้งาน"
⚠️ Admin ปฏิเสธ"สลิปไม่ผ่านการตรวจสอบ — จำนวน ฿Y — เหตุผล + กรุณาอัพโหลดใหม่"
🤖 OCR auto-verify ผ่านtoast "✓ ตรวจสลิปสำเร็จ — แพ็คเกจของคุณพร้อมใช้งาน" + status APPROVED ทันที
🤖 OCR auto-verify ไม่ผ่านtoast "อัพโหลดสำเร็จ แต่ตรวจอัตโนมัติไม่ผ่าน (เหตุผล) — รอแอดมินตรวจ"

คลิก notification จาก bell → deep link ไป /portal/billing ดูสถานะใหม่ + เหตุผลปฏิเสธ (ถ้ามี)

OCR Auto-verify (admin ตั้งค่าได้ที่ /admin/settings → Slip Verify):

ถ้า admin เปิดโหมด ocr_auto ระบบจะส่งสลิปไป EasySlip API ตรวจอัตโนมัติ — ถ้า:

  • ✓ amount ตรงกับ payment.amount + receiver account ตรง → APPROVED ทันที
  • ✗ ไม่ตรง → status SLIP_UPLOADED + admin เห็นเหตุผลใน reviewNote เช่น OCR easyslip: amount_mismatch (slip ฿657.43 ≠ expected ฿1499) แล้วตัดสินใจ approve/reject เอง

12.4 อัปเกรดแพ็กเกจ

📍 หน้า: /portal/upgrade 👤 สิทธิ์: OWNER, ADMIN

วัตถุประสงค์: ดูและเปรียบเทียบแพ็กเกจ เลือกอัปเกรดหรือดาวน์เกรด

แพ็กเกจที่ให้บริการ:

แพ็กเกจผู้ใช้BranchesStorageราคา
STARTER5 คน1 สาขา1 GBติดต่อ
PROFESSIONAL20 คน5 สาขา10 GBติดต่อ
ENTERPRISEไม่จำกัดไม่จำกัด100 GBติดต่อ

14. การจัดการระบบ (Admin)

14.1 สาขา

📍 หน้า: /branches 👤 สิทธิ์: OWNER, ADMIN

วัตถุประสงค์: เพิ่ม แก้ไข จัดการสาขาของร้าน

ขั้นตอนเพิ่มสาขาใหม่:

  1. กดปุ่ม "+ เพิ่มสาขา"
  2. กรอกข้อมูล:
ฟิลด์คำอธิบายจำเป็น
ชื่อสาขาชื่อสาขา (เช่น HQ, สาขาลาดพร้าว)
ที่อยู่ที่อยู่สาขา
เบอร์โทรเบอร์ติดต่อสาขา
อีเมลอีเมลสาขา
เป็นสาขาหลักตั้งเป็น HQ
  1. กดปุ่ม "บันทึก"

⚠️ หมายเหตุ: จำนวนสาขาที่สร้างได้ขึ้นอยู่กับแพ็กเกจ Subscription

14.2 ผู้ใช้งาน

📍 หน้า: /users 👤 สิทธิ์: OWNER, ADMIN

วัตถุประสงค์: เพิ่ม แก้ไข จัดการบัญชีผู้ใช้งานและกำหนด Role

ขั้นตอนเพิ่มผู้ใช้ใหม่:

  1. กดปุ่ม "+ เพิ่มผู้ใช้"
  2. กรอกข้อมูล:
ฟิลด์คำอธิบายจำเป็น
อีเมลอีเมลสำหรับ Login
ชื่อชื่อพนักงาน
นามสกุลนามสกุลพนักงาน
เบอร์โทรเบอร์ติดต่อ
Roleเลือกได้หลาย Role
สาขาสาขาประจำ
รหัสผ่านรหัสผ่านเริ่มต้น
อัตราค่าแรง/ชั่วโมงสำหรับคำนวณเงินเดือน
  1. ระบบสร้าง QR Code สำหรับลงเวลาอัตโนมัติ

การจัดการ Role:

  • แต่ละ User มีได้หลาย Role (MultiSelect)
  • ตัวอย่าง: พนักงานคนหนึ่งอาจมีทั้ง SALES และ TECHNICIAN (= SALESTECH)

QR Code พนักงาน:

  • ระบบสร้าง QR Code unique ให้ทุก User
  • กดปุ่ม "ดู QR" หรือ "พิมพ์ QR"
  • ใช้สำหรับสแกนลงเวลาที่ Kiosk

เปิด/ปิดบัญชี:

  • Toggle Switch เพื่อปิดใช้งานชั่วคราว
  • ผู้ใช้ที่ปิดใช้งานจะ Login ไม่ได้

14.3 ข้อมูลหลัก (Master Data)

📍 หน้า: /masters 👤 สิทธิ์: OWNER, ADMIN, MANAGER

วัตถุประสงค์: จัดการข้อมูลอ้างอิงที่ใช้ทั่วทั้งระบบ เช่น ยี่ห้อ รุ่น สี ประเภทการซ่อม ฯลฯ

รายการ Master Data:

หัวข้อURLคำอธิบาย
ยี่ห้อสินค้า/masters/brandsApple, Samsung, OPPO ฯลฯ
รุ่นสินค้า/masters/modelsiPhone 15, Galaxy S24 ฯลฯ
สี/masters/colorsดำ, ขาว, ทอง ฯลฯ (พร้อม Color Picker)
ความจุ/masters/storages64GB, 128GB, 256GB, 512GB ฯลฯ
ตำแหน่งจัดเก็บ/masters/storage-locationsShelf A1, ตู้ B ฯลฯ
หมวดหมู่อะไหล่/masters/spare-part-categoriesจอ, แบตเตอรี่, ชาร์จพอร์ต ฯลฯ
ประเภทการซ่อม/masters/repair-typesเปลี่ยนจอ, เปลี่ยนแบต, ซ่อมบอร์ด ฯลฯ
สถานะการซ่อม/masters/repair-statusesRECEIVED, IN_PROGRESS, COMPLETED ฯลฯ
สภาพสินค้า/masters/product-conditionsNEW, LIKE_NEW, เกรด A, B, C, D (ตำหนิเยอะ ราคาถูก)
สถานะสินค้า/masters/product-statusesIN_STOCK, RESERVED, SOLD
สถานะเงินเดือน/masters/payroll-statusesPENDING, APPROVED, PAID
สถานะประกัน/masters/warranty-statusesACTIVE, EXPIRED, CLAIMED

ขั้นตอนเพิ่ม Master Data:

  1. คลิกที่ Card ของ Master Data ที่ต้องการ
  2. กดปุ่ม "+ เพิ่ม"
  3. กรอกชื่อและรายละเอียด
  4. กดปุ่ม "บันทึก"

⚠️ หมายเหตุ: ข้อมูลหลักเป็น Tenant-specific — แต่ละร้านมีรายการของตัวเอง ไม่แชร์กับร้านอื่น

14.4 ตั้งค่า

📍 หน้า: /settings 👤 สิทธิ์: OWNER, ADMIN

วัตถุประสงค์: ตั้งค่าข้อมูลร้านค้า, เป้าหมายยอดขาย, PromptPay, VAT

ส่วนที่ตั้งค่าได้:

ส่วนฟิลด์
ข้อมูลร้านชื่อร้าน, ที่อยู่, เบอร์โทร, อีเมล, Logo
ภาษีจด VAT หรือไม่ (Toggle), อัตรา VAT (ค่าเริ่มต้น 7%)
PromptPayเบอร์โทร PromptPay สำหรับสร้าง QR
เลขประจำตัวผู้เสียภาษีTax ID
เป้าหมายเป้าหมายยอดขายต่อเดือน (บาท)
เป้าหมายซ่อมเป้าหมายจำนวนงานซ่อมต่อเดือน

💡 เคล็ดลับ: ตั้งค่า PromptPay Phone ก่อนเริ่มขาย เพื่อให้ระบบสร้าง QR Code ได้อัตโนมัติ

14.5 Audit Log

📍 หน้า: /audit-logs 👤 สิทธิ์: OWNER, ADMIN

วัตถุประสงค์: ดูบันทึกกิจกรรมทั้งหมดในระบบ — ใครทำอะไร เมื่อไหร่

ข้อมูลที่บันทึก:

ฟิลด์ตัวอย่าง
ผู้กระทำadmin@shop.com
การกระทำCREATE_PRODUCT, UPDATE_REPAIR, DELETE_USER
โมดูลProduct, Repair, User, Sale
รายละเอียดข้อมูลก่อน-หลังการเปลี่ยนแปลง
เวลาวัน-เวลาตาม Timezone Asia/Bangkok
IP AddressIP ของผู้ใช้

การใช้งาน:

  • กรองตามผู้ใช้, การกระทำ, โมดูล
  • ค้นหาด้วย keyword
  • Export เป็น CSV ได้

15. การแจ้งเตือน

📍 ไอคอน: Bell 🔔 ด้านบนขวาของหน้าจอ 👤 สิทธิ์: ทุก Role

วัตถุประสงค์: รับการแจ้งเตือนแบบ Real-time สำหรับเหตุการณ์สำคัญในระบบ

ประเภทการแจ้งเตือน:

ประเภทผู้รับตัวอย่าง
งานซ่อมใหม่ADMIN, MANAGER, OWNER"รับเครื่องซ่อมใหม่: iPhone 15 ลูกค้า สมชาย"
สถานะซ่อมเปลี่ยนผู้มอบหมายงาน"งานซ่อม #123 เสร็จแล้ว"
ยอดขายใหม่ADMIN, MANAGER"ขายสินค้า: Samsung S24 ฿25,000"
เงินเดือนรออนุมัติOWNER, ADMIN"มีเงินเดือนรออนุมัติ 5 รายการ"
Stock ต่ำADMIN, MANAGER"อะไหล่ 'แบตเตอรี่ iPhone 13' เหลือ 2 ชิ้น"
ประกันใกล้หมดอายุADMIN, MANAGER"ประกัน iPhone 14 ของ สมหญิง จะหมดใน 7 วัน"
ประกาศจากระบบทุก Role"📢 ประกาศใหม่: กำหนดอัพเดท..." (จากทีมงาน MobileHub)

วิธีใช้งาน:

  1. คลิกไอคอน Bell มุมบนขวา (Bell ringing 🔔 เมื่อมี unread)
  2. ดูรายการแจ้งเตือน — items ยังไม่อ่านมี เส้นขอบซ้ายสีฟ้า + ตัวหนา
  3. คลิกแต่ละรายการ → mark-as-read + navigate ไปหน้าที่เกี่ยวข้อง (เช่น คลิก "ประกาศใหม่" → ไปหน้า /portal/announcements)
  4. Header actions (3 ปุ่มมุมขวาบนของ dropdown):
    • อ่านทั้งหมด — mark-as-read ทุก unread (แสดงเฉพาะตอนมี unread)
    • 🗑 ลบที่อ่านแล้ว — ลบเฉพาะ items ที่ isRead=true (แสดงเมื่อมี read item)
    • รีเฟรช — โหลด list + count ใหม่จาก server
  5. Per-item × delete — กดเครื่องหมาย × ที่ขวาสุดของแต่ละ item → ลบทันที (กัน accidentally — มี stopPropagation ไม่ให้ navigate)
  6. Items ที่อ่านแล้วแสดง stamp "✓ อ่านแล้ว" สีเทาที่แถวเวลา

💡 เคล็ดลับ: การแจ้งเตือนทำงานแบบ Real-time ผ่าน Socket.IO และบันทึกลง Database เพื่อดูย้อนหลังได้

15.1 แจ้งเตือนทันที แม้ปิดเว็บอยู่ (Push Notifications)

📍 เปิดได้ที่: Banner ที่ Dashboard (ครั้งแรก) หรือหน้า Profile → การแจ้งเตือน Push 👤 สิทธิ์: ทุกแพ็คเกจ STARTER+ (รวมทั้ง Super Admin)

วัตถุประสงค์: รับแจ้งเตือนเหตุการณ์สำคัญทันที แม้ปิดแท็บหรือปิดเบราว์เซอร์อยู่ — เด้งเหมือน notification ของ LINE/Facebook

อุปกรณ์ที่รองรับ:

  • Desktop — Chrome / Edge / Firefox / Safari (Mac)
  • Android — Chrome / Edge / Firefox
  • iPhone / iPad — Safari 16.4 ขึ้นไป แต่ต้องติดตั้งเป็นแอป (Add to Home Screen) ก่อน

วิธีเปิดใช้งาน:

  1. เข้า Dashboard ครั้งแรก → จะเห็น Banner สีฟ้า ด้านบนพร้อมไอคอนระฆัง
  2. คลิกปุ่ม "เปิดการแจ้งเตือน"
  3. เบราว์เซอร์ขึ้นถาม "Allow notifications?" → กด Allow
  4. เสร็จ — ทดลองได้โดยปิดแท็บแล้วให้เพื่อนสร้างงานซ่อมใหม่ (จะเด้งบนเครื่องคุณ)

สำหรับ iPhone / iPad:

  1. เปิดเว็บใน Safari → กดปุ่ม Share (ลูกศรขึ้น)
  2. เลื่อนหา "Add to Home Screen" → กด Add
  3. เปิดแอปจากไอคอนบน Home Screen (ไม่ใช่จาก Safari)
  4. Login → เปิด Push Notifications ตามขั้นตอนปกติ

เปิด-ปิดเองได้ตลอดเวลา:

ไปที่หน้า Profile → การ์ด "การแจ้งเตือน Push" → เลื่อน Switch เปิด/ปิด

กรณี blocked:

ถ้าเผลอกด "Block" → คลิกไอคอน 🔒 ข้างซ้ายของ URL ในเบราว์เซอร์ → การตั้งค่าไซต์ → การแจ้งเตือน → Allow → รีเฟรชหน้า

Multi-device:

Login จาก 3 เครื่อง (เช่น Desktop ที่ร้าน + มือถือคุณ + แท็บเล็ตช่าง) แล้วเปิด Push ทั้ง 3 เครื่อง — ระบบจะส่งแจ้งเตือนทุกเครื่องพร้อมกัน

💡 เคล็ดลับ: Push notifications ทำงานคู่กับ Bell ในระบบ — ถ้าเปิดเว็บอยู่จะได้ทั้ง bell + push (อาจซ้อนกัน), ถ้าปิดเว็บได้แค่ push. ระบบใช้ tag-based grouping ทำให้ notification เหตุการณ์เดียวกันรวมเป็นรายการเดียว ไม่รก

15.2 ติดตั้งเป็นแอป (PWA Install)

📍 เปิดได้ที่: Banner สีฟ้าด้านล่างจอใน Dashboard (เด้งเองตอน browser พร้อม) หรือเมนู "ติดตั้งแอป" ใน Chrome 👤 สิทธิ์: ทุก Role

วัตถุประสงค์: ติดตั้ง MobileHub เป็นแอปบน Home Screen / Desktop เพื่อให้:

  • เปิดเร็วเหมือนแอปจริง (ไม่ต้องเปิดเบราว์เซอร์)
  • มีไอคอนแยกบนหน้าจอ
  • รับ Push Notifications ได้แม้ปิดเว็บ
  • ใช้ Shortcut ลัดเข้าฟีเจอร์หลัก (POS / รับเครื่อง / งานช่าง / ติดตามซ่อม)

Banner ที่เด้งเอง — Chrome / Edge / Android:

หลังเปิด Dashboard ใช้งาน 2-3 นาที จะเห็น Paper สีฟ้า fixed ด้านล่างจอ ประกอบด้วย:

  • ไอคอนระบบ (gradient ฟ้า-เขียว) + หัวข้อ "ติดตั้งเป็นแอป"
  • คำอธิบาย: "ติดตั้ง MobileHub บนมือถือ เปิดเร็วเหมือนแอป และรับการแจ้งเตือน"
  • ปุ่ม "ติดตั้งเลย" — เปิด install dialog ของเบราว์เซอร์ → ยืนยัน → ติดตั้งทันที
  • ปุ่ม "ไว้ก่อน" หรือ × ปิด — ซ่อน Banner 24 ชั่วโมง (วันถัดไปเด้งใหม่)

iPhone / iPad — ติดตั้งผ่าน Safari:

ปุ่ม "ติดตั้งเลย" จะเปลี่ยนเป็น "ดูวิธีติดตั้ง" เมื่อตรวจพบว่าเปิดผ่าน Safari → กดเพื่อเปิด Modal คำแนะนำ 3 ขั้นตอน:

  1. กดปุ่ม Share ที่แถบล่างของ Safari (รูปสี่เหลี่ยม + ลูกศรชี้ขึ้น)
  2. เลื่อนหา "Add to Home Screen" → กด Add
  3. กด "เพิ่ม" ที่มุมขวาบน → ไอคอน MobileHub ปรากฏบนหน้าโฮม

⚠️ iOS ต้องใช้ Safari เท่านั้น ไม่รองรับ Chrome/Firefox บน iOS (ข้อจำกัดของ Apple)

Shortcuts บน Home Screen (Android / iOS):

หลังติดตั้งแล้ว — กดค้างที่ไอคอน MobileHub บน Home Screen → จะเห็น 4 ทางลัด:

  • 🛒 POS → เปิด /sales ขายสินค้าทันที
  • 🔧 รับซ่อม → เปิด /repair-intake รับเครื่อง
  • 🔨 งานช่าง → เปิด /technician-repairs ดูงานที่มอบหมาย
  • 📋 ติดตาม → เปิด /track ค้นหาสถานะใบรับซ่อม

ตอนติดตั้งแล้ว:

  • เปิดจากไอคอนบน Home Screen → จะเห็นเป็นแอปเต็มจอ (ไม่มี URL bar)
  • Banner ติดตั้งจะหยุดเด้งอัตโนมัติ (ตรวจจาก display-mode: standalone)
  • iOS user ต้องเปิดจากไอคอนแอป (ไม่ใช่ Safari) ถึงจะรับ Push Notifications ได้

ถอนการติดตั้ง:

  • Android / Desktop Chrome / Edge — กดค้างที่ไอคอน → "Uninstall app" / "Remove from Chrome"
  • iOS — กดค้างที่ไอคอน → "Remove App" → "Delete App"

💡 เคล็ดลับ: ติดตั้งบนหลายเครื่องได้ — ที่ร้าน 1, ที่บ้าน 1, มือถือ 1 — ใช้บัญชีเดียวกัน Login จะเข้าถึงข้อมูลเดียวกันทุกเครื่อง

16. Multi-Tenant และ Multi-Branch

16.1 Tenant Isolation

MobileHub ใช้สถาปัตยกรรม Multi-Tenant SaaS ที่ข้อมูลของแต่ละร้านถูกแยกกันอย่างสมบูรณ์ (Tenant Isolation)

หลักการสำคัญ:

  • ข้อมูลทุกประเภทมี tenantId กำกับ
  • ผู้ใช้งานไม่สามารถเข้าถึงข้อมูลของ Tenant อื่นได้
  • Unique Constraint เป็นแบบ Compound: เช่น (tenantId, username) ไม่ใช่แค่ username
  • JWT Token บรรจุ tenantId เพื่อตรวจสอบทุก Request

สิ่งที่แยกกันตาม Tenant:

  • ลูกค้า, สินค้า, การขาย, งานซ่อม, อะไหล่
  • ผู้ใช้งาน, สาขา
  • Master Data (ยี่ห้อ, รุ่น, สี ฯลฯ)
  • ตั้งค่าร้าน, Subscription

16.2 Branch Selector

ตำแหน่ง: Header ด้านบนของหน้า (ทุกหน้า)

วัตถุประสงค์: เลือกสาขาที่ต้องการดูข้อมูล

วิธีใช้:

  1. คลิก Dropdown Branch ด้านบน
  2. เลือกสาขาที่ต้องการ — หรือเลือก "ทุกสาขา" (📦 Pro+) เพื่อดู aggregate
  3. ข้อมูลทั่วทั้งระบบกรองตามสาขาที่เลือกอัตโนมัติ

option "ทุกสาขา" (Multi-Branch Dashboard) — Pro+:

📦 แพ็คเกจ: Professional หรือ Enterprise

  • เงื่อนไขแสดง option นี้: ต้องมีฟีเจอร์ MULTI_BRANCH_DASHBOARD และ มีสาขา ≥ 2 (สาขาเดียวจะไม่เห็นเพราะ redundant)
  • มี badge "รวม" สีฟ้าเพื่อแยกออกจากสาขาทั่วไป
  • เมื่อเลือก "ทุกสาขา" → Dashboard / Reports / etc. แสดงข้อมูลรวมของ tenant ทั้งหมด

💡 STARTER ฿599 มีแค่ 1 สาขา อยู่แล้ว — option นี้จึงเป็นของ Pro/Enterprise ที่มีหลายสาขาเท่านั้น

หมายเหตุ:

  • OWNER/ADMIN เห็นทุกสาขา
  • พนักงานทั่วไปเห็นเฉพาะสาขาที่ตัวเองสังกัด
  • บางรายงานสามารถ "รวมทุกสาขา" ได้

17. ภาคผนวก

17.1 API Endpoints หลัก

Prefix: /api/v1

ModuleEndpointMethodคำอธิบาย
Auth/auth/loginPOSTเข้าสู่ระบบ
Auth/auth/registerPOSTสมัครใช้งาน
Auth/auth/verify-emailPOSTยืนยัน OTP
Products/productsGET/POSTดู/เพิ่มสินค้า
Sales/salesGET/POSTดู/สร้างการขาย
Repairs/repairsGET/POSTดู/สร้างงานซ่อม
Customers/customersGET/POSTดู/เพิ่มลูกค้า
Payroll/payrollGET/POSTดู/คำนวณเงินเดือน
Expenses/expensesGET/POST/PUT/DELETEดู/บันทึก/แก้ไข/ลบค่าใช้จ่ายดำเนินงาน
Expenses/expenses/summary/by-categoryGETสรุป expense ตามหมวด (สำหรับ chart)
Shift/shift/currentGETดูกะที่เปิดอยู่ของ user
Shift/shiftGETประวัติกะ (admin/manager: ทั้งสาขา; cashier: ของตัวเอง)
Shift/shift/openPOSTเปิดกะใหม่ — body: openingFloat
Shift/shift/:id/live-totalsGETpreview totals ของกะ OPEN ก่อนปิด
Shift/shift/:id/closePOSTปิดกะ — body: actualCash + varianceReason
POS/sales/preflight?branchId=...GETเช็คว่า user ขายได้ไหม — returns {shiftRequired, hasOpenShift, canSell, ...}
Tax CIT/reports/cit?period=H1|FULL&year=YYYYGETคำนวณภาษีนิติบุคคล (CORPORATION only)
Tax WHT/reports/wht?year=YYYY&month=MMGETสรุปหัก ณ ที่จ่าย — group by payee + Export CSV
Suppliers/suppliersGET/POST/PUT/DELETEดู/เพิ่ม/แก้/ลบผู้จัดหา
Reorders/reordersGET/POSTดู/สร้างคำสั่งซื้ออะไหล่
Reorders/reorders/low-stockGETอะไหล่ที่ต่ำกว่า min stock + suggestedQty
Reorders/reorders/:id/send|receive|cancelPOSTส่งคำสั่ง/รับเข้า/ยกเลิก
Stock Count/stock-countGET/POSTดู/เริ่มรอบนับ
Stock Count/stock-count/:id/items/:itemIdPUTบันทึก countedQty ของ item
Stock Count/stock-count/:id/completePOSTปิดรอบนับ + คำนวณ totals
Stock Transfer/stock-transferGET/POSTดู/ขอโอน
Stock Transfer/stock-transfer/:id/approve|receive|cancelPOSTอนุมัติ + ส่ง/รับเข้า/ยกเลิก
Sales Invoice (B2B)/sales-invoicesGET/POSTดู/ออก invoice — body: customerId + items + paymentTerms
Sales Invoice (B2B)/sales-invoices/:id/paymentPOSTบันทึกรับเงิน — body: amount + paymentMethod
Sales Invoice (B2B)/sales-invoices/:id/cancelPOSTยกเลิก invoice (ถ้ายังไม่ PAID)
Refunds/sales/refunds/listGETlist refund ทั้งหมด — filter date/method/search
Reports/reports/:typeGETดูรายงาน
Dashboard/dashboard/statsGETสถิติ Dashboard
Public Tracking/public/repairs/track/:slug/:repairIdGETติดตามสถานะ (ไม่ต้อง auth, masked PII)
Public Tracking/public/repairs/track/:slug/:repairId/verifyPOSTยืนยันด้วย 4 ตัวท้ายเบอร์ → full info
Public Tracking/public/repairs/lookup?code=GETค้นด้วยเลขเดียว ข้าม tenant (Kerry-style) → redirect
Public Tracking/public/tenants/search?q=GETautocomplete ชื่อร้าน (deprecated — เหลือไว้สำหรับ Phase 2)

17.2 Tech Stack

ส่วนเทคโนโลยีเวอร์ชัน
FrontendNext.js16
FrontendReact19
FrontendMantine UIv8.3
FrontendZustandState Management
FrontendSocket.IO ClientReal-time
BackendFastifyNode.js Framework
BackendPrisma ORMPostgreSQL Client
DatabasePostgreSQL
Real-timeSocket.IO
AuthJWT24h tenant, 12h admin
File UploadFastify Multipartสูงสุด 5MB
FontKanitThai Font
TimezoneAsia/Bangkokdayjs

17.3 Deployment

Docker Compose

ไฟล์: docker-compose.yml (root)

# Start production
docker-compose up -d

# View logs
docker-compose logs -f

Services:

  • backend — Fastify API (port 3001)
  • frontend — Next.js App (port 3000)
  • postgres — PostgreSQL Database
  • nginx — Reverse Proxy (port 80/443)

PM2 (Node.js Process Manager)

# Backend
cd backend
pm2 start ecosystem.config.js

# Frontend
cd frontend
pm2 start ecosystem.config.js

Config:

  • backend/ecosystem.config.js — Cluster mode
  • frontend/ecosystem.config.js — Cluster mode

Environment Variables

Backend (backend/.env):

DATABASE_URL=postgresql://...
JWT_SECRET=your-secret-key
PORT=3001
ALLOWED_ORIGINS=https://mobilehub.ajsoftwaredev.com
UPLOAD_DIR=/app/uploads

Frontend (.env.production):

NEXT_PUBLIC_API_URL=https://api.mobilehub.ajsoftwaredev.com
NEXT_PUBLIC_SOCKET_URL=wss://api.mobilehub.ajsoftwaredev.com

17.4 Backup & Restore

สร้าง Backup

💡 หมายเหตุ: การ backup จัดการโดยทีมสนับสนุนระบบ (Super Admin) สามารถติดต่อผ่าน Support Ticket ได้

ผ่าน Command Line (สำหรับผู้ดูแลระบบที่มีสิทธิ์ SSH):

cd /opt/mobilehub
bash scripts/backup.sh

Restore จาก Backup

# Decrypt backup
openssl enc -d -aes-256-cbc -in backup.sql.gz.enc -out backup.sql.gz

# Decompress
gunzip backup.sql.gz

# Restore to PostgreSQL
psql -U mobilehub -d mobilehub_db < backup.sql

⚠️ คำเตือน: ก่อน Restore ต้องหยุดระบบก่อน และ Backup ใช้ Encryption Salt จาก BACKUP_ENCRYPTION_SALT ใน .env

17.5 Security Rules (สรุปสำหรับผู้ดูแล)

กฎรายละเอียด
JWT TokenTenant: 24h, Admin: 12h
OTPHash ด้วย SHA-256 + สร้างด้วย crypto.randomInt
CORSProduction ห้าม Wildcard (*)
Body Limitสูงสุด 1MB (ไฟล์ Upload 5MB แยก)
Pagination Capสูงสุด 100 รายการต่อหน้า
Rate Limit100 req/min (global), 10/min (auth), 5/min (register)
Upload PathValidate branchId + path.resolve check
Admin Authใช้ adminToken แยกจาก Tenant Token
Socket.IOJWT Auth ก่อน connect, emit เฉพาะ Tenant Room
Mass AssignmentWhitelist fields ก่อน Prisma update
Error Responseไม่ expose error.message ใน 500 response

17.6 การแก้ปัญหาเบื้องต้น

ปัญหาสาเหตุวิธีแก้
Login ไม่ได้Token หมดอายุออกจากระบบแล้วเข้าใหม่
ข้อมูลไม่แสดงBranch ไม่ถูกเปลี่ยน Branch ใน Selector
QR Kiosk ไม่ทำงานCamera Permissionอนุญาตกล้องในเบราว์เซอร์
PromptPay QR ว่างยังไม่ได้ตั้งค่าเบอร์ตั้งค่าใน Settings → PromptPay Phone
Export Excel ช้าข้อมูลมากลดช่วงวันที่
Notification ไม่มาSocket.IO disconnectรีเฟรชหน้า
Upload ไม่ได้ไฟล์ใหญ่เกินขนาดสูงสุด 5MB ต่อไฟล์
หน้าขาว (Error)JavaScript ErrorF5 หรือ Clear Cache

คู่มือนี้จัดทำสำหรับ MobileHub v2 เวอร์ชัน 2.0 อัปเดตล่าสุด: 27 เมษายน 2569 สอบถามเพิ่มเติม: support@mobilehub.ajsoftwaredev.com

MobileHub v2.0 | คู่มือการใช้งาน | © 2026 AJ Software Dev.

ดาวน์โหลด PDF