ข้ามไปที่เนื้อหา

แผน Q2 — roots_hemms_spare_parts (Final 1.0)

เวอร์ชันแผน: Final 1.1 — Q2.1–Q2.8 commit แล้ว 2026-05-22 อนุมัติ: 2026-05-22 Module ID: roots_hemms_spare_parts Layer: 3 (เลนส์โรงพยาบาล) — ห่อหุ้มโมดูล OCA Layer 2 maintenance_stock สถานะ: Q2.1–Q2.8 ✅ commit แล้ว | Q2.9–Q2.11 ค้างอยู่

0. บทสรุปผู้บริหาร

สิ่งที่เราสร้าง: โมดูลอะไหล่สไตล์โรงพยาบาลบนฐานของ OCA maintenance_stock ซึ่ง (a) ให้ maintenance.equipment แต่ละตัวมี เทมเพลตอะไหล่ที่กรองได้, (b) สร้างร่าง stock.picking อัตโนมัติ เมื่อ PM cron สร้างคำขอ, และ © ให้ช่างเทคนิคมีมุมมองเฉพาะ "My Open Requests" เพื่อติดตาม picking ที่ค้างอยู่ของตน พร้อม เลข Stock Request แบบรันนิ่ง

ทำไม: OCA maintenance_stock ให้ลิงก์ picking↔request แต่ จงใจเว้นช่องว่างสามจุดที่สำคัญต่อ UX ของโรงพยาบาล — ไม่มีเทมเพลตการใช้สิ้นเปลือง, ไม่มีการสร้าง picking อัตโนมัติ, ไม่มี การติดตามแบบงานซ่อมบำรุง เราเติมเต็มทั้งสามจุดที่ Layer 3

ความพยายาม: 11 commit / ~3 เซสชันพัฒนา, เป้าหมายการทดสอบ 26 รายการ, เอกสาร 5 หน้า

ชัยชนะหลัก (จัดลำดับตามผลกระทบ):

  1. สร้างร่าง picking อัตโนมัติบน PM cron (Q2.6) — ช่างคลิก Validate ไม่ใช่ New
  2. มุมมอง My Open Requests (Q2.8) — ติดตามแบบบริการตนเองด้วย Running No SR/2026/00001
  3. ตัวกรองชนิด PM บนเทมเพลต (Q2.4) — เฉพาะอะไหล่ที่เกี่ยวข้องตามชนิดงานซ่อมบำรุง

License: LGPL-3 เหนือ dependency แบบ AGPL-3 — เข้ากันได้ที่การแจกจ่าย

สถานะของคำถามที่ยังเปิด: ไม่มีเหลือ (ล็อกทั้งหมดใน §2)


1. วัตถุประสงค์

ช่างเทคนิค BME ของโรงพยาบาลจำเป็นต้องรู้ว่า เครื่องมือแพทย์ชิ้นหนึ่ง ๆ อาจต้องใช้อะไหล่ใดระหว่างการซ่อม/PM — แล้วติดตามแต่ละคำขอจนเสร็จสิ้น — โดยไม่ต้องท่องจำ SKU หรือถามวิศวกรอาวุโส โมดูลนี้ มอบเทมเพลตอะไหล่ที่กำหนดค่าได้ให้ข้อมูลหลักของเครื่องมือแพทย์ ซึ่ง ไหลเข้าสู่ร่าง picking โดยอัตโนมัติเมื่อเปิดคำขอซ่อมบำรุง พร้อม มุมมองติดตามเฉพาะเพื่อติดตามผล

