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

ผู้ติดต่อ

ลูกค้าและผู้ขาย — รหัสที่เอกสารขายและเอกสารซื้อทุกฉบับต้องใช้

ผู้ติดต่อคือลูกค้า ผู้ขาย หรือทั้งสองอย่าง เอกสารขายอ้างอิงผู้ติดต่อผ่าน contactId เอกสารซื้อก็เช่นกัน โดยทั่วไปนี่คือข้อมูลชุดแรกที่ระบบเชื่อมต่อจะต้องซิงก์

กลุ่มนี้มีสองเรื่องที่ต่างจากส่วนอื่นของ API

  • การอ่านคืน object ตรง ๆ ไม่ห่อด้วย data
  • การเขียนใช้ multipart/form-data ไม่ใช่ JSON เพราะ endpoint นี้เดิมออกแบบมาให้อัปโหลดไฟล์ในเว็บแอป ABSERP ได้ สัญญาของฟอร์มใน Open API จึงเป็นแบบเดียวกัน แต่ตัว Open API เองไม่เปิดให้อัปโหลดไฟล์เหล่านั้น (ดูด้านล่าง) หากต้องการตั้งรูปประจำตัวให้ใช้ avatarUrl แทน

สามเส้นทางเข้าถึงข้อมูลชุดเดียวกัน

กลุ่มพฤติกรรมของการค้นหาและสร้าง
/contactsทั้งหมด กำหนด contactType ได้เอง
/customersบังคับ contactType: "client" ทั้งการค้นหาและการสร้าง — ตอนสร้างไม่ต้องส่ง contactType เอง ค่าที่ส่งมาจะถูกละเลย
/vendorsบังคับ contactType: "supplier" ทั้งการค้นหาและการสร้าง — ตอนสร้างไม่ต้องส่ง contactType เอง ค่าที่ส่งมาจะถูกละเลย

การดำเนินการกับ {id} ใช้ร่วมกัน GET /customers/9 และ GET /contacts/9 คืนแถวเดียวกัน ควรใช้เส้นทางย่อเมื่อโค้ดส่วนนั้นทำงานกับด้านเดียวอยู่แล้ว เพราะช่วยตัดตัวกรองที่ต้องจำออกไปหนึ่งตัว

ค้นหาผู้ติดต่อ

GET /contacts → แบ่งหน้า คืน ตรง ๆ

พารามิเตอร์หมายเหตุ
searchค้นจากรหัส ชื่อ เลขผู้เสียภาษี อีเมล และเบอร์โทร
contactTypeclient, supplier หรือ both
isActivetrue / false
isDeletedtrue เพื่อดูแถวที่ลบแบบ soft delete
page / limitดูการแบ่งหน้า

ชื่อพารามิเตอร์คือ contactType ไม่ใช่ type

bash
curl -X GET "$ABSERP_API_URL/openapi/v1/contacts?contactType=client&isActive=true&limit=100" \
  -H "Authorization: Bearer $ABSERP_API_KEY"
json
{
  "items": [
    {
      "id": 12,
      "code": "CUST-001",
      "name": "บริษัท เอซีเอ็มอี จำกัด",
      "businessType": "corporation",
      "taxId": "0105551234567",
      "branchType": "head_office",
      "branchCode": "00000",
      "contactType": "client",
      "contactName": "สมชาย ใจดี",
      "email": "[email protected]",
      "phone": "021234567",
      "address": "…",
      "creditDays": 30,
      "creditLimit": 100000,
      "paymentTermDays": 30,
      "currency": "THB",
      "bank": null,
      "isActive": true,
      "createdAt": 1735689600
    }
  ],
  "pagination": {
    "previousPage": null,
    "currentPage": 1,
    "nextPage": null,
    "totalPages": 1,
    "totalRows": 1
  }
}

ค้นหาผู้ติดต่อที่คุณมีข้อมูลอยู่แล้ว

ไม่มี endpoint แบบ "ค้นด้วยเลขผู้เสียภาษี" หากต้องการจับคู่ลูกค้าที่มีอยู่ในระบบของคุณ ให้ค้นด้วยค่าที่คุณเชื่อถือมากที่สุดแล้วตรวจผลลัพธ์

