POS Point — ระบบสะสมแต้ม POS และ Sale บน Odoo 17 Enterprise

โมดูล Odoo 17 Enterprise สำหรับจัดการ Point (แต้ม): รวมออเดอร์จาก Sale และ POS เป็น view เดียว คำนวณแต้มจาก Air Type, หมวดหมู่+ช่วงราคา และยอดสั่ง พร้อม export log เป็น Excel. ใช้ Python (ORM, SQL view) + res.config.settings.

· 10 min read

Problem

ต้องการระบบสะสมแต้มที่รวมทั้งออเดอร์จาก Sale และ POS เข้าด้วยกัน โดยคำนวณแต้มตามกฎหลายแบบ (ประเภทสินค้า, หมวดหมู่+ช่วงราคา, ยอดสั่ง) และกรองเฉพาะออเดอร์ที่จ่ายครบ ผ่านช่องทางที่กำหนด และไม่ overdue — โฟลว์มาตรฐานของ Odoo ไม่มี unified view และกฎคำนวณแต้มแบบนี้

Solution

พัฒนาโมดูลขยาย Odoo 17 (point_of_sale, sale, account) สร้าง SQL view รวม sale_order, pos_order และ out_refund; เพิ่มฟิลด์ our_point_code และ point ที่ res.partner, ขยาย product.air_type ด้วย point; สร้าง model ช่วงราคา–แต้ม และ res.config.settings สำหรับกฎคำนวณ (payment method, special price, overdue, air type, main category, ยอดทุก X บาทได้ Y แต้ม, exclude หมวดสินค้า) ทั้ง Sale และ POS; Wizard export log เป็น Excel ตามช่วงวันที่

Impact

ดูรายการออเดอร์ที่ได้แต้มจาก Sale และ POS ในที่เดียว, คำนวณแต้มตรงตามกฎที่ตั้งค่าได้, export log ใช้ตรวจสอบ/ส่งต่อได้ทันที

ทำไมต้องมีโมดูลนี้ (Executive Summary)

ปัญหาที่พบบ่อยใน Odoo คือแต้มสมาชิกแยกกันระหว่างหน้าร้าน (POS) กับหลังบ้าน (Sale Order) ทำให้ลูกค้าสับสนว่าแต้มมาจากช่องทางไหน และแอดมินต้องตรวจหรือรวบรวมข้อมูลจากหลายที่ ทำงานซ้ำซ้อน

POS Point ช่วยรวมศูนย์ข้อมูลแต้มจากทุกช่องทาง (Sale, POS, การคืนเงิน) ให้เห็นในหน้าเดียว และคำนวณแต้มตามเงื่อนไขธุรกิจที่ซับซ้อนได้โดยอัตโนมัติ — เช่น แต้มตามประเภทสินค้า ตามช่วงราคา หรือตามยอดสั่ง (ทุก X บาทได้ Y แต้ม) — โดยกรองเฉพาะออเดอร์ที่จ่ายครบและผ่านวิธีชำระที่กำหนด

ผลลัพธ์ที่ได้: แอดมินตรวจสอบแต้มได้ในหน้าเดียว และออกรายงาน Excel ตามช่วงวันที่ เพื่อใช้ทำ Marketing หรือส่งต่อทีมอื่นได้ทันที

เหมาะกับ: ธุรกิจที่มีทั้งโชว์รูม/หน้าร้าน (POS) และขายผ่านออเดอร์หลังบ้าน (Sale) และต้องการโปรแกรมสะสมแต้มที่ยืดหยุ่นตามกฎของบริษัท


System Architecture

Data Flow (Flowchart)

ข้อมูลออเดอร์จาก Sale, POS และใบลดหนี้ไหลมารวมที่ SQL view เดียว จากนั้นใช้แสดงใน Tree View หรือส่งออกผ่าน Export Wizard:

flowchart LR
  subgraph sources["แหล่งข้อมูล"]
    SO[sale.order]
    PO[pos.order]
    AM[account_move<br/>out_refund]
  end

  subgraph filter["กรอง"]
    RC[res.partner<br/>our_point_code]
  end

  subgraph unified["Unified View"]
    PSU[(pos.sale.unified<br/>SQL View)]
  end

  subgraph output["ผลลัพธ์"]
    TV[Tree View<br/>POS and Sale]
    WIZ[Export Wizard]
    XLSX[Excel]
  end

  SO --> RC
  PO --> RC
  AM --> RC
  RC --> PSU
  PSU --> TV
  PSU --> WIZ
  WIZ --> XLSX
  • เฉพาะลูกค้าที่มี รหัสสมาชิก (Our Point Code) จะถูกนำมาคำนวณแต้ม
  • View คำนวณให้ว่าแต่ละออเดอร์ ผ่านเงื่อนไขหรือไม่ (validated) และ ได้กี่แต้ม ตามกฎใน Settings

การเปิดดูรายการ (Sequence)

เมื่อผู้ใช้เปิดเมนู “POS and Sale” ระบบดึงข้อมูลจาก view แล้วคำนวณ validated และ point ทาง backend:

sequenceDiagram
  participant User
  participant OdooUI as Odoo Web UI
  participant ORM as ORM / Backend
  participant DB as PostgreSQL

  User->>OdooUI: เปิดเมนู POS and Sale
  OdooUI->>ORM: search_read(pos.sale.unified)
  ORM->>DB: SELECT จาก view pos_sale_unified
  DB-->>ORM: rows (order_id, partner, order_type, ...)
  ORM->>ORM: _compute_validated_order_and_point (แต่ละ record)
  Note over ORM: อ่าน res.config.settings<br/>กรอง payment / overdue<br/>_calculate_point (air type, category, amount)
  ORM-->>OdooUI: records พร้อม validated_order, point
  OdooUI-->>User: แสดง Tree View

การ Export Log (Sequence)

เมื่อผู้ใช้รัน Export Wizard กำหนดช่วงวันที่แล้วกด Export:

sequenceDiagram
  participant User
  participant Wizard as Export Wizard
  participant ORM as ORM
  participant SO as sale.order
  participant PO as pos.order
  participant XLSX as XlsxWriter

  User->>Wizard: กำหนด date_from, date_to → Export
  Wizard->>ORM: _get_paid_sale_order(domain)
  Wizard->>ORM: _get_paid_pos_order(domain)
  ORM->>SO: search + กรองจ่ายครบ / payment method
  ORM->>PO: search + กรอง our_point_code
  SO-->>Wizard: paid sale orders
  PO-->>Wizard: paid pos orders
  Wizard->>Wizard: _combine_and_sort, กรอง our_point_code
  Wizard->>Wizard: _calculate_point แต่ละ order
  Wizard->>XLSX: เขียนหัวคอลัมน์ + แถว
  Wizard->>ORM: สร้าง ir.attachment (binary)
  Wizard-->>User: redirect download URL

Implementation Details (Deep Dive)

POS Point เป็นโมดูลส่วนขยายของ Odoo 17 Enterprise สำหรับจัดการ Point (แต้ม) โดยรวมออเดอร์จาก Sale และ POS เข้าด้วยกัน คำนวณแต้มจากหลายกฎที่กำหนดใน Settings และแสดงใน view เดียว รองรับการ export รายการออเดอร์ที่ได้แต้มเป็นไฟล์ Excel

สถาปัตยกรรมเชิงเทคนิค

  • Backend (Python) — inherit res.partner, res.config.settings, ขยาย product.air_type (จาก sale_report_extension); สร้าง model pos.point.config, pos.point.product.price.range และ SQL view pos.sale.unified รวมข้อมูลจาก sale_order, pos_order และ account_move (out_refund)
  • กฎคำนวณแต้ม — อยู่ที่ Settings (company-scoped): วิธีชำระเงินที่อนุญาต, ออเดอร์ราคาพิเศษ/overdue นับหรือไม่, แต้มตาม Air Type, แต้มตาม Main POS Category + ช่วงราคา (price range → points), แต้มตามยอด (ทุก X บาทได้ Y แต้ม), และการยกเว้นหมวดสินค้า
  • Export — TransientModel wizard เลือกช่วงวันที่ แล้วดึง Sale/POS orders ที่จ่ายครบและผ่านกฎ จากนั้นคำนวณ point และ export เป็น XLSX (XlsxWriter)