ขอบเขต — ที่รวม

  • Vendor OCA maintenance_stock (ข้อกำหนดเบื้องต้น Layer 2)
  • โมเดลใหม่ hemms.equipment.spare.line (o2m บน maintenance.equipment)
  • roots_is_critical_spare + roots_name_th บน product.template
  • name_get สองภาษาเพื่อให้ค้นหาชื่อทั้ง EN และ TH ได้
  • qty_available แบบ inline + ป้ายระดับวิกฤตในมุมมองเทมเพลต
  • แพร่ระดับความวิกฤตของเครื่องมือแพทย์ (สีแดง) → line roots_is_critical โดยอัตโนมัติ
  • กิจกรรมแจ้งสต็อกต่ำสำหรับอะไหล่วิกฤต
  • สร้างร่าง picking อัตโนมัติ บน PM cron, กรองตามชนิดของคำขอ
  • ร่าง picking ยังคงแก้ไขได้เต็มที่ (เพิ่ม / ลบ / เปลี่ยนจำนวน) จนกว่าจะ validate — ยืนยันในพฤติกรรม Q2.6
  • ปุ่มสถิติสรุปอะไหล่บนฟอร์มเครื่องมือแพทย์
  • เลขรันนิ่ง Stock Request roots_request_no ผ่าน ir.sequence รหัส hemms.stock.request (prefix กำหนดค่าได้ผ่าน UI, ค่าเริ่มต้น SR/%(year)s/ padding 5 → SR/2026/00001)
  • มุมมองติดตาม Stock Request (List / Form / Kanban) พร้อมฟิลด์คำนวณ เปิด/ค้าง — หน้าเริ่มต้น = "My Open Requests"
  • ปุ่มสถิติ "Pending Items" บนฟอร์ม maintenance.request

ขอบเขต — ที่ตัดออก (เลื่อนออกไป)

  • ❌ ปักหมุด "Used last time" (F4) — Q3
  • ❌ ฝัง move-line แบบหน้าเดียวในฟอร์มคำขอ (S5) — Q3
  • ❌ วิซาร์ด "Copy from similar equipment" (S6) — Q3
  • ❌ ตัวป้องกันความเข้ากันได้ผ่าน product brand m2m (S4) — Q3
  • ❌ จองสต็อกอัตโนมัติเมื่อเปลี่ยน stage (A2) — Q3
  • ❌ คืน picking อัตโนมัติเมื่อยกเลิกคำขอ (A3) — Q3
  • ❌ ติดตามที่มาของ line "manual vs template" — Q3 analytics
  • ❌ เรียนรู้จำนวนอัตโนมัติ (A5), แจ้งเตือนต้นทุนแผนก (A7) — Q4+
  • ❌ การกำหนดเส้นทางหลายคลัง, ระบบอัตโนมัติ PO

2. การตัดสินใจด้านการออกแบบ (ล็อกแล้ว)

# การตัดสินใจ ตัวเลือก
D1 เทมเพลตบนเครื่องมือแพทย์ vs หมวดหมู่ เครื่องมือแพทย์ (คัดลอกหมวดหมู่ = วิซาร์ด Q3)
D2 ค่าเริ่มต้นการสร้าง picking อัตโนมัติ เลือกเข้าร่วมต่อเครื่องมือแพทย์, ค่าเริ่มต้น True เมื่อ allow_consumptions=True
D3 การอนุมัติเมื่อจำนวนเกินค่าเริ่มต้นใน Q2 ไม่ — กลับมาทบทวนใน Q3 หลังได้ feedback จากการสาธิต
D4 การตั้งชื่อฟิลด์ prefix roots_* บนโมเดลที่ inherit; ชื่อล้วนบนโมเดลใหม่ hemms.*
D5 License LGPL-3 (roots) เหนือ AGPL-3 (maintenance_stock)
D6 รูปแบบ sequence ของ Stock Request SR/%(year)s/00001 (อิงปี, padding 5) — admin แก้ไขได้ผ่าน Settings, ไม่ฮาร์ดโค้ด ใน Python; อยู่ในข้อมูล ir.sequence
D7 หน้าเริ่มต้นสำหรับเมนูติดตาม My Open Requests (state ∉ done/cancel AND user_id=uid OR create_uid=uid)
D8 ความสามารถในการแก้ไขร่าง picking แก้ไขได้เต็มที่ (เพิ่ม / ลบ / เปลี่ยนจำนวน) จนกว่าจะ Validate — อาศัยพฤติกรรม stock เริ่มต้นของ Odoo

