ขายสินค้า (POS)
ทำรายการขาย สแกนบาร์โค้ด และรับชำระเงินรายการสินค้าในตะกร้า
| สินค้า | ราคาหน่วย | จำนวน | รวม |
|---|
ยังไม่มีสินค้าในตะกร้า สแกนบาร์โค้ดหรือเลือกสินค้าจำลองทางขวาได้เลย
ยอดรวม
฿0.00
ส่วนลดสมาชิก
฿0.00
ส่วนลดโปรโมชัน
฿0.00
ยอดชำระสุทธิ
฿0.00
คลิกเพื่อจำลองสแกนสินค้า (Barcode Simulator)
รายการสินค้าทั้งหมด
0 รายการ
สินค้าสต๊อกต่ำกว่ากำหนด
0 รายการ
มูลค่าสินค้าในคลัง (ราคาทุน)
฿0.00
คลังเก็บสินค้าและสต๊อก
| รหัสสินค้า | บาร์โค้ด | ชื่อสินค้า | หมวดหมู่ | ราคาทุน | ราคาขาย 1 | ราคาขาย 2 | คงเหลือ | หน่วย | สต๊อกขั้นต่ำ | การจัดการ |
|---|
ข้อมูลเอกสารการรับเข้า
ยอดรวมสินค้า
฿0.00
ส่วนลดสินค้า
-฿0.00
บวกเพิ่มอื่นๆ
฿0.00
มูลค่าก่อน VAT
฿0.00
ภาษี VAT (0%)
฿0.00
ราคารวมสุทธิ
฿0.00
รายการสินค้ารับเข้า
| สินค้า / รายละเอียด | จำนวน | ทุน/หน่วย (฿) | ส่วนลด (฿) | ราคารวม |
|---|
ยอดหนี้ค้างชำระทั้งหมด
฿0.00
จำนวนเจ้าหนี้ในระบบ
0 ราย
รายชื่อคู่ค้า / เจ้าหนี้การค้า
| ชื่อผู้จำหน่าย / บริษัท | ข้อมูลติดต่อ / เบอร์โทร | ยอดค้างชำระปัจจุบัน | ประวัติธุรกรรม | จัดการหนี้ |
|---|
ทะเบียนข้อมูลสมาชิก
| รหัสสมาชิก | ชื่อสมาชิก | เบอร์โทรศัพท์ | ระดับราคาขาย | คะแนนสะสม | การจัดการ |
|---|
ตั้งค่าโปรโมชันสินค้า
| ชื่อโปรโมชัน | ประเภทโปรโมชัน | เงื่อนไขสินค้า | สิทธิ์พิเศษ / ของแถม | สถานะการใช้งาน | ลบ |
|---|
ประวัติการทำรายการและประวัติต่างๆ
เลือกวันที่:
ตั้งค่าโปรแกรมและการเชื่อมโยง Google Sheets
ข้อมูลร้านค้า (สำหรับหัวใบเสร็จและใบเสนอราคา)
ตั้งค่า QR Code ช่องทางชำระเงินโอน
การจัดการฐานข้อมูลคอมพิวเตอร์หน้าร้าน (IndexedDB)
การเชื่อมต่อ Google Sheets API (ซิงค์ขึ้นเว็บรายงาน)
นำ URL เว็บแอปที่ได้จากการเผยแพร่สคริปต์ใน Google Sheets มาใส่ในช่องนี้
💡 ขั้นตอนการตั้งค่า Google Sheets เพื่อใช้เป็นฐานข้อมูลคลาวด์:
- เปิด Google Sheets ใหม่ของคุณขึ้นมา
- ไปที่เมนู **ส่วนขยาย (Extensions)** > **Apps Script**
- ลบโค้ดเริ่มต้นออก แล้วคัดลอกโค้ดด้านล่างนี้ไปวางแทนที่:
📜 โค้ด Apps Script ฉบับสมบูรณ์ (ความเร็วสูง 100 เท่า & ซิงค์ครบทุกเมนู):
// โค้ด Apps Script สำหรับวางใน Google Sheets ของคุณ (ระบบซิงค์คลาวด์ 100% ครบทุกเมนู)
// (กดปุ่มเรียกใช้ฟังก์ชัน initSheets 1 ครั้ง เพื่อสร้างแผ่นงานทั้ง 7 แผ่นงานและหัวตารางให้อัตโนมัติ)
function formatSheetAsTable(sheetTab, headerBgColor) {
var lastRow = sheetTab.getLastRow();
var lastCol = sheetTab.getLastColumn();
if (lastRow === 0 || lastCol === 0) return;
sheetTab.setFrozenRows(1);
var headerRange = sheetTab.getRange(1, 1, 1, lastCol);
headerRange.setBackground(headerBgColor || "#059669")
.setFontColor("#FFFFFF")
.setFontWeight("bold")
.setHorizontalAlignment("center")
.setVerticalAlignment("middle")
.setFontSize(11);
sheetTab.setRowHeight(1, 34);
if (lastRow > 1) {
var bandings = sheetTab.getBandings();
for (var b = 0; b < bandings.length; b++) {
bandings[b].remove();
}
var dataRange = sheetTab.getRange(1, 1, lastRow, lastCol);
dataRange.applyRowBanding(SpreadsheetApp.BandingTheme.LIGHT_GREY, true, false);
var bodyRange = sheetTab.getRange(2, 1, lastRow - 1, lastCol);
bodyRange.setVerticalAlignment("middle").setFontSize(10);
}
for (var c = 1; c <= lastCol; c++) {
sheetTab.autoResizeColumn(c);
}
}
function initSheets() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var salesSheet = sheet.getSheetByName("Sales") || sheet.insertSheet("Sales");
if (salesSheet.getLastRow() === 0) {
salesSheet.appendRow(["เลขที่บิล", "วันที่", "สมาชิก", "ยอดขายสุทธิ", "ส่วนลด", "กำไรเบื้องต้น", "การชำระเงิน"]);
}
formatSheetAsTable(salesSheet, "#059669");
var prodSheet = sheet.getSheetByName("Products") || sheet.insertSheet("Products");
if (prodSheet.getLastRow() === 0) {
prodSheet.appendRow(["บาร์โค้ด", "ชื่อสินค้า", "หมวดหมู่", "ราคาทุน", "ราคาปกติ", "ราคาสมาชิก", "สต๊อก", "สต๊อกขั้นต่ำ", "หน่วยนับ"]);
}
formatSheetAsTable(prodSheet, "#2563EB");
var memSheet = sheet.getSheetByName("Members") || sheet.insertSheet("Members");
if (memSheet.getLastRow() === 0) {
memSheet.appendRow(["รหัสสมาชิก", "ชื่อ-นามสกุล", "เบอร์โทรศัพท์", "ระดับราคา", "คะแนนสะสม"]);
}
formatSheetAsTable(memSheet, "#7C3AED");
var intakeSheet = sheet.getSheetByName("Intakes") || sheet.insertSheet("Intakes");
if (intakeSheet.getLastRow() === 0) {
intakeSheet.appendRow(["เลขที่บันทึก", "เลขที่ใบรับสินค้า/Invoice", "วันที่", "เจ้าหนี้/คู่ค้า", "ยอดเงินรวมสุทธิ (฿)", "ประเภทภาษี (VAT)", "ภาษีมูลค่าเพิ่ม (฿)", "การชำระเงิน"]);
}
formatSheetAsTable(intakeSheet, "#0891B2");
var credSheet = sheet.getSheetByName("Creditors") || sheet.insertSheet("Creditors");
if (credSheet.getLastRow() === 0) {
credSheet.appendRow(["รหัสเจ้าหนี้", "ชื่อบริษัท/คู่ค้า", "เบอร์โทรติดต่อ", "ยอดหนี้ค้างชำระ (฿)"]);
}
formatSheetAsTable(credSheet, "#EA580C");
var wdrSheet = sheet.getSheetByName("Withdrawals") || sheet.insertSheet("Withdrawals");
if (wdrSheet.getLastRow() === 0) {
wdrSheet.appendRow(["เลขที่เบิก", "วันที่", "ชื่อสินค้า", "จำนวน", "หน่วยนับ", "เหตุผลการเบิก", "หมายเหตุ"]);
}
formatSheetAsTable(wdrSheet, "#DC2626");
var promoSheet = sheet.getSheetByName("Promotions") || sheet.insertSheet("Promotions");
if (promoSheet.getLastRow() === 0) {
promoSheet.appendRow(["รหัสโปรโมชัน", "ชื่อโปรโมชัน", "ประเภท", "เงื่อนไข/ส่วนลด"]);
}
formatSheetAsTable(promoSheet, "#D97706");
SpreadsheetApp.getUi().alert("จัดฟอร์แมตแผ่นงานทั้ง 7 แผ่นงานเป็นตารางสวยงามพร้อมใช้งานเรียบร้อยแล้วครับ!");
}
function doGet(e) {
var action = e && e.parameter ? e.parameter.action : "";
var sheet = SpreadsheetApp.getActiveSpreadsheet();
if (action === "get_all_data" || action === "get_products_members") {
var prodSheet = sheet.getSheetByName("Products");
var products = [];
if (prodSheet) {
var prodData = prodSheet.getDataRange().getValues();
for (var i = 1; i < prodData.length; i++) {
if (prodData[i][0]) {
products.push({
productCode: String(prodData[i][0]),
barcode: String(prodData[i][0]),
name: String(prodData[i][1] || ""),
category: String(prodData[i][2] || "ทั่วไป"),
cost: Number(prodData[i][3]) || 0,
price1: Number(prodData[i][4]) || 0,
price2: Number(prodData[i][5]) || 0,
stock: Number(prodData[i][6]) || 0,
minStock: Number(prodData[i][7]) || 0,
unit: String(prodData[i][8] || "ชิ้น")
});
}
}
}
var memSheet = sheet.getSheetByName("Members");
var members = [];
if (memSheet) {
var memData = memSheet.getDataRange().getValues();
for (var j = 1; j < memData.length; j++) {
if (memData[j][0]) {
members.push({
id: String(memData[j][0]),
name: String(memData[j][1] || ""),
phone: String(memData[j][2] || ""),
priceTier: String(memData[j][3] || "ราคาส่ง 1"),
points: Number(memData[j][4]) || 0
});
}
}
}
var credSheet = sheet.getSheetByName("Creditors");
var creditors = [];
if (credSheet) {
var credData = credSheet.getDataRange().getValues();
for (var c = 1; c < credData.length; c++) {
if (credData[c][0]) {
creditors.push({
id: String(credData[c][0]),
name: String(credData[c][1] || ""),
contact: String(credData[c][2] || ""),
balance: Number(credData[c][3]) || 0
});
}
}
}
return ContentService.createTextOutput(JSON.stringify({
status: "success",
products: products,
members: members,
creditors: creditors
})).setMimeType(ContentService.MimeType.JSON);
}
return ContentService.createTextOutput(JSON.stringify({
status: "success",
message: "Google Apps Script Web App สำหรับ PennuengPOS ทำงานปกติพร้อมใช้งานครับ!"
})).setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
if (!e || !e.postData || !e.postData.contents) {
return ContentService.createTextOutput(JSON.stringify({
status: "error",
message: "ไม่พบข้อมูล POST (กรณีนี้เกิดขึ้นเมื่อกดปุ่ม 'เรียกใช้' ในตัวแก้ไข Apps Script โดยตรง ให้ทดสอบนำ URL ที่ได้จากการปรับใช้ Web App ไปใส่ใน PennuengPOS เพื่อใช้งานครับ)"
})).setMimeType(ContentService.MimeType.JSON);
}
var requestData = JSON.parse(e.postData.contents);
var action = requestData.action;
var sheet = SpreadsheetApp.getActiveSpreadsheet();
if (action === "sync_sale") {
var salesSheet = sheet.getSheetByName("Sales") || sheet.insertSheet("Sales");
if (salesSheet.getLastRow() === 0) {
salesSheet.appendRow(["เลขที่บิล", "วันที่", "สมาชิก", "ยอดขายสุทธิ", "ส่วนลด", "กำไรเบื้องต้น", "การชำระเงิน"]);
}
var sale = requestData.data;
var data = salesSheet.getDataRange().getValues();
var rowIndex = -1;
for (var sIdx = 1; sIdx < data.length; sIdx++) {
if (String(data[sIdx][0]) === String(sale.id)) {
rowIndex = sIdx + 1;
break;
}
}
var rowVal = [sale.id, sale.date, sale.memberName || "ลูกค้าทั่วไป", sale.total, sale.discount, sale.profit, sale.paymentType];
if (rowIndex > 0) {
salesSheet.getRange(rowIndex, 1, 1, 7).setValues([rowVal]);
} else {
salesSheet.appendRow(rowVal);
}
return ContentService.createTextOutput(JSON.stringify({status: "success", message: "Sale synced"})).setMimeType(ContentService.MimeType.JSON);
}
if (action === "sync_intake") {
var intakeSheet = sheet.getSheetByName("Intakes") || sheet.insertSheet("Intakes");
if (intakeSheet.getLastRow() === 0) {
intakeSheet.appendRow(["เลขที่บันทึก", "เลขที่ใบรับสินค้า/Invoice", "วันที่", "เจ้าหนี้/คู่ค้า", "ยอดเงินรวมสุทธิ (฿)", "ประเภทภาษี (VAT)", "ภาษีมูลค่าเพิ่ม (฿)", "การชำระเงิน"]);
}
var intake = requestData.data;
var data = intakeSheet.getDataRange().getValues();
var rowIndex = -1;
for (var iIdx = 1; iIdx < data.length; iIdx++) {
if (String(data[iIdx][0]) === String(intake.id)) {
rowIndex = iIdx + 1;
break;
}
}
var rowVal = [intake.id, intake.invoiceNo, intake.date, intake.creditorName, intake.totalCost, intake.vatType, intake.vatAmount, intake.paymentType];
if (rowIndex > 0) {
intakeSheet.getRange(rowIndex, 1, 1, 8).setValues([rowVal]);
} else {
intakeSheet.appendRow(rowVal);
}
return ContentService.createTextOutput(JSON.stringify({status: "success", message: "Intake synced"})).setMimeType(ContentService.MimeType.JSON);
}
if (action === "sync_withdrawal") {
var wdrSheet = sheet.getSheetByName("Withdrawals") || sheet.insertSheet("Withdrawals");
if (wdrSheet.getLastRow() === 0) {
wdrSheet.appendRow(["เลขที่เบิก", "วันที่", "ชื่อสินค้า", "จำนวน", "หน่วยนับ", "เหตุผลการเบิก", "หมายเหตุ"]);
}
var wdr = requestData.data;
var data = wdrSheet.getDataRange().getValues();
var rowIndex = -1;
for (var wIdx = 1; wIdx < data.length; wIdx++) {
if (String(data[wIdx][0]) === String(wdr.id)) {
rowIndex = wIdx + 1;
break;
}
}
var rowVal = [wdr.id, wdr.date, wdr.productName, wdr.qty, wdr.unit, wdr.reason, wdr.note];
if (rowIndex > 0) {
wdrSheet.getRange(rowIndex, 1, 1, 7).setValues([rowVal]);
} else {
wdrSheet.appendRow(rowVal);
}
return ContentService.createTextOutput(JSON.stringify({status: "success", message: "Withdrawal synced"})).setMimeType(ContentService.MimeType.JSON);
}
if (action === "sync_creditor") {
var credSheet = sheet.getSheetByName("Creditors") || sheet.insertSheet("Creditors");
var cred = requestData.data;
var data = credSheet.getDataRange().getValues();
var rowIndex = -1;
for (var i = 1; i < data.length; i++) {
if (String(data[i][0]) === String(cred.id)) {
rowIndex = i + 1;
break;
}
}
if (rowIndex > 0) {
credSheet.getRange(rowIndex, 1, 1, 4).setValues([[cred.id, cred.name, cred.contact, cred.balance]]);
} else {
if (credSheet.getLastRow() === 0) {
credSheet.appendRow(["รหัสเจ้าหนี้", "ชื่อบริษัท/คู่ค้า", "เบอร์โทรติดต่อ", "ยอดหนี้ค้างชำระ (฿)"]);
}
credSheet.appendRow([cred.id, cred.name, cred.contact, cred.balance]);
}
return ContentService.createTextOutput(JSON.stringify({status: "success", message: "Creditor synced"})).setMimeType(ContentService.MimeType.JSON);
}
if (action === "sync_product") {
var prodSheet = sheet.getSheetByName("Products") || sheet.insertSheet("Products");
if (prodSheet.getLastRow() === 0) {
prodSheet.appendRow(["บาร์โค้ด", "ชื่อสินค้า", "หมวดหมู่", "ราคาทุน", "ราคาปกติ", "ราคาสมาชิก", "สต๊อก", "สต๊อกขั้นต่ำ", "หน่วยนับ"]);
}
var prod = requestData.data;
var data = prodSheet.getDataRange().getValues();
var rowIndex = -1;
for (var i = 1; i < data.length; i++) {
if (String(data[i][0]) === String(prod.barcode)) {
rowIndex = i + 1;
break;
}
}
var rowVal = [prod.barcode, prod.name, prod.category, prod.cost, prod.price1, prod.price2, prod.stock, prod.minStock, prod.unit];
if (rowIndex > 0) {
prodSheet.getRange(rowIndex, 1, 1, 9).setValues([rowVal]);
} else {
prodSheet.appendRow(rowVal);
}
return ContentService.createTextOutput(JSON.stringify({status: "success", message: "Product synced"})).setMimeType(ContentService.MimeType.JSON);
}
if (action === "sync_member") {
var memSheet = sheet.getSheetByName("Members") || sheet.insertSheet("Members");
if (memSheet.getLastRow() === 0) {
memSheet.appendRow(["รหัสสมาชิก", "ชื่อ-นามสกุล", "เบอร์โทรศัพท์", "ระดับราคา", "คะแนนสะสม"]);
}
var mem = requestData.data;
var data = memSheet.getDataRange().getValues();
var rowIndex = -1;
for (var j = 1; j < data.length; j++) {
if (String(data[j][0]) === String(mem.id)) {
rowIndex = j + 1;
break;
}
}
var rowVal = [mem.id, mem.name, mem.phone, mem.priceTier, mem.points];
if (rowIndex > 0) {
memSheet.getRange(rowIndex, 1, 1, 5).setValues([rowVal]);
} else {
memSheet.appendRow(rowVal);
}
return ContentService.createTextOutput(JSON.stringify({status: "success", message: "Member synced"})).setMimeType(ContentService.MimeType.JSON);
}
if (action === "sync_promotion") {
var promoSheet = sheet.getSheetByName("Promotions") || sheet.insertSheet("Promotions");
if (promoSheet.getLastRow() === 0) {
promoSheet.appendRow(["รหัสโปรโมชัน", "ชื่อโปรโมชัน", "ประเภท", "เงื่อนไข/ส่วนลด"]);
}
var promo = requestData.data;
var data = promoSheet.getDataRange().getValues();
var rowIndex = -1;
for (var k = 1; k < data.length; k++) {
if (String(data[k][0]) === String(promo.id)) {
rowIndex = k + 1;
break;
}
}
var rowVal = [promo.id, promo.name, promo.type, promo.condition || '-'];
if (rowIndex > 0) {
promoSheet.getRange(rowIndex, 1, 1, 4).setValues([rowVal]);
} else {
promoSheet.appendRow(rowVal);
}
return ContentService.createTextOutput(JSON.stringify({status: "success", message: "Promotion synced"})).setMimeType(ContentService.MimeType.JSON);
}
if (action === "sync_bulk_fast") {
var bulk = requestData.data;
// 1. Sales Bulk Append
if (bulk.sales && bulk.sales.length > 0) {
var salesSheet = sheet.getSheetByName("Sales") || sheet.insertSheet("Sales");
if (salesSheet.getLastRow() === 0) {
salesSheet.appendRow(["เลขที่บิล", "วันที่", "สมาชิก", "ยอดขายสุทธิ", "ส่วนลด", "กำไรเบื้องต้น", "การชำระเงิน"]);
}
var existingSalesData = salesSheet.getDataRange().getValues();
var existingSaleIds = {};
for (var s = 1; s < existingSalesData.length; s++) {
existingSaleIds[String(existingSalesData[s][0])] = true;
}
var salesRows = [];
bulk.sales.forEach(function(sale) {
if (!existingSaleIds[String(sale.id)]) {
salesRows.push([sale.id, sale.date, sale.memberName || "ลูกค้าทั่วไป", sale.total, sale.discount, sale.profit, sale.paymentType]);
}
});
if (salesRows.length > 0) {
salesSheet.getRange(salesSheet.getLastRow() + 1, 1, salesRows.length, 7).setValues(salesRows);
}
}
// 2. Intakes Bulk Append
if (bulk.intakes && bulk.intakes.length > 0) {
var intakeSheet = sheet.getSheetByName("Intakes") || sheet.insertSheet("Intakes");
if (intakeSheet.getLastRow() === 0) {
intakeSheet.appendRow(["เลขที่บันทึก", "เลขที่ใบรับสินค้า/Invoice", "วันที่", "เจ้าหนี้/คู่ค้า", "ยอดเงินรวมสุทธิ (฿)", "ประเภทภาษี (VAT)", "ภาษีมูลค่าเพิ่ม (฿)", "การชำระเงิน"]);
}
var existingIntakesData = intakeSheet.getDataRange().getValues();
var existingIntakeIds = {};
for (var k = 1; k < existingIntakesData.length; k++) {
existingIntakeIds[String(existingIntakesData[k][0])] = true;
}
var intakeRows = [];
bulk.intakes.forEach(function(itk) {
if (!existingIntakeIds[String(itk.id)]) {
intakeRows.push([itk.id, itk.invoiceNo, itk.date, itk.creditorName, itk.totalCost, itk.vatType, itk.vatAmount, itk.paymentType]);
}
});
if (intakeRows.length > 0) {
intakeSheet.getRange(intakeSheet.getLastRow() + 1, 1, intakeRows.length, 8).setValues(intakeRows);
}
}
// 3. Withdrawals Bulk Append
if (bulk.withdrawals && bulk.withdrawals.length > 0) {
var wdrSheet = sheet.getSheetByName("Withdrawals") || sheet.insertSheet("Withdrawals");
if (wdrSheet.getLastRow() === 0) {
wdrSheet.appendRow(["เลขที่เบิก", "วันที่", "ชื่อสินค้า", "จำนวน", "หน่วยนับ", "เหตุผลการเบิก", "หมายเหตุ"]);
}
var existingWdrData = wdrSheet.getDataRange().getValues();
var existingWdrIds = {};
for (var w = 1; w < existingWdrData.length; w++) {
existingWdrIds[String(existingWdrData[w][0])] = true;
}
var wdrRows = [];
bulk.withdrawals.forEach(function(wdr) {
if (!existingWdrIds[String(wdr.id)]) {
wdrRows.push([wdr.id, wdr.date, wdr.productName, wdr.qty, wdr.unit, wdr.reason, wdr.note]);
}
});
if (wdrRows.length > 0) {
wdrSheet.getRange(wdrSheet.getLastRow() + 1, 1, wdrRows.length, 7).setValues(wdrRows);
}
}
// 4. Creditors Bulk Update/Append
if (bulk.creditors && bulk.creditors.length > 0) {
var credSheet = sheet.getSheetByName("Creditors") || sheet.insertSheet("Creditors");
if (credSheet.getLastRow() === 0) {
credSheet.appendRow(["รหัสเจ้าหนี้", "ชื่อบริษัท/คู่ค้า", "เบอร์โทรติดต่อ", "ยอดหนี้ค้างชำระ (฿)"]);
}
var existingCredsData = credSheet.getDataRange().getValues();
var credRowMap = {};
for (var c = 1; c < existingCredsData.length; c++) {
credRowMap[String(existingCredsData[c][0])] = c + 1;
}
var newCredRows = [];
bulk.creditors.forEach(function(cred) {
var rIdx = credRowMap[String(cred.id)];
if (rIdx) {
credSheet.getRange(rIdx, 1, 1, 4).setValues([[cred.id, cred.name, cred.contact, cred.balance]]);
} else {
newCredRows.push([cred.id, cred.name, cred.contact, cred.balance]);
}
});
if (newCredRows.length > 0) {
credSheet.getRange(credSheet.getLastRow() + 1, 1, newCredRows.length, 4).setValues(newCredRows);
}
}
// 5. Products Bulk Update/Append
if (bulk.products && bulk.products.length > 0) {
var prodSheet = sheet.getSheetByName("Products") || sheet.insertSheet("Products");
if (prodSheet.getLastRow() === 0) {
prodSheet.appendRow(["บาร์โค้ด", "ชื่อสินค้า", "หมวดหมู่", "ราคาทุน", "ราคาปกติ", "ราคาสมาชิก", "สต๊อก", "สต๊อกขั้นต่ำ", "หน่วยนับ"]);
}
var existingProdData = prodSheet.getDataRange().getValues();
var prodRowMap = {};
for (var p = 1; p < existingProdData.length; p++) {
prodRowMap[String(existingProdData[p][0])] = p + 1;
}
var newProdRows = [];
bulk.products.forEach(function(prod) {
var rIdx = prodRowMap[String(prod.barcode)];
var rowVal = [prod.barcode, prod.name, prod.category, prod.cost, prod.price1, prod.price2, prod.stock, prod.minStock, prod.unit];
if (rIdx) {
prodSheet.getRange(rIdx, 1, 1, 9).setValues([rowVal]);
} else {
newProdRows.push(rowVal);
}
});
if (newProdRows.length > 0) {
prodSheet.getRange(prodSheet.getLastRow() + 1, 1, newProdRows.length, 9).setValues(newProdRows);
}
}
// 6. Members Bulk Update/Append
if (bulk.members && bulk.members.length > 0) {
var memSheet = sheet.getSheetByName("Members") || sheet.insertSheet("Members");
if (memSheet.getLastRow() === 0) {
memSheet.appendRow(["รหัสสมาชิก", "ชื่อ-นามสกุล", "เบอร์โทรศัพท์", "ระดับราคา", "คะแนนสะสม"]);
}
var existingMemData = memSheet.getDataRange().getValues();
var memRowMap = {};
for (var m = 1; m < existingMemData.length; m++) {
memRowMap[String(existingMemData[m][0])] = m + 1;
}
var newMemRows = [];
bulk.members.forEach(function(mem) {
var rIdx = memRowMap[String(mem.id)];
var rowVal = [mem.id, mem.name, mem.phone, mem.priceTier, mem.points];
if (rIdx) {
memSheet.getRange(rIdx, 1, 1, 5).setValues([rowVal]);
} else {
newMemRows.push(rowVal);
}
});
if (newMemRows.length > 0) {
memSheet.getRange(memSheet.getLastRow() + 1, 1, newMemRows.length, 5).setValues(newMemRows);
}
}
// 7. Promotions Bulk Update/Append
if (bulk.promotions && bulk.promotions.length > 0) {
var promoSheet = sheet.getSheetByName("Promotions") || sheet.insertSheet("Promotions");
if (promoSheet.getLastRow() === 0) {
promoSheet.appendRow(["รหัสโปรโมชัน", "ชื่อโปรโมชัน", "ประเภท", "เงื่อนไข/ส่วนลด"]);
}
var existingPromoData = promoSheet.getDataRange().getValues();
var promoRowMap = {};
for (var pr = 1; pr < existingPromoData.length; pr++) {
promoRowMap[String(existingPromoData[pr][0])] = pr + 1;
}
var newPromoRows = [];
bulk.promotions.forEach(function(promo) {
var rIdx = promoRowMap[String(promo.id)];
var rowVal = [promo.id, promo.name, promo.type, promo.condition || '-'];
if (rIdx) {
promoSheet.getRange(rIdx, 1, 1, 4).setValues([rowVal]);
} else {
newPromoRows.push(rowVal);
}
});
if (newPromoRows.length > 0) {
promoSheet.getRange(promoSheet.getLastRow() + 1, 1, newPromoRows.length, 4).setValues(newPromoRows);
}
}
return ContentService.createTextOutput(JSON.stringify({status: "success", message: "Fast bulk sync completed"})).setMimeType(ContentService.MimeType.JSON);
}
if (action === "get_products_members") {
var prodSheet = sheet.getSheetByName("Products");
var products = [];
if (prodSheet) {
var prodData = prodSheet.getDataRange().getValues();
for (var i = 1; i < prodData.length; i++) {
products.push({
barcode: String(prodData[i][0]),
name: prodData[i][1],
category: prodData[i][2],
cost: Number(prodData[i][3]),
price1: Number(prodData[i][4]),
price2: Number(prodData[i][5]),
stock: Number(prodData[i][6]),
minStock: Number(prodData[i][7]),
unit: prodData[i][8]
});
}
}
var memSheet = sheet.getSheetByName("Members");
var members = [];
if (memSheet) {
var memData = memSheet.getDataRange().getValues();
for (var j = 1; j < memData.length; j++) {
members.push({
id: String(memData[j][0]),
name: memData[j][1],
phone: String(memData[j][2]),
priceTier: memData[j][3],
points: Number(memData[j][4])
});
}
}
return ContentService.createTextOutput(JSON.stringify({status: "success", products: products, members: members})).setMimeType(ContentService.MimeType.JSON);
}
}
- กดปุ่มบันทึกโครงการ และกดที่ปุ่ม **การทำให้ใช้งานได้ (Deploy)** > **การนำไปใช้งานได้ใหม่ (New deployment)**
- เลือกประเภทเป็น **เว็บแอป (Web app)**
- ตั้งค่า **ผู้มีสิทธิ์เข้าถึง (Who has access)** เป็น **ทุกคน (Anyone)** (สำคัญมาก!)
- กดปุ่ม **การทำให้ใช้งานได้ (Deploy)** และคัดลอกลิงก์ **URL ของเว็บแอป** มากรอกใส่ช่องตั้งค่าด้านบน