bash
curl -X GET "$ABSERP_API_URL/openapi/v1/contacts?search=0105551234567&contactType=client" \
  -H "Authorization: Bearer $ABSERP_API_KEY"

จากนั้นเก็บ id ที่ได้ผูกกับข้อมูลฝั่งคุณ การค้นครั้งเดียวแล้วเก็บ id ไว้ประหยัดกว่าการค้นก่อนสร้างเอกสารทุกครั้งมาก และช่วยกันการสร้างข้อมูลซ้ำเมื่อชื่อสะกดต่างกันเล็กน้อย

สร้างผู้ติดต่อ

POST /contacts → 201 คืนผู้ติดต่อที่สร้างแล้ว ตรง ๆ โครงสร้างเดียวกับ GET /contacts/{id} (id, code, name, contactType, businessType, taxId, email, phone, creditDays, creditLimit, paymentTermDays, currency, isActive, createdAt, …)

เก็บ id จาก response นี้ไว้ใช้ต่อได้ทันที ไม่ต้องเรียกรายการพร้อม search เพื่อหา id ซ้ำอีก

body เป็น multipart/form-data ฟิลด์ที่จำเป็นคือ name และ contactType

bash
curl -X POST "$ABSERP_API_URL/openapi/v1/contacts" \
  -H "Authorization: Bearer $ABSERP_API_KEY" \
  -F "name=บริษัท เอซีเอ็มอี จำกัด" \
  -F "contactType=client" \
  -F "businessType=corporation" \
  -F "taxId=0105551234567" \
  -F "branchType=head_office" \
  -F "branchCode=00000" \
  -F "contactName=สมชาย ใจดี" \
  -F "[email protected]" \
  -F "phone=021234567" \
  -F "creditDays=30" \
  -F "currency=THB"

การส่ง endpoint นี้เป็น JSON เป็นความผิดพลาดที่พบมากที่สุด เพราะ request จะผ่านเข้าไปได้ แต่ทุกฟิลด์จะว่าง และคุณจะได้ข้อผิดพลาดว่า name จำเป็น

ฟิลด์

ฟิลด์จำเป็นหมายเหตุ
nameใช่ไม่เกิน 255 ตัวอักษร
contactTypeใช่ เฉพาะ /contactsclient, supplier หรือ both — สร้างผ่าน /customers หรือ /vendors ไม่ต้องส่งฟิลด์นี้ ระบบตั้งค่าให้เองและไม่สนใจค่าที่ส่งมา
businessTypeไม่corporation หรือ individual
taxIdไม่ไม่เกิน 20 ตัวอักษร
branchTypeไม่head_office หรือ branch
branchCodeไม่ไม่เกิน 10 ตัวอักษร เช่น 00000 สำหรับสำนักงานใหญ่
branchNameไม่ไม่เกิน 100 ตัวอักษร
contactNameไม่ชื่อผู้ที่ติดต่อได้
email, phone, websiteไม่phone ไม่เกิน 30 ตัวอักษร
telegram, lineId, whatsappId, discordIdไม่บัญชีแอปแชท
addressไม่ที่อยู่สำหรับออกเอกสาร
shippingInfoไม่ที่อยู่จัดส่ง
creditDaysไม่จำนวนเต็ม
creditLimitไม่ต้องเป็น 0 หรือมากกว่า
paymentTermDaysไม่จำนวนเต็ม
currencyไม่3 ตัวอักษรพอดี
remarkไม่หมายเหตุภายใน
avatarUrlไม่URL รูปประจำตัวของผู้ติดต่อ

การ อัปโหลดไฟล์ รูปประจำตัวและรูป QR บัญชีธนาคารไม่ได้เป็นส่วนหนึ่งของ API นี้ ตั้งค่าได้จากเว็บแอป ABSERP เท่านั้น หากต้องการตั้งรูปประจำตัวจากระบบที่เชื่อมต่อ ให้ส่ง avatarUrl แทน