3. โมเดลข้อมูล

maintenance.equipment (inherit)
  ├─ roots_auto_generate_picking (Boolean, default by allow_consumptions)
  ├─ roots_spare_line_ids (o2m → hemms.equipment.spare.line)
  └─ roots_spare_line_count (Integer, computed)

hemms.equipment.spare.line (NEW)
  ├─ equipment_id (m2o → maintenance.equipment, ondelete=cascade)
  ├─ product_id (m2o → product.product, ondelete=restrict)
  ├─ default_qty (Float, default 1.0)
  ├─ kind_ids (m2m → maintenance.kind)         ⭐ filter axis
  ├─ position_note (Char)
  ├─ roots_is_critical (Boolean, computed+stored, writable)
  ├─ qty_available (Float, related, readonly)
  └─ sequence (Integer)

product.template (inherit)
  ├─ roots_is_critical_spare (Boolean)
  └─ roots_name_th (Char)

stock.picking (inherit — Stock Request tracking)
  ├─ roots_request_no (Char, readonly, copy=False, index=True, tracking=True)
  ├─ roots_is_open (Boolean, computed+stored)
  ├─ roots_pending_line_count (Integer, computed)
  ├─ roots_qty_progress (Float, computed)        sum(quantity)/sum(uom_qty)*100
  ├─ roots_pending_qty_total (Float, computed)
  └─ roots_scheduled_overdue (Boolean, computed)

ir.sequence (data record, NOT hardcoded)
  ├─ code   : "hemms.stock.request"
  ├─ name   : "HEMMS Stock Request"
  ├─ prefix : "SR/%(year)s/"
  ├─ padding: 5
  └─ company_id: False

4. แผนการพัฒนา (11 ขั้นตอน)

# ขั้นตอน Commit prefix ผลลัพธ์สำคัญ
Q2.1 ✅ Vendor OCA maintenance_stock 18.0 → addons/oca/ 3650615 ติดตั้งได้สะอาด
Q2.2 ✅ โครงโมดูล (manifest + โมเดลว่าง + security) 8332871 ติดตั้งได้; ยังไม่มีฟีเจอร์
Q2.3 ✅ roots_is_critical_spare + roots_name_th บน product.template + _compute_display_name สองภาษา + _name_search EN/TH ca55074 "แบตเตอรี่" จับคู่กับ "Battery" ได้
Q2.4 ✅ โมเดลใหม่ hemms.equipment.spare.line + o2m บนเครื่องมือแพทย์ + มุมมอง inline (qty_available, ป้ายวิกฤต, แท็กชนิด) 5910394 Admin ตั้งเทมเพลต; ช่างเห็นรายการที่กรองตามชนิด
Q2.5 ✅ ir.cron สำหรับกิจกรรมแจ้งสต็อกต่ำของอะไหล่วิกฤตรายวัน f1340c3 ป้ายวิกฤต + flow กิจกรรม
Q2.6 ✅ override maintenance.request.create() → สร้างร่าง stock.picking อัตโนมัติจากเทมเพลตที่กรองตาม maintenance_kind_id ad0805d คำขอ PM เปิดขึ้นพร้อมร่าง picking ที่กรอกไว้ล่วงหน้า; line ยังแก้ไขได้
Q2.7 ✅ ปุ่มสถิติสรุปอะไหล่บนฟอร์มเครื่องมือแพทย์ ("N Spare Parts · N Critical Low") c2dc019 เจาะดูจากเครื่องมือแพทย์ได้ในคลิกเดียว
Q2.8 ✅ ⭐ การติดตาม Stock Requestir.sequence + roots_request_no + ฟิลด์ค้างที่คำนวณ + มุมมอง List/Kanban + ตัวกรองค้นหา + ปุ่มสถิติ "Pending SR" บนฟอร์มคำขอ + เมนู 3f36d84 ช่างเปิดเมนู "Stock Requests", เห็น SR/2026/00001, จำนวนค้างต่อ picking
Q2.9 การทดสอบ (9 unit + 17 integration = 26) test(spare): add unit + integration tests [Q2.9] CI เขียว
Q2.10 เอกสารโมดูล (5 หน้า) ใต้ docs/modules/spare-parts/ docs(spare): add module documentation [Q2.10] mkdocs serve สะอาด
Q2.11 ข้อมูลสาธิต — เครื่องช่วยหายใจ/MRI/เครื่องกระตุกหัวใจ พร้อมเทมเพลตอะไหล่ที่สมจริง chore(spare): demo data for 3 critical equipment classes [Q2.11] smoke test ผ่านบน DB ใหม่

