ERP

การติดตั้งใช้งาน ERPNext: คู่มือปฏิบัติเกี่ยวกับระบบ โมเดลเอกสาร และเวิร์กโฟลว์หลัก

ERPNext สร้างขึ้นบนพื้นฐานของ Frappe Framework ซึ่งเป็นแพลตฟอร์มแบบ low-code ที่ขับเคลื่อนด้วยเมทาดาทา (metadata-driven) ข้อเท็จจริงเพียงข้อนี้อธิบายเกือบทุกอย่างเกี่ยวกับวิธีการติดตั้งใช้งาน ERPNext ในทางปฏิบัติ: คุณไม่ได้กำลังเขียนระบบ ERP ขึ้นมาใหม่ตั้งแต่ต้น แต่กำลัง "กำหนดค่า" ระบบที่โมเดลข้อมูล ฟอร์ม สิทธิ์การเข้าถึง และเวิร์กโฟลว์ทั้งหมดถูกนิยามไว้ในรูปแบบ เอกสาร (documents) เอง การเข้าใจโมเดลเอกสารนี้คือหนทางที่เร็วที่สุดในการก้าวจาก "เราติดตั้ง ERPNext แล้ว" ไปสู่ "เราบริหารธุรกิจด้วย ERPNext"

บทความนี้ครอบคลุมสามเรื่อง ได้แก่ แผนการดำเนินโครงการติดตั้งใช้งานในทางปฏิบัติ โมเดลเอกสารที่เป็นรากฐานของทุกโมดูล (ขาย จัดซื้อ สต๊อกสินค้า บัญชี และทรัพยากรบุคคล) และตัวอย่างไดอะแกรมลำดับเหตุการณ์ (sequence diagram) สำหรับสองเวิร์กโฟลว์ที่ทุกโครงการต้องทำให้ถูกต้องในที่สุด นั่นคือ กระบวนการขายจนถึงรับเงิน (order-to-cash) และกระบวนการจัดซื้อจนถึงจ่ายเงิน (procure-to-pay)

1. การติดตั้งใช้งาน ERPNext ดำเนินไปอย่างไรในความเป็นจริง

การติดตั้งใช้งาน ERPNext ที่ประสบความสำเร็จส่วนใหญ่จะผ่าน 5 ระยะ กรอบเวลาด้านล่างนี้อ้างอิงจากบริษัทขนาดเล็กถึงกลางที่มีนิติบุคคลเดียว ส่วนการติดตั้งแบบหลายบริษัท (multi-company) หรือที่เน้นการผลิต (manufacturing) จะใช้เวลานานกว่านี้

ระยะที่ 1 — สำรวจความต้องการทางธุรกิจ (2–4 สัปดาห์) เวิร์กช็อปกับผู้มีส่วนได้ส่วนเสียในแต่ละแผนก การทำแผนผังกระบวนการทำงานปัจจุบัน การตรวจสอบระบบเดิม และการรวบรวมความต้องการ ขั้นตอนนี้จะจบลงด้วยเอกสารความต้องการทางธุรกิจ (Business Requirements Document หรือ BRD) ที่ระบุความต้องการแยกตามโมดูล พร้อมการวิเคราะห์ช่องว่าง (gap analysis) เพื่อระบุจุดที่ต้องปรับแต่งเพิ่มเติม

ระยะที่ 2 — กำหนดค่าโมดูล (4–8 สัปดาห์) เริ่มจากการตั้งค่าระดับบริษัท การจัดการผู้ใช้งาน และผังบัญชี (chart of accounts) จากนั้นทีมงานจะกำหนดค่าโมดูลตามความต้องการทีละส่วน ได้แก่ ขาย จัดซื้อ สต๊อกสินค้า บัญชี และทรัพยากรบุคคล พร้อมสร้างข้อมูลหลัก (master data) เช่น ลูกค้า ผู้จำหน่าย สินค้า รายการราคา และคลังสินค้า