โมดูลและ Models

โมดูลอยู่ในโครงสร้างมาตรฐาน Odoo (__manifest__.py, models, views, wizard, security):

  • res.partner — เพิ่ม our_point_code, point สำหรับลูกค้าที่ร่วมรายการสะสมแต้ม
  • product.air_type (inherit จาก sale_report_extension) — เพิ่มฟิลด์ point (company_dependent) ใช้คำนวณแต้มตามประเภทสินค้า
  • pos.point.product.price.range — ช่วงราคา (price_from, price_to) และ points; ใช้ร่วมกับ Main Point Category ในการคำนวณแต้มตามราคาขาย
  • res.config.settings — ตั้งค่ากฎคำนวณแยก Sale / POS: payment method ที่อนุญาต, special price, overdue, air type point, main category + price range, point by order amount (every THB / get point), exclude product categories; เก็บใน ir.config_parameter แยกตาม company
  • pos.sale.unified — SQL view (_auto = False) รวมออเดอร์จาก Sale, POS และ Refund เฉพาะ partner ที่มี our_point_code; มี computed fields validated_order และ point ตามกฎใน settings
# models/pos_sale_unified.py (สรุป)
class PosSaleUnified(models.Model):
    _name = "pos.sale.unified"
    _auto = False
    _order = "last_payment_date DESC, name DESC"

    order_id = fields.Char("Order ID")
    name = fields.Char("Order Ref")
    order_type = fields.Selection([("sale", "Sale"), ("pos", "POS"), ("refund", "Sale Refund")])
    partner_id = fields.Many2one("res.partner", string="Customer")
    our_point_code = fields.Char("Our Point Code")
    validated_order = fields.Boolean(compute="_compute_validated_order_and_point", ...)
    point = fields.Float(compute="_compute_validated_order_and_point", ...)
    # ... sale_order_id, pos_order_id (computed from order_type + order_id)

การคำนวณ validated_order และ point ใช้เมธอดเช่น _get_paid_sale_order, _get_paid_pos_order (กรอง payment method, down payment, overdue ตาม settings) และ _calculate_point (รวมจาก air type, main category + price range, และยอดสั่ง)

การคำนวณแต้ม

ลำดับใน _calculate_point: กรองบรรทัดออเดอร์ (ยกเว้น down payment, โอนไป POS ตามกฎ) → กรอง special price ตาม setting → คำนวณแต้มจาก Air Type → จาก Main Category + ช่วงราคา (pos.point.product.price.range) → จากยอดสั่ง (every THB / get point) รวมทั้ง refund ที่หักแต้ม

Export Log (Wizard)

Wizard pos.point.log.export.wizard กำหนดช่วงวันที่ (From/To), เลือก Partner และ Source (POS/Sale) จากนั้นเรียก export_query_excel: ดึง sale orders และ pos orders ที่จ่ายครบและผ่านกฎใน domain, เรียงตาม create_date, กรองเฉพาะที่มี our_point_code, คำนวณ point ต่อออเดอร์ แล้วเขียน Excel (หัวคอลัมน์: No., Company Name, Customer Name, Our point Code, Create Date, Mobile, Source, Order Ref., Point) และสร้าง ir.attachment แล้วส่งกลับ action download

Deployment

รันบน instance Odoo 17 Enterprise; โมดูล depend บน base, sale, point_of_sale, account, sale_report_extension, purchase, mrp. ติดตั้งผ่าน Apps แล้วอัปเดต module list ใช้ PostgreSQL ของ Odoo โดยตรง ไม่เพิ่ม service อื่น

สรุปผลลัพธ์เชิงเทคนิค

  • รายการออเดอร์จาก Sale และ POS แสดงใน view เดียว (pos.sale.unified) พร้อมสถานะ validated และจำนวนแต้ม
  • กฎคำนวณแต้มกำหนดได้แยก Sale / POS ผ่าน Settings (payment, special price, overdue, air type, main category + price range, amount-based, exclude category)
  • Export log เป็น Excel ตามช่วงวันที่และตัวกรอง สำหรับตรวจสอบหรือส่งต่อได้ทันที