Dependencies: maintenance_stock (OCA — ต้อง vendor), roots_hemms_pm, roots_hemms_asset_master, roots_hemms_criticality, stock, mail

5. ข้อกำหนดมุมมอง (รายละเอียด Q2.8)

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

Maintenance
└─ Operations
   └─ Stock Requests (ใบเบิก)
      ├─ My Open Requests          ← default landing (D7)
      ├─ All My Requests
      ├─ Team Open
      └─ Backorders
└─ Configuration
   └─ Stock Request Sequence       ← ir.sequence shortcut

5.2 มุมมอง List (ค่าเริ่มต้น = My Open Requests)

คอลัมน์ แหล่งที่มา
Request No. roots_request_no
Equipment equipment_id (พร้อมรูปภาพ)
For Request maintenance_request_id
State state (ป้าย)
Progress roots_qty_progress (widget แถบความคืบหน้า)
Pending Items roots_pending_line_count
Scheduled scheduled_date (สีแดงถ้าเกินกำหนด)
  • ตัวกรองเริ่มต้น: state ∉ done/cancel AND ของฉัน
  • จัดกลุ่มเริ่มต้นตาม: State
  • การตกแต่ง: แถวเป็นสีแดงเมื่อ roots_scheduled_overdue=True

5.3 มุมมอง Form — แท็บ notebook "Pending Items"

คอลัมน์ แหล่งที่มา
Product move.product_id
Ordered move.product_uom_qty
Received move.quantity
Pending product_uom_qty - quantity
Available product.qty_available (ป้ายแดงถ้าเป็น 0)
Critical product.roots_is_critical_spare
  • ตัวกรอง: แสดงเฉพาะ move ที่ state ∉ (done, cancel)
  • ส่วนหัวแสดง roots_request_no อย่างเด่นชัด + ป้าย state + แถบความคืบหน้า

5.4 มุมมอง Kanban

  • คอลัมน์ตาม state: Draft / Waiting / Ready / Partial / Done (ซ่อนคอลัมน์ Partial โดยค่าเริ่มต้น)
  • การ์ด: ภาพย่อเครื่องมือแพทย์, request no, จำนวนรายการ, แถบความคืบหน้า, ป้ายเกินกำหนด

5.5 ตัวกรองค้นหา

  • ☑ Mine (user_id=uid OR create_uid=uid)
  • ☑ Open Only (state ∉ done, cancel)
  • ☐ Overdue (scheduled_date < today AND roots_is_open)
  • ☐ Backorders (backorder_id != False)
  • ☐ Has Critical Spare (mapped("move_ids.product_id.roots_is_critical_spare") มี True)
  • ☐ Scheduled This Week
  • จัดกลุ่มตาม: State / Equipment / Kind / Scheduled Date

5.6 ปุ่มสถิติ "Pending Items" บน maintenance.request

เพิ่มปุ่มสถิติที่ 4 ข้าง 3 ปุ่มของ OCA (Picking list / Stock Moves / Product Moves):

