การนำเข้าและ Map ข้อมูลลูกค้าเข้ากับผู้ใช้เดิม
ภาพรวม
ต่างจากการนำเข้าเพื่อสร้างผู้ใช้ใหม่ งานนี้คือการ เติมข้อมูลให้ผู้ใช้ที่มีอยู่แล้วในระบบ ลูกค้าอัปโหลดไฟล์ CSV ที่มีคอลัมน์อย่างเบอร์โทรศัพท์ อีเมล ยอดซื้อ หรือระดับสมาชิก แล้วกำหนดว่าแต่ละคอลัมน์จะ map เข้ากับฟิลด์ใดของ line_user หรือ custom attribute ตัวใด โดยจับคู่แถวเข้ากับผู้ใช้ด้วย unique key เช่นเบอร์โทรศัพท์หรือ LINE User ID
คิวนี้เป็นของใหม่ที่เกิดขึ้นในฝั่ง Go และไม่มีในระบบ NestJS เดิม จุดเด่นคือมีการตรวจความถูกต้องระดับรายเซลล์ และสร้างไฟล์ error log ให้ผู้ใช้ดาวน์โหลดไปตรวจสอบได้ว่าแถวใดไม่ผ่านและเพราะเหตุใด
Business Flow
- รับ payload ที่มีฟิลด์
importMappingJobIdหากไม่มีค่าหรือมีค่าน้อยกว่าหรือเท่ากับศูนย์ ระบบจะคืนmq.Permanentเพื่อส่งข้อความเข้า DLQ ทันทีโดยไม่ retry - โหลดแถว
import_mapping_jobพร้อม join ตารางline_oaเพื่อเอาline_oa_hashไว้ใช้ประกอบ path ตอนอัปโหลด error log - อ่านไฟล์ CSV จาก S3 แล้วอ่านแถว header เพื่อระบุตำแหน่งของแต่ละคอลัมน์
buildLookupสร้าง map จากค่า unique key ไปยังline_user.idโดยรองรับ key สองรูปแบบ คือแบบอ้างฟิลด์ตรง เช่นfield.mobile_no,field.emailหรือuser_idและแบบอ้าง custom attribute- วนประมวลผลทีละแถวผ่าน
processRowโดยแบ่งเป็น chunk ละ 500 แถว พร้อมรายงานความคืบหน้าระหว่างทาง- ค้นหา
line_userจาก lookup ที่สร้างไว้ หากไม่พบจะข้ามแถวนั้นพร้อมบันทึกเหตุผล - ตรวจความถูกต้องของค่าตามชนิดคอลัมน์ โดย
field.emailต้องตรงกับ regular expression^[^\s@]+@[^\s@]+\.[^\s@]+$ส่วนfield.mobile_noเมื่อตัดช่องว่างและเครื่องหมายขีดออกแล้วต้องเป็นตัวเลข 9 ถึง 10 หลัก - เขียนค่าลงคอลัมน์โดยตรง หรือ merge เข้าไปในคอลัมน์
line_user.custom_attributeซึ่งเป็น jsonb
- ค้นหา
uploadErrorLogจะทำงานเมื่อมีแถวที่ถูกข้าม โดยสร้างไฟล์ CSV รวมรายการที่ไม่ผ่านพร้อมสาเหตุ แล้วอัปโหลดขึ้น S3 ที่private/<lineOaHash>/import-mapping/error_<jobId>.csvfinalizeJobเขียนสถานะสุดท้าย สถิติ (Stats) สรุปสาเหตุที่ข้ามเรียงตามจำนวนผ่านsortedReasonsและ path ของ error log กลับลงแถว job- เนื่องจาก service จัดการขั้นตอน finalize ด้วยตัวเอง จึงคืนค่า error เฉพาะกรณีที่การ retry ยังมีโอกาสสำเร็จเท่านั้น
ไฟล์และฟังก์ชันหลัก
internal/importmapping/service.goService.ProcessImportMappingJob(ctx, payload)— entry pointrun(),processRow(),buildLookup(),parseTarget(),validateFieldValue(),normalizeIdentifier(),stripPhone()uploadErrorLog(),finalizeJob(),findJobByID(),sortedReasons()- ค่าคงที่ที่สำคัญ:
chunkSizeเท่ากับ 500,folderImportMappingErrorมีค่าเป็นimport-mappingรวมถึงemailPatternและphonePattern
internal/importmapping/consumer.go—Consumer.HandleImportMappingJobและRegister()internal/importmapping/types.go— นิยามชนิดImportMappingJobPayload,Stats,ReasonCountและskippedRow- คิวที่เกี่ยวข้อง:
import_mapping_job(runtime profilemain)
จุดเชื่อมต่อกับ Service อื่น
- ต้นทางของงาน — cms-api-go จากหน้า import mapping ของ CMS
- ฐานข้อมูล —
import_mapping_job(สถานะ สถิติ และ path ของ error log),line_user(UPDATE ทั้งคอลัมน์ตรงและcustom_attributeแบบ jsonb) และline_oa(ใช้ hash ประกอบ path บน S3) - S3 — อ่านไฟล์ CSV ต้นทาง และเขียนไฟล์ error log
- ไม่เรียก LINE API เพราะงานนี้ทำงานกับผู้ใช้ที่มีข้อมูลอยู่แล้วเท่านั้น
- ใช้
Storageinterface ตัวเดียวกับงานนำเข้ารายชื่อผู้ใช้จาก CSV ผ่าน adapterlineUserStorageในcmd/worker/integration.go