ระยะที่ 3 — การปรับแต่งและเชื่อมต่อระบบ (3–6 สัปดาห์) ช่องว่างที่พบจากขั้นตอนสำรวจความต้องการจะถูกปิดด้วยการเพิ่มฟิลด์กำหนดเอง (custom fields) สคริปต์ฝั่งไคลเอนต์/เซิร์ฟเวอร์ รูปแบบการพิมพ์และรายงานที่กำหนดเอง และเอกสารประเภท Workflow สำหรับสายการอนุมัติ ส่วนการเชื่อมต่อระบบ (เกตเวย์ชำระเงิน อีคอมเมิร์ซ ธนาคาร ผู้ให้บริการขนส่ง) จะถูกสร้างหรือกำหนดค่าในขั้นตอนนี้

ระยะที่ 4 — ทดสอบและฝึกอบรม (3–4 สัปดาห์) ดำเนินการทดสอบหน่วย (unit testing) และทดสอบการเชื่อมต่อ (integration testing) ของเวิร์กโฟลว์ที่กำหนดค่าไว้ ควบคู่ไปกับการทดสอบการยอมรับของผู้ใช้ (UAT) ด้วยธุรกรรมจริง และการฝึกอบรมตามบทบาทหน้าที่ ครอบคลุมทีมบัญชี ขาย คลังสินค้า และทรัพยากรบุคคล ซึ่งแต่ละทีมต้องการการอบรมที่แตกต่างกันเนื่องจากใช้งาน DocType คนละชุด

ระยะที่ 5 — เริ่มใช้งานจริงและซัพพอร์ต การย้ายข้อมูลครั้งสุดท้าย การบันทึกยอดยกมา (opening balances) และการทำงานคู่ขนาน (parallel-run) หรือการตัดใช้งานทันที (hard cutover) ตามด้วยช่วง hypercare (โดยทั่วไปคือ 1–2 สัปดาห์แรกหลังเริ่มใช้งาน) ที่มีทีมซัพพอร์ตเฉพาะทางคอยดูแลก่อนส่งต่อไปยังการซัพพอร์ตมาตรฐาน

รวมแล้ว: 3–6 เดือน สำหรับการติดตั้งใช้งานทั่วไปในกลุ่มธุรกิจขนาดกลาง ตัวแปรที่มักผันผวนที่สุดคือระยะที่ 3 เสมอ — ยิ่งกระบวนการทำงานของคุณแตกต่างจากค่าเริ่มต้นของ ERPNext มากเท่าไร ก็ยิ่งต้องใช้ DocType สคริปต์ และสถานะเวิร์กโฟลว์ที่กำหนดเองมากขึ้นเท่านั้น และแต่ละส่วนก็ต้องผ่านการทดสอบของตัวเองด้วย

2. โมเดลเอกสาร: ทุกสิ่งคือ DocType

ใน Frappe Framework DocType คือทั้งนิยามตารางฐานข้อมูล ฟอร์ม ขอบเขตสิทธิ์การเข้าถึง และ (บ่อยครั้ง) ตรรกะทางธุรกิจ ในเวลาเดียวกัน เมื่อคุณสร้าง DocType ขึ้นมา Frappe จะสร้างตารางฐานข้อมูลรองรับ (นำหน้าด้วย tab ดังนั้น DocType ชื่อ Sales Order จะอยู่ในตาราง tabSales Order) มุมมองรายการ (list view) และมุมมองฟอร์ม (form view) ให้โดยอัตโนมัติ โดยไม่ต้องเขียนโค้ดฝั่งหน้าบ้านเพิ่มเติม