[ Picking list ]  [ Stock Moves ]  [ Product Moves ]  [ Pending Items ⭐ ]
       3                8                              5

เปิดรายการของ stock.move ที่ picking_id.maintenance_request_id=request.id AND state ∉ done, cancel

6. ฟีเจอร์ UX ที่บันทึกไว้

ฟีเจอร์ จากการวิเคราะห์ อยู่ในขั้นตอน Q2 ใด
เทมเพลตอะไหล่ของเครื่องมือแพทย์ (โมเดลข้อมูล A3) ข้อกำหนดหลัก Q2.4
เติม picking อัตโนมัติจากเทมเพลต (F1) จุดติดขัด Q2.6
กรองล่วงหน้าตามชนิด PM (F2) จุดติดขัด Q2.4 + Q2.6
qty_available inline + ป้ายวิกฤต (F3) จุดติดขัด มุมมอง Q2.4
ค้นหาสองภาษา (F5) จุดติดขัด Q2.3
widget สรุปอะไหล่ (S1) ทำให้ง่ายขึ้น Q2.7
สลับซ่อนของหมดสต็อก (S3) ทำให้ง่ายขึ้น มุมมอง Q2.4
สร้างร่าง picking อัตโนมัติบน PM cron (A1) ทำอัตโนมัติ ⭐ Q2.6
กิจกรรมแจ้งสต็อกต่ำ (A4) ทำอัตโนมัติ Q2.5
แพร่ความวิกฤตอัตโนมัติ (A6) ทำอัตโนมัติ Q2.5
เลขรันนิ่ง Stock Request (ใหม่) การสืบย้อน UX Q2.8
มุมมอง My Open Requests (ใหม่) บริการตนเอง UX Q2.8
Pending Items ต่อ picking (ใหม่) การมองเห็น UX Q2.8
ร่าง picking ที่แก้ไขได้ (ยืนยันแล้ว) ความเป็นจริงของงานภาคสนาม Q2.6 (พฤติกรรม Odoo เริ่มต้น, ล็อกด้วยการทดสอบ)

7. กรณีทดสอบ (26)

Unit (test_spare_unit.py) — 9 การทดสอบ

# การทดสอบ ตรวจสอบ
U1 test_critical_spare_default_false ค่าเริ่มต้นของ flag = False
U2 test_bilingual_name_get name_get() คืนค่า "EN / TH" เมื่อตั้ง roots_name_th
U3 test_bilingual_search_by_thai name_search("แบตเตอรี่") พบ product ที่ roots_name_th="แบตเตอรี่"
U4 test_spare_line_default_qty line ใหม่มี qty เริ่มต้น = 1.0
U5 test_spare_line_critical_propagation ความวิกฤตเครื่องมือแพทย์=สีแดง → line roots_is_critical=True
U6 test_auto_generate_flag_follows_allow_consumptions allow_consumptions=Trueroots_auto_generate_picking=True
U7 test_request_no_assigned_on_create_with_maintenance_link picking ที่มี maintenance_request_idroots_request_no ถูกเติม
U8 test_request_no_skipped_for_non_maintenance_picking picking ที่ไม่มีลิงก์ซ่อมบำรุง → roots_request_no ว่าง
U9 test_request_no_uses_ir_sequence_code รหัส sequence = hemms.stock.request มีอยู่; prefix ไม่ฮาร์ดโค้ดใน Python

Integration (test_spare_integration.py) — 17 การทดสอบ

