⚠️ Important: This is functional source code, not an installable plugin or add-on. It runs entirely inside a Google Apps Script project bound to a Google Spreadsheet. You must copy the files into a Google Apps Script editor and bind them to your own spreadsheet. There is no.exe, no npm package, and no marketplace listing.
The Order System is a client-facing B2B order management platform built on Google Apps Script and Google Sheets. It allows sales representatives to share a web link (or QR code) with a retail client, who can then log in, browse a product catalog, and submit an order — all from their phone or computer, with no app download required.
Once an order is submitted, it is saved to the Google Spreadsheet, a PDF order form is automatically generated and saved to Google Drive, and the admin can review, adjust, and re-export the order at any time from within the spreadsheet.
- Mobile-first order form web app — clients browse products by category, enter quantities, and submit with one tap
- Client-gated access — each client logs in with their unique Client ID; they only see the products and sections they are permitted to view
- Automatic PDF generation — each submitted order produces a formatted PDF invoice and/or a completed order form sheet
- Admin dashboard (inside the spreadsheet) — add products, add customers, manage categories, generate PDFs for any selected order
- Order revision tracking — re-submitted orders are stored as
Rev:Nrevisions of the original invoice - Category & section management — products are grouped into colour-coded categories; clients can be restricted to specific sections (A, B, C, D)
- Fully configurable — all labels, colours, column mappings, URLs, and section names are controlled via the
SETTINGSsheet — no code changes required for routine admin tasks
Google Spreadsheet (data store)
├── SETTINGS — all configuration, colours, column mappings
├── CLIENT DATA — one row per client, with section access flags
├── PRODUCTS — product catalog with variations, pricing, commission
├── ORDERS — one row per submitted order (compact encoded format)
├── ORDER_FORM_1/2 — printable order form templates (populated by PDF engine)
├── ORDERS_EXPORT — staging area for export summaries
├── DAILY_OPERATIONS — auto-refreshed sales summary dashboard
└── DASHBOARD — clickable admin action panel
Google Apps Script (this repository)
└── Bound to the spreadsheet above
Web App (served by Apps Script)
└── Accessible via a deployed URL shared with clients
Global constants and shared utility functions used across all other files.
SHEET_NAMES— object mapping logical names to spreadsheet tab namesORDER_FORM_COLORS— brand colour constants for PDF outputsuperNormalize()— canonical string normalizer used for fuzzy key matchingcolumnToLetter()— converts column index to A1-notation lettergetSheet()— safe sheet accessor with case-insensitive fallbackinclude()— server-side HTML template include helpergetOrderFormSheetName()— readsFORM_N_SHEETkey from SETTINGS to find the correct order form tabgetOrderFormTemplates()— returns all configured form template mappings for the admin UI
Entry point and UI wiring. This is the file Apps Script calls directly.
doGet(e)— web app entry point; reads URL params (clientId,orderId), builds the HTML template, and serves the order form pageonOpen()— installs the Order System spreadsheet menu with all admin actionsshowAddProductSidebar()— opens the product/customer management sidebarshowOrderFormDialog()— detects the active order (if any) and launches the web app in a popup windowinstallDashboardTrigger()— installs theonSelectionChangetrigger for the DASHBOARD clickable buttonsupdateConfigSetting()— wrapper called from admin UI to update a SETTINGS rowshowCopyLink()— displays a shareable copy-link dialog with QR code for distributing the spreadsheet to colleagues
Core data access and administrative operations. The largest file.
getAppConfig()— reads all key/value pairs from SETTINGS; returns a config object including theADMIN_KEY(read from theADMIN_LOGINnamed range)updateConfigSetting()— upserts a key/value row in SETTINGSonSelectionChange(e)— handles clickable DASHBOARD button actions via selection triggersaveClientInfoUpdate()— writes client update requests to theCLIENT_INFO_UPDATESsheet for admin reviewgetClientById()— fetches a single client record and calculates section permissionsgetClientData()— reads the full CLIENT DATA sheet with dual-header support (section headers in row 1, data headers in row 2)getClientTypes()— reads theCLIENT_TYPESnamed range for dropdown populationgetSectionNames()— readsSECTION_A–Dnamed ranges for dynamic section labelsaddNewClient()— appends a new client row with proper column mapping and checkbox validationgetAppStyles()— readsPRIMARY_COLOUR,SECONDARY_COLOURetc. from named ranges; supports named colours (e.g. "Orange") viaCOLOUR_FORMAT_DEFINITIONSgetCategorySettings()— reads the category table from SETTINGS; returns colour, display order, section gating, and sale status per categorygetVariationDefaults()/getVariationGroups()— reads variation group definitions from theVARIATION_GROUPS_AND_VALUESnamed rangeaddValueToVariationGroup()/createNewVariationGroup()— mutate the variation groups table
Order submission and retrieval.
processOrder(orderData)— validates and writes an order row to the ORDERS sheet; handles revision numbering; triggers PDF generation; usesLockServiceto prevent concurrent write conflictsgetOrderById(orderId)— fetches and parses a single order row by invoice number, returning a structured object with items decoded from the compact[qty|@sku|$price|flag]encodinggetOrdersByClient(clientName)— returns all orders for a given client name, sorted newest-first
Data model factories — pure functions, no I/O.
createProductModel(rawData, parentModel, rowIndex)— builds a fully normalized product object from a raw sheet row; handles parent→child inheritance for name, category, pricing, commission rates, colour, section, and order form assignment; computeshasCase,isAvailable, and variation headerscreateOrderModel(rawData)— builds a WooCommerce-style order object from a raw payload; normalizes line items and billing/shipping structures
Product catalog management — reading and writing to the PRODUCTS sheet.
getProductCatalog()— reads all products with dynamic header detection; supports variable column order; filters out rows missing SKU or name; reads all variation, pricing, commission, description, image, and colour fieldsgetExistingSkus()— returns all current SKUs for duplicate checkingaddProductBatch(newItems)— appends one or more new product rows; maps fields by column name; auto-assigns REF character sequences and SKUs based on the product name prefix
Generates formatted PDF order forms by writing quantities into the ORDER_FORM_N sheet and exporting.
generateOrderFormHtmlPdf(params)— the main PDF entry point; matches ordered items to rows in the order form template by REF code or SKU; writes quantities into the appropriateQtycells; exports the populated sheet to PDF; returns the Drive file URLgenerateSelectedOrderFormPdf()— spreadsheet menu trigger; reads the currently selected ORDERS row and calls the PDF generatoraddProductToOrderFormSheet(sheet, product)— inserts a product row into the order form template above the "Shipping" sentinel row
Generates PDF invoices (line-item summary style, distinct from the order form template).
createOrderPdf()/generateSelectedOrderPdf()— builds a formatted invoice PDF from order data using Google Docs or Sheets export
Sheet and template maintenance helpers called after initial installation.
setupSettingsSheet()— ensures SETTINGS exists with correct headers and default keyssetupOrderDataSheet()— creates theORDER_DATAstaging sheet used for bulk PDF populationstyleProductHeaders()/cleanupProductSheet()— apply colour formatting to PRODUCTS sheet based on category colours; remove blank/duplicate rowsrefreshDailyOperationsDashboard()— recalculates the DAILY_OPERATIONS summary from ORDERS databackupSheetHeaders()/compareSheetHeaders()/resetSheetHeaders()— header protection utilities that save and validate column headers to prevent accidental restructuring
Full spreadsheet bootstrapper — run once on a blank spreadsheet.
runInstaller()— orchestrates the creation of all required sheets, named ranges, and default values_createSheet_*()functions — create each individual sheet with correct headers, sample rows, and column widths_setupNamedRanges()— maps allgetRangeByName()calls used throughout the codebase to their corresponding SETTINGS rows_getDefaultSettings()— returns the complete list of default SETTINGS key/value pairs_protectSystemSheets()— applies warning-only protection to ORDERS and system sheets_showSetupWizard()/_runInstallerFromSidebar()— sidebar integration for the step-by-step setup UI
Tracks usage metrics within the spreadsheet for internal reporting.
Utilities for validating that sheet column headers match expected structure; used by the header backup/restore system.
Development utilities — log sheet stats, run internal test cases, and debug data mapping issues. Not used in production.
The main customer-facing web app shell. Sets up the page structure, injects server-side template variables (categorySettings, appStyles, clientId, version), applies the primary theme colour from settings, and includes the CSS and JS partials.
All client-side JavaScript for the order form (~1800 lines).
- App initialization, client data fetch, and product rendering
- Product grouping by category with colour-coded headers and sort-order support
- Matrix and compact table rendering modes for different product types
- Quantity input handling, total calculation, and form submission via
google.script.run - Admin mode (unlocked with the admin key) enabling order editing, client switching, and summary PDF option
- Order history pre-fill when an
orderIdURL parameter is present
Material Design 3 stylesheet for the order form — dark/light surfaces, text fields, buttons, category headers, product tables, sticky headers, and snackbar notifications.
HTML markup for the Add Product / Add Customer admin sidebar panel. Supports four modes: Single Entry, Bulk Generator, Add Variation, Edit Product, and Archive.
JavaScript for the admin sidebar — form validation, bulk variation generation, product submission, customer creation, and communication with the server via google.script.run.
Stylesheet for the admin sidebar panel.
Legacy/standalone sidebar for adding products (pre-dates the modular admin panel).
Step-by-step setup wizard UI that calls runInstaller() from a guided sidebar interface.
These are manual steps — there is no automated installer script for GitHub.
- Create a new Google Spreadsheet
- Open Extensions → Apps Script
- Copy all
.jsfiles from this repository into the Apps Script editor (one file per.gsscript file) - Copy all
.htmlfiles into the Apps Script editor as HTML files - Run
runInstaller()from the editor once to create all required sheets - In the Apps Script editor, go to Deploy → New Deployment → Web App
- Execute as: Me
- Who has access: Anyone (for client access without login)
- Copy the deployment URL and paste it into
SETTINGS → WEB_APP_URL - Add your clients to
CLIENT DATA(row 3 onward) - Add your products to the
PRODUCTSsheet - Share the Web App URL (or a QR code) with your clients
- The
ADMIN_LOGINnamed range in SETTINGS controls the admin password. Set this before sharing the spreadsheet. - Client IDs act as access tokens — keep them unique and non-guessable.
- All data reads/writes are server-side; clients have no direct sheet access.
- Sheet protection (warning-only) is applied to ORDERS and system sheets by the installer.
- A Google Account
- Google Sheets + Google Apps Script (both free)
- No external dependencies, npm packages, or third-party services