From 07f1a8fb4c23d800b0b5754e3f22f58010dde449 Mon Sep 17 00:00:00 2001 From: moonlander101 Date: Mon, 30 Mar 2026 14:13:40 +0530 Subject: [PATCH] - refactor: some redundant code - feat: keep track of sheets with header already initialized --- .../data_mappings.bal | 70 +++++---------- .../functions.bal | 88 ++++++++++--------- 2 files changed, 70 insertions(+), 88 deletions(-) diff --git a/ballerina-integrator/shopify-order-to-google-sheets/data_mappings.bal b/ballerina-integrator/shopify-order-to-google-sheets/data_mappings.bal index 7eb90a17..b326bcce 100644 --- a/ballerina-integrator/shopify-order-to-google-sheets/data_mappings.bal +++ b/ballerina-integrator/shopify-order-to-google-sheets/data_mappings.bal @@ -4,78 +4,56 @@ import ballerina/time; # Formats a date string according to the configured date format # + dateString - The input date string (RFC 3339 format from Shopify) # + return - Formatted date string or original if formatting fails/not configured -function formatDate(string? dateString) returns string { +isolated function formatDate(string? dateString) returns string { if dateString is () { return ""; } - if dateFormat == "default" || dateString.trim() == "" { - return dateString; - } time:Civil|time:Error civilResult = time:civilFromString(dateString); if civilResult is time:Error { return dateString; } - time:Civil civil = civilResult; - - if dateFormat == "iso8601" { - string|time:Error formatted = time:civilToString(civil); - if formatted is string { - return formatted; + match dateFormat { + "iso8601" => { + string|time:Error formatted = time:civilToString(civilResult); + if formatted is string { + return formatted; + } } - } else if dateFormat == "rfc5322" { - string|time:Error formatted = time:civilToEmailString(civil, time:PREFER_ZONE_OFFSET); - if formatted is string { - return formatted; + "rfc5322" => { + string|time:Error formatted = time:civilToEmailString(civilResult, time:PREFER_ZONE_OFFSET); + if formatted is string { + return formatted; + } } } - return dateString; } # Helper function to extract discount codes # + codes - Array of discount code objects from Shopify order # + return - Comma-separated string of discount codes or empty string if none -function getDiscountCodes(shopify:DiscountCode[]? codes) returns string { +isolated function getDiscountCodes(shopify:DiscountCode[]? codes) returns string { if codes is () || codes.length() == 0 { return ""; } - string[] codeList = from var code in codes select code?.code ?: ""; - return string:'join(", ", ...codeList); -} + string[] codeList = from var code in codes let string c = code?.code ?: "" where c != "" select c; -# Helper function to extract shipping method -# + lines - Array of shipping line objects from Shopify order -# + return - Shipping method title or empty string if not available -function getShippingMethod(shopify:ShippingLine[]? lines) returns string { - if lines is () || lines.length() == 0 { - return ""; - } - return lines[0]?.title ?: ""; + return string:'join(", ", ...codeList); } -# Helper function to get shipping price +# Helper function to retrieve the first shipping line # + lines - Array of shipping line objects from Shopify order -# + return - Shipping price as string or "0.00" if not available -function getShippingPrice(shopify:ShippingLine[]? lines) returns string { +# + return - The first ShippingLine record, or nil if not available +isolated function getFirstShippingLine(shopify:ShippingLine[]? lines) returns shopify:ShippingLine? { if lines is () || lines.length() == 0 { - return "0.00"; - } - return lines[0]?.price ?: "0.00"; -} - -# Helper function to get customer ID -# + customerId - Customer ID from Shopify order (nullable) -# + return - Customer ID as string or empty string if not available -function getCustomerId(int? customerId) returns string { - if customerId is () { - return ""; + return (); } - return customerId.toString(); + return lines[0]; } -function eventToRowData(shopify:OrderEvent event) returns (int|string|decimal)[] => [ +isolated function eventToRowData(shopify:OrderEvent event) returns (int|string|decimal)[] => [ // Order Identifiers event?.id.toString(), event?.order_number ?: "", @@ -87,7 +65,7 @@ function eventToRowData(shopify:OrderEvent event) returns (int|string|decimal)[] event?.subtotal_price ?: "0.00", event?.total_tax ?: "0.00", event?.total_discounts ?: "0.00", - getShippingPrice(event?.shipping_lines), + getFirstShippingLine(event?.shipping_lines)?.price ?: "0.00", event?.total_line_items_price ?: "0.00", event?.currency ?: "", @@ -102,7 +80,7 @@ function eventToRowData(shopify:OrderEvent event) returns (int|string|decimal)[] formatDate(event?.cancelled_at), // Customer Information - getCustomerId(event?.customer?.id), + event?.customer?.id ?: "", event?.email ?: "", event?.customer?.first_name ?: "", event?.customer?.last_name ?: "", @@ -120,7 +98,7 @@ function eventToRowData(shopify:OrderEvent event) returns (int|string|decimal)[] event?.shipping_address?.country ?: "", event?.shipping_address?.country_code ?: "", event?.shipping_address?.phone ?: "", - getShippingMethod(event?.shipping_lines), + getFirstShippingLine(event?.shipping_lines)?.title ?: "", // Billing Address event?.billing_address?.first_name ?: "", diff --git a/ballerina-integrator/shopify-order-to-google-sheets/functions.bal b/ballerina-integrator/shopify-order-to-google-sheets/functions.bal index 5298aae5..9a391c6b 100644 --- a/ballerina-integrator/shopify-order-to-google-sheets/functions.bal +++ b/ballerina-integrator/shopify-order-to-google-sheets/functions.bal @@ -3,10 +3,32 @@ import ballerina/time; import ballerinax/googleapis.sheets; import ballerinax/trigger.shopify; +isolated string[] initializedSheets = []; + +# Extracts line item details and creates a row for each line item +# + rowValues - The base row values from the order event +# + lineItems - The list of line items from the order event +# + return - A list of rows with line item details included +isolated function expandLineItems((int|string|decimal)[] rowValues, shopify:LineItem[] lineItems) returns (int|string|decimal)[][] { + (int|string|decimal)[][] allRows = []; + foreach var item in lineItems { + (int|string|decimal)[] lineItemValues = rowValues.clone(); + lineItemValues.push(item?.title ?: ""); + lineItemValues.push(item?.sku ?: ""); + lineItemValues.push(item?.variant_title ?: ""); + lineItemValues.push(item?.quantity ?: 0); + lineItemValues.push(item?.price ?: "0.00"); + lineItemValues.push(item?.product_id.toString()); + lineItemValues.push(item?.variant_id.toString()); + allRows.push(lineItemValues); + } + return allRows; +} + # Apply filters to determine if order should be processed # + event - The order event # + return - True if order should be filtered out (skipped), false if it should be processed -function applyFilters(shopify:OrderEvent event) returns boolean { +isolated function applyFilters(shopify:OrderEvent event) returns boolean { string orderNumber = event?.order_number.toString(); if allowedCountryCodes.length() > 0 { @@ -51,21 +73,17 @@ function applyFilters(shopify:OrderEvent event) returns boolean { string orderTags = event?.tags ?: ""; string:RegExp commaPattern = re `,`; - string[] orderTagList = orderTags == "" ? [] : from string tag in commaPattern.split(orderTags) select tag.trim(); + + string[] tempTagList = orderTags == "" ? [] : from string tag in commaPattern.split(orderTags) select tag.trim(); + final string[] & readonly orderTagList = tempTagList.cloneReadOnly(); if requiredTags.length() > 0 { if orderTagList.length() == 0 { log:printWarn(string `Filter failed for order ${orderNumber}: No tags found, but required tags are configured`); return true; } - boolean hasRequiredTag = false; - foreach string requiredTag in requiredTags { - if orderTagList.indexOf(requiredTag) !is () { - hasRequiredTag = true; - break; - } - } - if !hasRequiredTag { + + if !requiredTags.some(isolated function(string tag) returns boolean => orderTagList.indexOf(tag) is int) { log:printWarn(string `Filter failed for order ${orderNumber}: Order tags '${orderTags}' do not contain any required tags`); return true; } @@ -83,7 +101,7 @@ function applyFilters(shopify:OrderEvent event) returns boolean { return false; } -function resolveSheetName(shopify:OrderEvent event) returns string|error { +isolated function resolveSheetName(shopify:OrderEvent event) returns string|error { if !groupByMonth { check ensureSheetExists(sheetName); return sheetName; @@ -100,7 +118,7 @@ function resolveSheetName(shopify:OrderEvent event) returns string|error { return name; } -function ensureSheetExists(string sheetName) returns error? { +isolated function ensureSheetExists(string sheetName) returns error? { sheets:Sheet|error sheet = sheetsClient->getSheetByName(googleSheetsConfig.spreadsheetId, sheetName); if sheet is error { @@ -120,7 +138,7 @@ function ensureSheetExists(string sheetName) returns error? { # create row from order event # + event - The order event # + return - Error if operation fails -function createRowFromEvent(shopify:OrderEvent event) returns error? { +isolated function createRowFromEvent(shopify:OrderEvent event) returns error? { log:printDebug(string `Received order event: ${event?.order_number.toString()}`); boolean shouldFilter = applyFilters(event); if shouldFilter { @@ -129,6 +147,7 @@ function createRowFromEvent(shopify:OrderEvent event) returns error? { string sheetName = check resolveSheetName(event); check addHeader(sheetName); + (int|string|decimal)[] rowValues = eventToRowData(event); sheets:A1Range a1Range = { sheetName: sheetName, @@ -141,19 +160,7 @@ function createRowFromEvent(shopify:OrderEvent event) returns error? { var lineItems = event?.line_items; if !(lineItems is ()) && lineItems.length() > 0 { - (int|string|decimal)[][] allRows = []; - foreach var item in lineItems { - (int|string|decimal)[] lineItemValues = rowValues.clone(); - lineItemValues.push(item?.title ?: ""); - lineItemValues.push(item?.sku ?: ""); - lineItemValues.push(item?.variant_title ?: ""); - lineItemValues.push(item?.quantity ?: 0); - lineItemValues.push(item?.price ?: "0.00"); - lineItemValues.push(item?.product_id ?: ""); - lineItemValues.push(item?.variant_id ?: ""); - allRows.push(lineItemValues); - } - + (int|string|decimal)[][] allRows = expandLineItems(rowValues, lineItems); _ = check sheetsClient->appendValues(googleSheetsConfig.spreadsheetId, allRows, a1Range); return; } @@ -166,14 +173,18 @@ function createRowFromEvent(shopify:OrderEvent event) returns error? { check upsertOrderWithoutLineItems(event, rowValues, a1Range, sheetName); } } - - return; } # Adds the header row for an empty sheet # + sheetName - Target sheet name # + return - Error if operation fails -function addHeader(string sheetName) returns error? { +isolated function addHeader(string sheetName) returns error? { + lock { + if (initializedSheets.indexOf(sheetName) is int) { + return; + } + } + sheets:Row firstRow = check sheetsClient->getRow(googleSheetsConfig.spreadsheetId, sheetName, 1); (int|string|decimal)[] firstRowValues = firstRow.values; @@ -252,6 +263,9 @@ function addHeader(string sheetName) returns error? { } check sheetsClient->createOrUpdateRow(googleSheetsConfig.spreadsheetId, sheetName, 1, headerRow); } + lock { + initializedSheets.push(sheetName); + } } # Upsert order without line items (single row per order) @@ -260,7 +274,7 @@ function addHeader(string sheetName) returns error? { # + a1Range - The A1 range for appending # + sheetName - Target sheet name # + return - Error if operation fails -function upsertOrderWithoutLineItems(shopify:OrderEvent event, (int|string|decimal)[] rowValues, sheets:A1Range a1Range, string sheetName) returns error? { +isolated function upsertOrderWithoutLineItems(shopify:OrderEvent event, (int|string|decimal)[] rowValues, sheets:A1Range a1Range, string sheetName) returns error? { sheets:Column orderNumberRowData = check sheetsClient->getColumn(googleSheetsConfig.spreadsheetId, sheetName, "B"); (int|string|decimal)[] orderNums = orderNumberRowData.values; @@ -284,7 +298,7 @@ function upsertOrderWithoutLineItems(shopify:OrderEvent event, (int|string|decim # + a1Range - The A1 range for appending # + sheetName - Target sheet name # + return - Error if operation fails -function upsertOrderWithLineItems(shopify:OrderEvent event, (int|string|decimal)[] rowValues, sheets:A1Range a1Range, string sheetName) returns error? { +isolated function upsertOrderWithLineItems(shopify:OrderEvent event, (int|string|decimal)[] rowValues, sheets:A1Range a1Range, string sheetName) returns error? { sheets:Column orderNumberRowData = check sheetsClient->getColumn(googleSheetsConfig.spreadsheetId, sheetName, "B"); (int|string|decimal)[] orderNums = orderNumberRowData.values; @@ -300,17 +314,7 @@ function upsertOrderWithLineItems(shopify:OrderEvent event, (int|string|decimal) var lineItems = event?.line_items; (int|string|decimal)[][] allRows = []; if !(lineItems is ()) && lineItems.length() > 0 { - foreach var item in lineItems { - (int|string|decimal)[] lineItemValues = rowValues.clone(); - lineItemValues.push(item?.title ?: ""); - lineItemValues.push(item?.sku ?: ""); - lineItemValues.push(item?.variant_title ?: ""); - lineItemValues.push(item?.quantity ?: 0); - lineItemValues.push(item?.price ?: "0.00"); - lineItemValues.push(item?.product_id ?: ""); - lineItemValues.push(item?.variant_id ?: ""); - allRows.push(lineItemValues); - } + allRows = expandLineItems(rowValues, lineItems); } else { // No line items, just use base row allRows.push(rowValues);