ข้อมูลธนาคารส่งในฟอร์มเดียวกัน ได้แก่ bankCompany, accountNo, accountName, accountType, accountBranch, accountBranchCode, swiftCode (ไม่เกิน 11) และ bankAddress เวลาอ่านจะคืนซ้อนอยู่ใต้คีย์ bank

code (CUST-001, VD-001) ระบบ ABSERP กำหนดให้ ตั้งเองไม่ได้

อ่านผู้ติดต่อรายรายการ

GET /contacts/{id} → คืนผู้ติดต่อ ตรง ๆ

GET /contacts/{id}/credit-usage ไม่เปิดให้ใช้ผ่าน Open API (ใช้ได้ในเว็บแอปเท่านั้น) ค่า creditLimit และ creditDays อยู่บนตัวผู้ติดต่ออยู่แล้ว หากขั้นตอนงานของคุณต้องคุมวงเงินเครดิต ให้คำนวณยอดที่ใช้ไปจากใบแจ้งหนี้ที่ดึงผ่าน GET /sales/documents เพราะ endpoint เอกสารขายจะไม่ตรวจให้

แก้ไขผู้ติดต่อ

PATCH /contacts/{id} → { "success": true, "message": "…" }

ฟิลด์เหมือนตอนสร้างทั้งหมดแต่ไม่บังคับ และเพิ่ม isActive เข้ามา ใช้ multipart/form-data เช่นเดียวกัน

ส่งเฉพาะฟิลด์ที่เปลี่ยน ฟิลด์ที่ไม่ส่งจะคงค่าเดิม ฟิลด์ที่ส่งเป็นค่าว่างจะถูกล้าง

ลบและกู้คืน

DELETE /contacts/{id} ลบแบบ soft delete เอกสารที่อ้างอิงผู้ติดต่ออยู่แล้วยังทำงานได้ตามปกติ ซึ่งเป็นเหตุผลที่การลบเป็นแบบ soft delete และการดึงรายการด้วย isDeleted=true ยังเห็นแถวนั้นอยู่

การกู้คืน (PATCH /contacts/{id}/restore) ไม่เปิดให้ใช้ผ่าน Open API (ใช้ได้ในเว็บแอปเท่านั้น) ผู้ติดต่อที่ลบแล้วต้องกู้คืนจากใน ABSERP

โดยทั่วไปการปิดใช้งาน (isActive: false) เหมาะกว่าอยู่แล้ว เพราะผู้ติดต่อจะไม่ปรากฏในตัวเลือกอีก ข้อมูลยังอยู่ครบ และเปิดใช้งานกลับได้ผ่าน PATCH /contacts/{id}

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

สถานะรหัสสาเหตุ
400BadRequestขาด name/contactType หรือค่า enum ไม่ถูกต้อง (businessType, branchType, contactType, currency ที่ไม่ใช่ 3 ตัวอักษรพอดี) ตอนสร้างหรือแก้ไข
404NotFoundไม่พบ :id ในองค์กรนี้

ไม่มีรหัสข้อมูลซ้ำ/ขัดแย้งโดยเฉพาะสำหรับผู้ติดต่อ taxId, phone หรือ email ที่ตรงกับผู้ติดต่อที่มีอยู่แล้วระบบจะรับไว้ ไม่ปฏิเสธ ส่วน code (CUST-001) ระบบ ABSERP กำหนดให้เองจึงชนกันไม่ได้

FileSizeExceeded และ FileTypeError มีอยู่ใน endpoint ต้นทางสำหรับการอัปโหลดรูปประจำตัวและรูป QR บัญชีธนาคาร แต่ฟิลด์เหล่านั้นไม่ได้เป็นส่วนหนึ่งของสัญญา Open API ที่เอกสารนี้ระบุ (ดู "ฟิลด์" ด้านบน) หากส่ง avatarUrl ตามที่เอกสารนี้แนะนำ คุณจะไม่พบรหัสทั้งสองนี้

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

อ่านต่อที่ สินค้าและคลังสินค้า