feat: implement periodic shopify sales sync
- automated sales check (default 10 mins) - manual reconciliation menu - updates 'status' and 'shopify_status' in sheet - updated docs
This commit is contained in:
111
src/salesSync.ts
Normal file
111
src/salesSync.ts
Normal file
@ -0,0 +1,111 @@
|
||||
import { Config } from "./config";
|
||||
import { Shop } from "./shopifyApi";
|
||||
import { Product } from "./Product";
|
||||
import { getRowByColumnValue, getCellRangeByColumnName, toastAndLog } from "./sheetUtils";
|
||||
|
||||
// Declare SpreadsheetApp globally for Google Apps Script environment
|
||||
declare var SpreadsheetApp: GoogleAppsScript.Spreadsheet.SpreadsheetApp;
|
||||
|
||||
export function checkRecentSales() {
|
||||
console.log("Starting checkRecentSales...");
|
||||
const config = new Config();
|
||||
const freq = config.salesSyncFrequency || 10;
|
||||
|
||||
// 2.5x lookback
|
||||
const now = new Date();
|
||||
const lookbackMs = freq * 2.5 * 60 * 1000;
|
||||
const startTime = new Date(now.getTime() - lookbackMs);
|
||||
|
||||
const shop = new Shop();
|
||||
console.log(`Fetching orders from ${startTime.toISOString()} to ${now.toISOString()}`);
|
||||
|
||||
const orders = shop.FetchOrders(startTime, now);
|
||||
console.log(`Found ${orders.length} orders.`);
|
||||
|
||||
syncOrders(orders, shop);
|
||||
}
|
||||
|
||||
export function reconcileSalesHandler() {
|
||||
const ui = SpreadsheetApp.getUi();
|
||||
const result = ui.prompt("Reconcile Sales", "Enter number of days to look back:", ui.ButtonSet.OK_CANCEL);
|
||||
|
||||
if (result.getSelectedButton() == ui.Button.OK) {
|
||||
const days = parseInt(result.getResponseText());
|
||||
if (isNaN(days) || days <= 0) {
|
||||
toastAndLog("Invalid number of days.");
|
||||
return;
|
||||
}
|
||||
|
||||
toastAndLog(`Reconciling sales for last ${days} days...`);
|
||||
const now = new Date();
|
||||
const startTime = new Date(now.getTime() - (days * 24 * 60 * 60 * 1000));
|
||||
|
||||
const shop = new Shop();
|
||||
const orders = shop.FetchOrders(startTime, now);
|
||||
toastAndLog(`Found ${orders.length} orders. Syncing...`);
|
||||
|
||||
syncOrders(orders, shop);
|
||||
toastAndLog("Reconciliation complete.");
|
||||
}
|
||||
}
|
||||
|
||||
function syncOrders(orders: any[], shop: Shop) {
|
||||
const processedSkus = new Set<string>();
|
||||
|
||||
for (const order of orders) {
|
||||
const lineItems = order.line_items;
|
||||
if (!lineItems || !Array.isArray(lineItems)) continue;
|
||||
|
||||
for (const item of lineItems) {
|
||||
const sku = item.sku;
|
||||
if (!sku) continue;
|
||||
|
||||
if (processedSkus.has(sku)) continue;
|
||||
processedSkus.add(sku);
|
||||
|
||||
console.log(`Processing sold SKU: ${sku}`);
|
||||
|
||||
try {
|
||||
const row = getRowByColumnValue("product_inventory", "sku", sku);
|
||||
if (!row) {
|
||||
console.log(`SKU ${sku} not found in sheet.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("product_inventory");
|
||||
if (!sheet) {
|
||||
console.error("Could not find product_inventory sheet");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 1. Update status to 'sold'
|
||||
const statusCell = getCellRangeByColumnName(sheet, "status", row);
|
||||
if (statusCell) {
|
||||
const currentStatus = statusCell.getValue();
|
||||
if (currentStatus !== "sold") {
|
||||
statusCell.setValue("sold");
|
||||
console.log(`Set status='sold' for SKU ${sku}`);
|
||||
}
|
||||
} else {
|
||||
console.warn(`Could not find 'status' column for SKU ${sku}`);
|
||||
}
|
||||
|
||||
// 2. Sync Shopify Status
|
||||
// Use Product class to fetch fresh data
|
||||
const product = new Product(sku);
|
||||
product.MatchToShopifyProduct(shop);
|
||||
|
||||
if (product.shopify_product && product.shopify_product.status) {
|
||||
const shopifyStatusCell = getCellRangeByColumnName(sheet, "shopify_status", row);
|
||||
if (shopifyStatusCell) {
|
||||
shopifyStatusCell.setValue(product.shopify_product.status);
|
||||
console.log(`Updated shopify_status='${product.shopify_product.status}' for SKU ${sku}`);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error(`Error processing SKU ${sku}: ${e}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user