ข้ามไปเนื้อหาหลัก

เอกสารซื้อ

ใบขอซื้อ ใบสั่งซื้อ ใบรับสินค้า ใบแจ้งหนี้ซื้อ และใบสำคัญจ่าย

สายเอกสารซื้อคล้ายกับสายเอกสารขาย แต่มีสองข้อที่ต้องรู้ก่อนเริ่ม คือ วันที่เป็น Unix timestamp ไม่ใช่สตริงวันที่ และ ทุก response ห่อด้วย data

รหัสเอกสาร
PRใบขอซื้อ
POใบสั่งซื้อ
GRใบรับสินค้า
PIใบแจ้งหนี้ซื้อ
PVใบสำคัญจ่าย

สร้างเอกสาร

POST /purchase/documents → 201 { "success": true, "data": { … } }

ต้องระบุ docType, docDate, currency และรายการอย่างน้อยหนึ่งรายการ แต่ละรายการต้องมี description, unit และ quantity มากกว่าศูนย์

bash
curl -X POST "$ABSERP_API_URL/openapi/v1/purchase/documents" \
  -H "Authorization: Bearer $ABSERP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "docType": "PO",
    "docDate": 1757289600,
    "dueDate": 1759881600,
    "contactId": 7,
    "currency": "THB",
    "notes": "เติมสต็อกสำหรับโปรโมชันเดือนกันยายน",
    "items": [
      {
        "productId": 5,
        "description": "Widget",
        "unit": "ชิ้น",
        "quantity": 100,
        "unitPrice": 250,
        "discountPercent": 0,
        "taxRate": 7
      }
    ]
  }'

ฟิลด์ระดับเอกสาร

ฟิลด์ชนิดจำเป็นหมายเหตุ
docTypestringใช่หนึ่งในห้ารหัสด้านบน
docDateintegerใช่Unix seconds เช่น 1757289600
currencystringใช่รหัส 3 ตัวอักษร — จำเป็นในฝั่งซื้อ ต่างจากเอกสารขาย
itemsarrayใช่อย่างน้อยหนึ่งรายการ
dueDateintegerไม่Unix seconds
contactIdintegerไม่ผู้ขาย ไม่บังคับใน PR เพราะอาจยังไม่ทราบผู้ขาย
refDocId / refDocTypeinteger / stringไม่เชื่อมเอกสารนี้กับเอกสารก่อนหน้าในสาย
notesstringไม่แสดงบนเอกสาร
internalNotesstringไม่ไม่แสดงบนเอกสาร
whtRatenumberไม่เปอร์เซ็นต์ภาษีหัก ณ ที่จ่าย 0–100
whtAmountnumberไม่จำนวนเงินภาษีหัก ณ ที่จ่าย
whtSectionstringไม่ข้อความอิสระไม่เกิน 50 ตัวอักษร เช่น SERVICE, RENT
bankIdintegerไม่ใช้กับ PV เท่านั้น — บัญชีที่เงินออก ส่งกับชนิดอื่นจะได้ 400

ฟิลด์รายบรรทัด

ฟิลด์ชนิดจำเป็นหมายเหตุ
descriptionstringใช่ข้อความรายการ
unitstringใช่ไม่เกิน 20 ตัวอักษร
quantitynumberใช่มากกว่าศูนย์
productIdintegerไม่เชื่อมกับสินค้าเพื่อให้สต็อกและต้นทุนเคลื่อนไหวเมื่อ GR ถูก post
productAltUnitIdintegerไม่ซื้อด้วยหน่วยทางเลือก
unitPricenumberไม่ค่าเริ่มต้น 0
discountPercentnumberไม่0–100
taxRatenumberไม่เปอร์เซ็นต์ 0–100 รายบรรทัด ต่างจากฝั่งขายที่ VAT เป็นอัตราเดียวระดับเอกสาร
accountIdintegerไม่กำหนดบัญชีค่าใช้จ่ายของบรรทัดนี้เอง

ข้อมูลที่คืนกลับ

json
{
  "success": true,
  "data": {
    "id": 18,
    "docNumber": "PO-2026-0001",
    "docType": "PO",
    "docDate": 1757289600,
    "dueDate": 1759881600,
    "contactId": 7,
    "contactName": "บริษัท ซัพพลายเออร์ จำกัด",
    "status": "draft",
    "subtotal": 25000,
    "discountAmount": 0,
    "taxAmount": 1750,
    "totalAmount": 26750,
    "paidAmount": 0,
    "currency": "THB",
    "createdBy": 3,
    "createdByName": "สมหญิง ใจดี",
    "approvedBy": null,
    "approvedAt": null,
    "items": [
      {
        "id": 55,
        "productId": 5,
        "productName": "Widget",
        "description": "Widget",
        "unit": "ชิ้น",
        "quantity": 100,
        "receivedQuantity": 0,
        "unitPrice": 250,
        "taxRate": 7,
        "taxAmount": 1750,
        "lineTotal": 26750
      }
    ],
    "statusHistories": [
      {
        "fromStatus": null,
        "toStatus": "draft",
        "changedBy": 3,
        "changedByName": "สมหญิง ใจดี",
        "createdAt": 1757289600
      }
    ],
    "paymentAllocations": []
  }
}

receivedQuantity ในบรรทัดของ PO คือจำนวนที่รับเข้ามาแล้วผ่านใบรับสินค้า เป็นค่าที่ควรอ่านเพื่อแยกใบสั่งซื้อที่รับของครบจากที่รับของบางส่วน