แนวคิดบางอย่างสำคัญยิ่งกว่าอย่างอื่นเมื่อคุณกำลังติดตั้งใช้งานระบบ ไม่ใช่แค่ใช้งานมันเฉยๆ:

  • DocField — นิยามฟิลด์เดี่ยว (ชนิดข้อมูล ป้ายชื่อ การตรวจสอบความถูกต้อง ระดับสิทธิ์) ภายใน DocType โครงสร้างของ DocType ก็คือรายการของ DocField นั่นเอง
  • Meta — DocType นั้นถูกเก็บในรูปแบบ DocType เช่นกัน (DocType ชื่อ DocType เป็นตัวอธิบาย DocType) ความสะท้อนกลับตัวเอง (reflexivity) นี้เองที่ทำให้ Customize Form สามารถเพิ่มฟิลด์ให้กับ doctype มาตรฐานอย่าง Sales Order ได้โดยไม่ต้องแตะซอร์สโค้ด — เพราะคุณกำลังแก้ไขเมทาดาทา ไม่ใช่โค้ด
  • Child Table / Table DocType — DocType ที่ถูกกำหนดเป็น istable ซึ่งจะมีอยู่ได้ก็ต่อเมื่อถูกซ้อนอยู่ภายในเอกสารหลักเท่านั้น ไม่มีมุมมองรายการเป็นของตัวเอง Sales Order Item เป็น child table ของ Sales Order โดยแต่ละแถวคือรายการสินค้าหนึ่งรายการ
  • Link Field — ฟิลด์ที่อ้างอิงไปยัง DocType อื่นด้วยชื่อ คล้ายกับ foreign key ในฐานข้อมูล ทำให้เกิดความสัมพันธ์เชิงอ้างอิง (Sales Order เชื่อมโยงไปยัง Customer, Sales Order Item เชื่อมโยงไปยัง Item) โดยไม่ต้องเขียน join ด้วยมือ
  • เอกสารที่ submit ได้ และ docstatus — DocType ประเภทธุรกรรมอย่าง Sales Order, Delivery Note และ Purchase Invoice จะมีฟิลด์ docstatus กำกับอยู่: 0 = ฉบับร่าง (Draft), 1 = ส่งแล้ว (Submitted), 2 = ยกเลิก (Cancelled) การ submit คือจุดที่กระตุ้นให้เกิดผลลัพธ์ในขั้นถัดไป — การเคลื่อนไหวของสต๊อก การบันทึกบัญชีแยกประเภททั่วไป (GL) — และเอกสารที่ submit แล้วจะไม่สามารถแก้ไขได้อีกเป็นส่วนใหญ่ ซึ่งเป็นสิ่งที่ทำให้ระบบบัญชีของ ERPNext มี audit trail แทนที่จะเป็นเหมือนสเปรดชีตที่แก้ไขได้ตลอดเวลา
  • Naming series — ควบคุมวิธีการสร้างรหัสเอกสาร (เช่น SO-.YYYY.-.##### สำหรับ Sales Order) สามารถกำหนดค่าแยกตามบริษัทหรือปีบัญชีได้
  • Workflow — เป็น DocType เช่นกัน ใช้สำหรับเพิ่มสถานะการอนุมัติแบบกำหนดเอง (ฉบับร่าง → รออนุมัติ → อนุมัติแล้ว) ทับบน DocType เป้าหมาย โดยไม่ต้องเขียนโค้ด

ไดอะแกรมโมเดลเอกสาร: ชั้นเมทาดาทา

classDiagram
    class DocType {
        +name: string
        +module: string
        +istable: bool
        +is_submittable: bool
        +autoname: string
    }
    class DocField {
        +fieldname: string
        +fieldtype: string
        +label: string
        +reqd: bool
        +options: string
    }
    class Document {
        +doctype: string
        +name: string
        +docstatus: int
        +owner: string
        +validate()
        +on_submit()
        +on_cancel()
    }
    class Workflow {
        +document_type: string
        +states: WorkflowState[]
        +transitions: WorkflowTransition[]
    }

    DocType "1" --> "*" DocField : defines
    DocType "1" --> "*" Document : instantiates
    Workflow "1" --> "1" DocType : governs
    Document "1" --> "*" Document : child table rows

ไดอะแกรมโมเดลเอกสาร: ข้อมูลวงจรการขาย

erDiagram
    CUSTOMER ||--o{ SALES_ORDER : places
    SALES_ORDER ||--|{ SALES_ORDER_ITEM : contains
    ITEM ||--o{ SALES_ORDER_ITEM : referenced_by
    SALES_ORDER ||--o{ DELIVERY_NOTE : fulfilled_by
    DELIVERY_NOTE ||--|{ DELIVERY_NOTE_ITEM : contains
    SALES_ORDER ||--o{ SALES_INVOICE : billed_by
    SALES_INVOICE ||--|{ SALES_INVOICE_ITEM : contains
    SALES_INVOICE ||--o{ PAYMENT_ENTRY : settled_by
    SALES_INVOICE ||--o{ GL_ENTRY : posts
    DELIVERY_NOTE ||--o{ STOCK_LEDGER_ENTRY : posts

ลูกศรทุกเส้นในภาพนี้คือ Link Field หรือความสัมพันธ์แบบ child-table ที่ถูกนิยามไว้ในเมทาดาทา ไม่ใช่ join ที่เขียนด้วยมือ — และนี่คือเหตุผลที่ Customize Form, Report Builder และเครื่องมือ Query Report สามารถไล่ตามความสัมพันธ์เหล่านี้ได้โดยไม่ต้องมีนักพัฒนาเขียน SQL

3. ตัวอย่างไดอะแกรมลำดับเหตุการณ์: กระบวนการขายจนถึงรับเงิน (Order-to-Cash)

นี่คือกระบวนการที่เวิร์กช็อปสำรวจความต้องการมักใช้เวลามากที่สุด เพราะคำถามอย่าง "รายได้ควรรับรู้เมื่อไร" และ "สินค้าออกจากคลังเมื่อไร" มักเป็นจุดที่กระบวนการจริงของลูกค้าต่างไปจากค่าเริ่มต้นของ ERPNext

sequenceDiagram
    actor Customer as ลูกค้า
    actor SalesUser as พนักงานขาย
    participant ERPNext as ERPNext (Frappe)
    participant Warehouse as คลังสินค้า
    actor Accounts as พนักงานบัญชี

    Customer->>SalesUser: ขอใบเสนอราคา
    SalesUser->>ERPNext: สร้าง Quotation
    ERPNext-->>SalesUser: Quotation (docstatus=0 ฉบับร่าง)
    SalesUser->>Customer: ส่ง Quotation ให้ลูกค้า
    Customer->>SalesUser: อนุมัติ

    SalesUser->>ERPNext: สร้าง Sales Order จาก Quotation
    ERPNext-->>SalesUser: Sales Order (ฉบับร่าง)
    SalesUser->>ERPNext: Submit Sales Order
    ERPNext->>ERPNext: docstatus 0 → 1 (Submitted)
    ERPNext-->>Warehouse: คำสั่งซื้อพร้อมสำหรับการจัดส่ง

    Warehouse->>ERPNext: สร้าง Delivery Note จาก Sales Order
    ERPNext-->>Warehouse: Delivery Note (ฉบับร่าง)
    Warehouse->>ERPNext: Submit Delivery Note
    ERPNext->>ERPNext: บันทึก Stock Ledger Entry (จำนวน -N)
    ERPNext->>ERPNext: อัปเดต % การส่งมอบของ Sales Order

    Accounts->>ERPNext: สร้าง Sales Invoice จาก Delivery Note
    ERPNext-->>Accounts: Sales Invoice (ฉบับร่าง)
    Accounts->>ERPNext: Submit Sales Invoice
    ERPNext->>ERPNext: บันทึก GL Entry (เดบิตลูกหนี้ / เครดิตรายได้)

    Customer->>Accounts: ชำระเงิน
    Accounts->>ERPNext: สร้าง Payment Entry สำหรับ Sales Invoice
    ERPNext->>ERPNext: กระทบยอด GL Entry ปิดยอดค้างชำระ
    ERPNext-->>Accounts: สถานะใบแจ้งหนี้ = ชำระแล้ว

ข้อสังเกตที่ควรพูดคุยกับลูกค้าระหว่างการกำหนดค่าในระยะที่ 2:

  • Delivery Note เป็นทางเลือก ไม่บังคับ ธุรกิจบริการสามารถไปจาก Sales Order → Sales Invoice ได้โดยตรง ไม่มีสิ่งใดในโมเดลเอกสารที่บังคับให้ต้องผ่านขั้นตอนสต๊อก
  • การกดปุ่ม submit คือตัวกระตุ้น ไม่ใช่การกด save เอกสารฉบับร่าง (docstatus=0) สามารถแก้ไขได้อย่างอิสระและไม่กระทบบัญชีแยกประเภท นี่คือช่องว่างการฝึกอบรมที่พบบ่อยที่สุด — ผู้ใช้ที่ "save" Delivery Note แล้วสงสัยว่าทำไมสต๊อกไม่เคลื่อนไหว
  • เปอร์เซ็นต์การส่งมอบและเปอร์เซ็นต์การเรียกเก็บเงินเป็นฟิลด์คำนวณอัตโนมัติใน Sales Order ที่อัปเดตทันทีเมื่อเอกสารที่เชื่อมโยงกันถูก submit — นี่คือสิ่งที่ขับเคลื่อนกลไกป้องกันการส่งมอบเกิน (over-delivery) และเรียกเก็บเงินเกิน (over-billing)

4. ตัวอย่างไดอะแกรมลำดับเหตุการณ์: กระบวนการจัดซื้อจนถึงจ่ายเงิน (Procure-to-Pay)

sequenceDiagram
    actor Dept as แผนกผู้ขอซื้อ
    actor Buyer as พนักงานจัดซื้อ
    participant ERPNext as ERPNext (Frappe)
    actor Supplier as ผู้จำหน่าย
    participant Warehouse as คลังสินค้า
    actor Accounts as พนักงานบัญชี

    Dept->>ERPNext: สร้าง Material Request
    ERPNext-->>Buyer: Material Request รออนุมัติ

    opt เปรียบเทียบผู้จำหน่ายหลายราย
        Buyer->>ERPNext: สร้าง Request for Quotation (RFQ)
        ERPNext-->>Supplier: ส่ง RFQ
        Supplier->>ERPNext: Submit Supplier Quotation
        Buyer->>ERPNext: เปรียบเทียบ Supplier Quotation
    end

    Buyer->>ERPNext: สร้าง Purchase Order (จาก RFQ หรือ Material Request)
    ERPNext-->>Buyer: Purchase Order (ฉบับร่าง)
    Buyer->>ERPNext: Submit Purchase Order
    ERPNext->>Supplier: ออก PO

    Supplier->>Warehouse: จัดส่งสินค้า
    Warehouse->>ERPNext: สร้าง Purchase Receipt จาก Purchase Order
    Warehouse->>ERPNext: Submit Purchase Receipt
    ERPNext->>ERPNext: บันทึก Stock Ledger Entry (จำนวน +N)
    ERPNext->>ERPNext: อัปเดต % การรับสินค้าของ PO

    Accounts->>ERPNext: สร้าง Purchase Invoice จาก Purchase Receipt
    Accounts->>ERPNext: Submit Purchase Invoice
    ERPNext->>ERPNext: บันทึก GL Entry (เดบิตค่าใช้จ่าย/สต๊อก / เครดิตเจ้าหนี้)

    Accounts->>ERPNext: สร้าง Payment Entry สำหรับ Purchase Invoice
    ERPNext->>ERPNext: กระทบยอด GL Entry ปิดยอดค้างชำระ
    ERPNext-->>Supplier: จ่ายเงินเรียบร้อย

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

  • การเปรียบเทียบ RFQ / Supplier Quotation เป็นทางเลือก ข้ามขั้นตอนนี้ไปได้เลยสำหรับองค์กรที่มีผู้จำหน่ายที่เจรจาไว้ล่วงหน้าหรือมีแหล่งจัดหาเดียว โดยไปจาก Material Request สู่ Purchase Order ได้โดยตรง
  • ลำดับของ Purchase Receipt และ Purchase Invoice ไม่ตายตัว บางองค์กรออกใบแจ้งหนี้ก่อนสินค้ามาถึง (invoice-first) บางแห่งรับสินค้าก่อน (receive-first) ERPNext รองรับทั้งสองแบบ คุณกำหนดค่าเริ่มต้นได้ใน Buying Settings แต่ธุรกรรมแต่ละรายการสามารถเบี่ยงเบนจากค่าเริ่มต้นได้

5. สิ่งนี้หมายความว่าอย่างไรสำหรับรายการตรวจสอบการติดตั้งใช้งานของคุณ

เนื่องจากโมเดลเอกสารมีความสอดคล้องกันในทุกโมดูล งานติดตั้งใช้งานส่วนใหญ่จึงเป็นการทำซ้ำรูปแบบเดิม มากกว่าการออกแบบสิ่งใหม่:

  1. จับคู่แต่ละกระบวนการทางธุรกิจกับสายเอกสาร ในลักษณะเดียวกับสองไดอะแกรมข้างต้น ระบุว่าขั้นตอนใดจำเป็น ขั้นตอนใดเป็นทางเลือก และขั้นตอนใดต้องเพิ่ม Workflow DocType ทับเข้าไปสำหรับการอนุมัติ
  2. กำหนดเงื่อนไขการ submit สำหรับ DocType ที่ submit ได้ทุกตัว ตกลงกันว่าใครมีสิทธิ์ submit และควรมีเงื่อนไขอะไรเป็นจริงก่อนที่จะ submit (มีสต๊อกเพียงพอ ตรวจสอบวงเงินเครดิตแล้ว งบประมาณได้รับอนุมัติแล้ว)
  3. ขยายไม่ใช่แยกออก (Extend, don’t fork) เลือกใช้ Customize Form (เพิ่ม DocField เข้าไปใน DocType มาตรฐาน) มากกว่าการสร้าง DocType กำหนดเองแยกต่างหาก เพื่อให้ยังคงเข้ากันได้กับรายงานหลักและการอัปเกรด ERPNext ในอนาคต
  4. กำหนด naming series และรูปแบบเลขที่เอกสารให้ถูกต้องก่อนเริ่มใช้งานจริง การเปลี่ยนรูปแบบ series หลังจากมีธุรกรรมจริงเกิดขึ้นแล้วจะสร้างความยุ่งยากมาก ควรตกลงรูปแบบ (เช่น SO-.YYYY.-.#####) ในระยะที่ 2 ไม่ใช่ระยะที่ 5
  5. ทดสอบสายเอกสารที่เชื่อมโยงกันแบบครบวงจร ไม่ใช่ทดสอบ DocType แยกทีละตัว ข้อบกพร่องส่วนใหญ่ที่พบใน UAT ของการติดตั้งใช้งาน ERPNext มักปรากฏในจุดส่งต่อระหว่างเอกสาร (เช่น Delivery Note ที่ submit ไม่ได้เพราะตรรกะการจองสต๊อกของ Sales Order ขัดแย้งกับการตั้งค่าคลังสินค้า) ไม่ใช่ภายในฟอร์มเดียว

เมื่อโมเดลเอกสารถูกต้องแล้ว ไดอะแกรมลำดับเหตุการณ์ข้างต้นจะไม่ใช่แค่ "ERPNext ทำงานอย่างไร" อีกต่อไป แต่จะกลายเป็น "ธุรกิจของคุณทำงานอย่างไรอยู่แล้ว" ที่ถูกแสดงออกมาในรูปแบบเมทาดาทาของ Frappe


แหล่งที่มา: