โครงสร้างข้อมูลและรหัสอ้างอิง
รหัสสี่ตัวยึด API นี้ไว้ด้วยกัน คือแฟรนไชส์ ร้าน แบรนด์สมาชิก และบิล เข้าใจสี่ตัวนี้ถูก ที่เหลือทั้งเครื่อง สถานี รายการสินค้า คูปอง และช่องทางขาย จะห้อยตามมาเอง
แผนที่ข้อมูล
หัวข้อที่มีชื่อว่า “แผนที่ข้อมูล”franchiseId ─┬─ shopId ─┬─ รหัสบิล ──── items[] │ │ │ ├─ deviceId · stationId (มีบนทุกบิล) │ │ │ └─ providerId ─── memberId (m1_…) ─── coupons[] │ ▲ └─ … สาขาอื่น │ บิลที่ผูกสมาชิก ────────┘ (transaction.memberId คือค่าเดียวกัน)GET /v1/shopsคือจุดเริ่มต้นเสมอ เพราะมันคืนshopIdfranchiseIdและproviderIdของทุกสาขาที่กุญแจอ่านได้ ไม่มีเส้นอื่นที่ต้องอธิบายความสัมพันธ์นี้อีกfranchiseIdกับproviderIdเป็นคนละแกน ทั้งคู่บันทึกอยู่บนตัวร้าน ตัวหนึ่งคือโครงสร้างธุรกิจ อีกตัวคือฐานข้อมูลสมาชิก หลายสาขาใช้แบรนด์สมาชิกร่วมกันได้โดยไม่ต้องอยู่แฟรนไชส์เดียวกัน จึงห้ามอนุมานตัวหนึ่งจากอีกตัวหนึ่ง- บิลหนึ่งใบเป็นของร้านเดียวเท่านั้น และพก
franchiseIddeviceIdstationIdมาด้วย คุณจึงรวมยอดข้ามสาขาหรือแยกตามเครื่องได้โดยไม่ต้องยิงคำขอที่สอง - สมาชิกเป็นของแบรนด์ ไม่ใช่ของสาขา ข้อมูลสมาชิกกำหนดขอบเขตด้วย
providerIdและไม่มีช่องร้านอยู่บนตัวสมาชิก
รหัสอ้างอิง
หัวข้อที่มีชื่อว่า “รหัสอ้างอิง”| รหัส | ได้มาจากไหน | รูปแบบ | เอาไปทำอะไร |
|---|---|---|---|
franchiseId |
GET /v1/shops และบนทุกบิล |
สตริงทึบ เป็น null ถ้าเป็นร้านเดี่ยว |
จัดกลุ่มสาขา |
shopId |
GET /v1/shops |
สตริงทึบ | ต้องใช้กับ GET /v1/transactions |
providerId |
GET /v1/shops |
สตริงทึบ เป็น null ถ้าร้านไม่ได้ทำระบบสมาชิก |
ต้องใช้กับ GET /v1/members |
รหัสบิล id |
ช่อง data[].id ของลิสต์บิล |
สตริงทึบ | ใช้กับ GET /v1/transactions/{id} และใช้เป็น cursor ของเส้นนั้น |
deviceId stationId |
บนทุกบิล | สตริงทึบ หรือ null |
แยกยอดขายตามเครื่อง |
memberId |
บนตัวสมาชิก บนบิลที่สมาชิกเป็นคนจ่าย และจาก GET /v1/members/lookup |
m1_ ตามด้วยค่าที่เข้ารหัสแล้ว |
ใช้กับ GET /v1/members/{memberToken} และใช้จับคู่บิลกับสมาชิก |
items[].category categories[].id |
อยู่ในบิล · และรายชื่อของร้านใน GET /v1/shops |
สตริงทึบ | แปลงรหัสหมวดของรายการที่ขายเป็นชื่อ — จับคู่ id ภายใน shopId เดียวกัน · รหัสที่หาไม่เจอ = หมวดที่ถูกลบแล้ว |
items[].id items[].rootId |
อยู่ในบิล | สตริงทึบ หรือ null |
จับคู่รายการที่ขายกับแคตตาล็อกของคุณ ส่วน rootId คือตัวเชื่อมเมนูของสาขากลับไปยังเมนูต้นแบบของสำนักงานใหญ่ในระบบแฟรนไชส์ ร้านเดี่ยวจะเป็น null และไม่ใช่สินค้าแม่ของตัวเลือกย่อยหรือสินค้าในชุด |
ทุกตัวข้างบนเป็นค่าทึบ ให้ปฏิบัติกับมันเป็นสตริง เก็บความยาวและตัวพิมพ์ไว้ให้ตรงเป๊ะ อย่าสร้างขึ้นเอง และอย่าตีความหมายจากตัวอักษรข้างใน
token ของสมาชิกมีเรื่องที่ต้องบอกเพิ่ม มันไม่ใช่รหัสภายในของระเบียนสมาชิก เพราะรหัสนั้นได้มาจากบัญชีแชตของบุคคลจริง จึงไม่ถูกส่งออกไปไหน สิ่งที่คุณได้คือ token ที่
- เสถียร สมาชิกคนเดิมได้ token เดิมเสมอ จึงเก็บเป็นคีย์อ้างอิง ใช้เป็นคีย์ของรายการ หรือใช้จับคู่กับบิลได้อย่างปลอดภัย
- เหมือนกันทั้งระบบ token ไม่เปลี่ยนตามกุญแจหรือตามสาขา สองร้านในแฟรนไชส์เดียวกันจึงเห็นค่าเดียวกันสำหรับคนคนเดียวกัน
- ย้อนกลับไม่ได้ แปลงกลับเป็นตัวตนจริงจากนอก ScanFood ไม่ได้
- บอกรุ่นด้วยคำนำหน้า วันนี้ทุก token ขึ้นต้นด้วย
m1_ถ้าวันหลังมีการหมุนกุญแจเข้ารหัส จะกลายเป็นm2_ให้ตรวจที่คำนำหน้า อย่ายึดความยาวตายตัว
คุณหยิบ memberId จากบิลไปเรียก GET /v1/members/{memberToken} ได้เลย ไม่ต้องมีตารางแปลง
ถ้าสมาชิกคนนั้นอยู่ในแบรนด์ที่กุญแจของคุณอ่านไม่ได้ คำตอบคือ 404
ยังมีอีกทางหนึ่งที่จะได้ token มา ถ้าคุณมี LINE user id ของลูกค้าอยู่แล้ว
จากบอทหรือ LIFF ของคุณเอง GET /v1/members/lookup จะแลกมันเป็น memberId ของคนนั้นให้
เฉพาะกุญแจที่เปิดสิทธิ์การค้นนี้ไว้ การแลกเดินทางเดียวคือส่ง id เข้าไปแล้วได้ token กลับมา
และไม่มี response ไหนส่ง LINE user id กลับออกไป ดูรายละเอียดที่
สมาชิก
จำนวนเงิน
หัวข้อที่มีชื่อว่า “จำนวนเงิน”จำนวนเงินทุกช่องเป็น เงินบาท ในรูปตัวเลขธรรมดา ไม่มีช่องบอกสกุลเงิน ไม่ใช่หน่วยย่อย และไม่ใช่สตริง
ยอดระดับบิลอยู่ใน amounts และมีสี่กติกา
amounts.netคือยอดที่ลูกค้าจ่ายจริง รวมทิปแล้ว ถ้าจะเรียกว่ายอดขายของร้าน ต้องหักamounts.tipออกก่อน เพราะทิปเป็นของพนักงานnullไม่เท่ากับ0nullแปลว่า “ไม่เกี่ยวกับบิลนี้” คือร้านปิดฟีเจอร์นั้น หรือไม่เคยมีการเขียนค่าลงไป ส่วน0แปลว่าเปิดใช้อยู่และค่าเป็นศูนย์พอดี อย่ารวมสองอย่างนี้เข้าด้วยกันตอนคิดยอดamounts.vatTypeบอกว่า VAT อยู่ในราคาอย่างไร"Include"คือราคารวม VAT แล้ว และถอด VAT ออกจากยอด ส่วน"Exclude"คือบวก VAT ท้ายบิล อ่านค่านี้ก่อนคำนวณตัวเลขภาษีใหม่เสมอ- ส่วนลดบันทึกที่ระดับบิล ไม่ได้กระจายลงรายบรรทัด
amounts.discountคือส่วนลดที่แคชเชียร์กดเองamounts.campaignและamounts.couponคือรายการโปรโมชันและคูปองที่ใช้ ส่วนamounts.discountTotalคือยอดที่ลดจริง รายการสินค้าไม่มีช่องส่วนลดต่อบรรทัด ถ้าต้องการยอดสุทธิรายบรรทัด ต้องเฉลี่ยเอง
รายการสินค้าแต่ละบรรทัดมี qty unitPrice (ราคาที่คิดจริง) lineTotal
ตัวเลือกที่ลูกค้าเลือก รหัสหมวดสินค้า ณ เวลาที่ขาย และธง cancelled vat isTip
ทิปที่ถูกกดเป็นรายการหนึ่งบรรทัดจะมี isTip: true ให้ตัดบรรทัดเหล่านั้นออกจากการวิเคราะห์สินค้า
payments[] แยกการรับเงินตามช่องทาง เพราะบิลใบเดียวแบ่งจ่ายหลายช่องทางได้
ยอดในนั้นมากกว่า net ได้ เมื่อลูกค้าจ่ายเงินสดแล้วรับเงินทอน
ช่องทางการขาย
หัวข้อที่มีชื่อว่า “ช่องทางการขาย”channel บอกว่าออเดอร์นั้นมาถึงครัวได้อย่างไร
code |
หมายความว่า |
|---|---|
dine_in |
นั่งกินที่ร้าน รวมถึงการขายหน้าร้านที่ไม่ได้ระบุโต๊ะด้วย |
take_away |
สั่งที่เคาน์เตอร์แล้วซื้อกลับบ้าน |
pickup |
ลูกค้าสั่งเองเพื่อมารับ ส่วนใหญ่ผ่าน QR หรือลิงก์ |
| รหัสที่ร้านตั้งเอง | ช่องทางที่ร้านตั้งค่าเอง เช่น แอปเดลิเวอรี มาร์เกตเพลส หรือโทรสั่ง |
null |
บิลนั้นไม่ได้บันทึกช่องทางไว้ |
ฟิลด์ที่ไม่ควรยึด
หัวข้อที่มีชื่อว่า “ฟิลด์ที่ไม่ควรยึด”บางอย่างไม่ถูกส่งออกโดยเจตนา และบางอย่างส่งออกแต่ไม่เสถียร
ไม่ส่งออกเลย โดยนโยบาย
- ต้นทุนและสูตรอาหาร ต้นทุนต่อหน่วย สูตรวัตถุดิบ และการตัดสต็อก อยู่ใน ScanFood เท่านั้น
- ตัวตนของลูกค้าบนบิล ชื่อ เบอร์โทร ที่อยู่ โน้ตท้ายบิล และสลิปที่อัปโหลด ไม่ได้เป็นส่วนหนึ่งของบิลที่ส่งออก
- ตัวตนของสมาชิก ชื่อ วันเกิด เพศ รูปภาพ ประวัติแต้มดิบ และประวัติการมาใช้บริการ
ไม่ถูกส่งออกเลย สิ่งที่ได้คือค่าจริงเท็จ
hasTelhasEmailhasLineส่วนเบอร์โทรและอีเมลตัวจริงจะเปิดให้เฉพาะกุญแจที่ได้รับอนุมัติไว้แล้วเท่านั้น - ช่องที่ใช้ภายใน การอ้างอิงกะและผู้จัดการ การอ้างอิงเกตเวย์รับเงิน และสถานะระบบบัญชี
ส่งออก แต่อย่าเอาไปเขียนเป็นเงื่อนไข
- ข้อความ
messageในข้อผิดพลาด ให้แตกสาขาที่รหัสerrorแทน - จำนวนช่องข้อมูลในออบเจกต์ ภายใน
/v1/มีการเพิ่มช่องได้ ให้มองข้ามสิ่งที่ยังไม่รู้จัก channel.nametableNameและcashierทั้งหมดนี้คือสิ่งที่พนักงานพิมพ์เอง และพนักงานเปลี่ยนชื่อกันเป็นเรื่องปกติ ให้จับคู่ด้วยรหัส แล้วใช้ชื่อไว้แสดงผลrankLevelมีความหมายเฉพาะเมื่อแบรนด์นั้นเปิดการเลื่อนระดับอัตโนมัติ ถ้าจะแสดงผลให้ใช้rankNamebusinessDateเป็นnullได้ในบิลที่ไม่ได้ปิดผ่านเส้นทาง POS ปัจจุบัน ดู เขตเวลาและวันธุรกิจ