ค้นหาเอกสาร

GET /purchase/documents → แบ่งหน้า อยู่ใน data

พารามิเตอร์หมายเหตุ
docTypeหนึ่งใน PR, PO, GR, PI, PV
contactIdรหัสผู้ขาย
statusกรองตามสถานะ
fromDate / toDateUnix seconds อ้างอิงวันที่เอกสาร
searchค้นจากเลขที่เอกสารและชื่อผู้ขาย
page / limitดูการแบ่งหน้า
bash
curl -X GET "$ABSERP_API_URL/openapi/v1/purchase/documents?docType=PO&status=sent&limit=100" \
  -H "Authorization: Bearer $ABSERP_API_KEY"

อ่านเอกสารรายฉบับ

GET /purchase/documents/{id} → คืนเอกสารใน data พร้อม items, statusHistories และ paymentAllocations

แก้ไขเอกสาร

PATCH /purchase/documents/{id} → คืนเอกสารที่แก้แล้วใน data

แก้ได้ที่ docDate, dueDate, contactId, notes, internalNotes, ฟิลด์ภาษีหัก ณ ที่จ่าย, bankId และ items แต่ docType แก้ไม่ได้ ใบสั่งซื้อไม่สามารถกลายเป็นใบรับสินค้า ให้สร้างเอกสารถัดไปในสายแล้วอ้างอิงเอกสารนี้ด้วย refDocId / refDocType

เปลี่ยนสถานะ

PATCH /purchase/documents/{id}/status → คืนเอกสารที่แก้แล้วใน data

bash
curl -X PATCH "$ABSERP_API_URL/openapi/v1/purchase/documents/18/status" \
  -H "Authorization: Bearer $ABSERP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "status": "sent", "note": "ส่งให้ผู้ขายแล้ว" }'

ฟิลด์หมายเหตุของฝั่งซื้อชื่อ note ขณะที่เอกสารขายใช้ remark การเปลี่ยนสถานะที่อนุญาตของแต่ละชนิดอยู่ในข้อมูลอ้างอิงชนิดเอกสาร การเปลี่ยนที่ไม่อนุญาตจะได้ 400 และไม่มีอะไรเปลี่ยน

ต่างจากฝั่งขาย endpoint นี้คืน เอกสารทั้งฉบับที่อัปเดตแล้ว จึงไม่ต้องเรียกอ่านอีกครั้งเพื่อดูยอดหรือประวัติใหม่

ลบเอกสาร

DELETE /purchase/documents/{id} → 204 No Content

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

ตัวอย่างสายงานเต็มรอบ

การเติมสต็อกตั้งแต่ต้นจนจบ

  1. POST /purchase/documents ด้วย docType: "PO" → ได้ id 18 สถานะ draft
  2. PATCH /purchase/documents/18/status เป็น sent แล้วเป็น acknowledged เมื่อผู้ขายยืนยัน
  3. ของมาถึง: POST /purchase/documents ด้วย docType: "GR", refDocId: 18, refDocType: "PO" และจำนวนที่รับจริง
  4. PATCH ใบ GR เป็น posted — สต็อกและต้นทุนเฉลี่ยเคลื่อนไหวที่ขั้นนี้
  5. ใบแจ้งหนี้มาถึง: docType: "PI" อ้างอิงใบ GR แล้ว PATCH เป็น matched และ approved
  6. จ่ายเงิน: docType: "PV" พร้อม bankId แล้ว PATCH เป็น approved และ paid

หากระบบของคุณต้องตอบสนองเมื่อผู้ขายยืนยัน ให้เรียก GET /purchase/documents?docType=PO&status=acknowledged เป็นระยะตั้งแต่ขั้นที่ 2 เป็นต้นไป

รหัสข้อผิดพลาด

เอกสารซื้อใช้รหัสทั่วไป 400 BadRequest / 404 NotFound / 500 InternalError จากข้อผิดพลาดและการแบ่งหน้า กับความผิดพลาดส่วนใหญ่ รวมถึงการเปลี่ยนสถานะที่ไม่อนุญาตด้วย ซึ่งฝั่งนี้จะได้ 400 BadRequest ธรรมดา ไม่ใช่รหัส InvalidStatusTransition เฉพาะแบบที่เอกสารขายใช้ ให้อ่าน errorDescription เพื่อดูสาเหตุ ส่วนการเปลี่ยนสถานะที่อนุญาตอยู่ในข้อมูลอ้างอิงชนิดเอกสาร

มีบางกรณีที่ได้รหัสเฉพาะ

สถานะรหัสสาเหตุ
400BankNotFoundไม่พบ bankId ในองค์กรนี้
400BankNotAllowedForDocumentTypeส่ง bankId กับชนิดเอกสารที่ไม่ใช่ PV
400NoDefaultWarehouseยืนยันใบรับสินค้า (GR → posted) โดยไม่มี warehouseId และองค์กรยังไม่ได้ตั้งค่าคลังเริ่มต้น
422NegativeStockBlockedยกเลิกใบรับสินค้าที่ยืนยันแล้วซึ่งสต็อกที่รับเข้ามาถูกใช้ไปที่อื่นบางส่วนแล้ว

ขั้นตอนถัดไป

อ่านต่อที่ เรื่องเบิกค่าใช้จ่าย