TLDR
ลำดับของ workflow transition สำคัญมาก transition ที่มี idx สูงกว่า (อยู่ท้ายลิสต์) มีความสำคัญสูงกว่าและจะชนะเสมอเมื่อมีหลาย transition ที่ match กัน
Use Case
สำหรับ workflow ของ Purchase Order เรามี requirement สองข้อ:
- ถ้า Purchase User submit PO สถานะควรเปลี่ยนเป็น
Pending Approval - ถ้า Purchase Manager submit PO สถานะควรข้ามไปเป็น
Submittedเลย
ตอนแรกที่เราเพิ่ม transition เราเรียงลำดับแบบนี้:
- Draft -> Submitted (Allowed: Purchase Manager)
- Draft -> Pending Approval (Allowed: Purchase User)
แล้วก็สังเกตเห็นปัญหา: เมื่อ user ที่มีทั้ง role Purchase User และ Purchase Manager submit PO document กลับเปลี่ยนสถานะไปเป็น Pending Approval แทนที่จะเป็น Submitted ซึ่งไม่ถูกต้อง - ใครก็ตามที่มี role Purchase Manager ควรข้ามขั้นตอน approval ไปได้เลย
เราเลยดูเพิ่มเติมว่าทำไมถึงเป็นแบบนั้น
สาเหตุของปัญหา
จริงๆ แล้วนี่ไม่ใช่ bug - แต่เป็นแค่วิธีที่ Frappe ทำงาน
โค้ดอยู่ใน frappe/model/workflow.py ในฟังก์ชัน apply_workflow หลังจาก collect transition ทั้งหมดที่ user มีสิทธิ์ใช้ได้แล้ว มันจะเลือก transition ที่ match กับ action ที่กดแบบนี้:
# find the transition
transition = None
for t in transitions:
if t.action == action:
transition = t # ← last match overwritesใน loop นี้ไม่มี break ทุก transition ที่ match จะทับของเดิม ดังนั้น transition ที่อยู่ท้ายสุดในลิสต์จะชนะเสมอ
get_transitions สร้างลิสต์นั้นโดย iterate workflow.transitions ตาม idx:
for transition in workflow.transitions:
if transition.state == current_state and transition.allowed in roles:
if not is_transition_condition_satisfied(transition, doc):
continue
transitions.append(transition.as_dict())ดังนั้น transition ที่อยู่ ท้ายกว่า ในลิสต์ (idx สูงกว่า) จะถูก apply - ไม่ว่า role hierarchy จะเป็นยังไงก็ตาม
วิธีแก้ไข
แก้ได้ง่ายมาก - แค่เรียงลำดับ transition ใหม่ให้ transition ที่มี priority สูงกว่าหรือ specific กว่าอยู่ ท้ายสุด ในกรณีของเรา แค่สลับลำดับ:
- Draft -> Pending Approval (Allowed: Purchase User)
- Draft -> Submitted (Allowed: Purchase Manager)
ตอนนี้เมื่อ Purchase Manager submit PO transition ทั้งสองตัว match - แต่เนื่องจาก "Draft -> Submitted" อยู่ท้ายสุดในลิสต์ มันจึงชนะ
กฎง่ายๆ คือ: วาง transition ที่มีสิทธิ์สูงกว่าหรือ specific กว่าไว้ด้านล่างเสมอ