# การทดสอบ ตรวจสอบ
I1 test_add_spare_line_to_equipment Admin เพิ่ม product + qty + kind ได้
I2 test_template_filtered_by_kind_on_request_view การเปิดคำขอชนิด=Calibration แสดงเฉพาะ line ที่แท็กชนิดนั้น
I3 test_pm_cron_creates_draft_picking_from_template PM cron → คำขอ + ร่าง picking จากเทมเพลต
I4 test_pm_cron_picking_lines_filtered_by_kind การสร้าง picking อัตโนมัติรวมเฉพาะ line เทมเพลตที่ตรงกับชนิด
I5 test_validating_picking_reduces_qty_available validate picking → qty_available ลดลง
I6 test_critical_spare_below_min_creates_activity อะไหล่วิกฤต < ขั้นต่ำ → กิจกรรมสำหรับ BME Manager
I7 test_non_critical_spare_below_min_no_activity ไม่วิกฤต → ไม่มีกิจกรรม
I8 test_equipment_summary_count_excludes_archived_products จำนวนปุ่มสถิติไม่นับที่ archive แล้ว
I9 test_corrective_request_does_not_auto_generate คำขอที่ไม่ใช่ PM → ไม่สร้าง picking อัตโนมัติ
I10 test_auto_generate_disabled_skips_picking roots_auto_generate_picking=False → ไม่มีร่าง
I11 test_technician_can_add_non_template_line_to_draft_picking เพิ่ม line นอกเทมเพลต, validate สำเร็จ
I12 test_technician_can_remove_template_line_from_draft_picking ลบ line เทมเพลต, validate สำเร็จ
I13 test_technician_can_change_qty_on_template_line qty 1→2, qty_available ลด 2 เมื่อ validate
I14 test_pending_line_count_excludes_done_moves จำนวนค้างไม่รวม move ที่ done/cancel
I15 test_qty_progress_computes_correctly_on_partial_validation validate บางส่วน → progress=50%, state=partial
I16 test_open_filter_excludes_done_and_cancel ตัวกรอง "Open Only" ไม่รวม done + cancel
I17 test_my_filter_includes_responsible_and_creator ตัวกรอง "Mine" รวมทั้ง user_id และ create_uid

Acceptance smoke (ทำด้วยมือ)

  1. ตั้งค่าเครื่องช่วยหายใจ → ความวิกฤต=สีแดง → allow_consumptions=True → เพิ่ม 3 line เทมเพลต (Filter ×1 kind=Filter Replacement, Battery ×1 kind=Battery, Sensor ×1 kind=Calibration)
  2. แนบ maintenance.plan kind=Filter Replacement, interval=3 เดือน
  3. รัน PM cron ด้วยมือ
  4. ตรวจสอบ: คำขออยู่ใน stage PM Scheduled; ร่าง picking แนบมาพร้อม roots_request_no=SR/2026/00001 มี เฉพาะ line Filter เท่านั้น
  5. เปิดเมนู "My Open Requests" → เห็น SR/2026/00001 พร้อม progress 0%
  6. เปิด picking → แท็บ "Pending Items" → เห็น line Filter ที่ Pending=1
  7. เพิ่ม line Battery ที่ไม่ได้กำหนด → บันทึก → Pending=2
  8. Validate → state=done → แถวหายไปจาก "My Open Requests"
  9. ถ้าจำนวน Filter ต่ำกว่าขั้นต่ำ → กิจกรรมไปยัง BME Manager

8. คำถามที่ยังเปิด

ไม่มี ชื่อโมดูล, ขอบเขต, โมเดลข้อมูล, การตัดสินใจด้านการออกแบบ (D1–D8), รูปแบบ sequence, และมุมมองหน้าเริ่มต้น ยืนยันทั้งหมดเมื่อ 2026-05-22

9. รายการตรวจสอบเพื่อทำงานต่อ

เสร็จแล้ว (ณ 2026-05-22): Q2.1–Q2.8 commit ทั้งหมดบน main

เซสชันถัดไปเริ่มที่ Q2.9:

  1. อ่านไฟล์นี้ (v1.1)
  2. รันการทดสอบจาก §7 — implement tests/test_spare_unit.py + tests/test_spare_integration.py
  3. commit เป็น test(spare): add unit + integration tests [Q2.9]
  4. ดำเนินการต่อไปยัง Q2.10 (เอกสาร) และ Q2.11 (ข้อมูลสาธิต) เพื่อปิด Q2