Google Sheets consumers
Audience: developers & AI agents · Scope: every read/write site against Google Sheets · Last reviewed: 2026-07-20
TL;DR — Thirty-plus consumers. Most go through ConfigboxModelGooglesheets; a handful build a raw
Google_Client inline and therefore skip the picker and the access pre-flight. Use this page to answer "which
sheet does X use, and what triggers it?".
Paths are relative to docroot/components/com_configbox/data/customization/ unless stated.
Through the shared client
| Feature | Sheet setting | R/W | Call site | Trigger |
|---|---|---|---|---|
| Products-page filters | product_filters_sheet | read A:CC | models/bcconfigurator.php:312 | page load (APCu-cached) + Refresh Product Filters button |
| Rep import (Where to Buy) | reps_sheet | read A1:ZZ | controllers/adminbcreps.php:57 | Import button; docroot/cli/configbox_update_reps.php |
| Branch import | branches_sheet | read A1:ZZ | controllers/adminbcbranches.php:92 | Import button |
| SQL exports | per-record sheet column | write (replace) | models/sqlexports.php:165 | controllers/adminsqlexports.php:41 runDataExport |
| Performance data import | performance_data_import_sheet | read A:F | models/adminbcperformancedata.php:124 | Import button (adminbcpdimport) |
| Performance data multipliers | performance_data_multiplier_import_sheet | read A:C | models/adminbcperformancedatamultipliers.php:77 | same run |
| Quote stage-change log | quote_stage_sync_sheet | header probe + append + cell updates | models/bcquotestagesync.php:89,106,164,174 | cron cli/cb_quote_stage_sync_export_sheet.php |
| Quote follow-up nudge sheet | quote_nudge_sheet | clear + append | models/bcquotenudge.php:109-110 | cron cli/cb_quote_nudge_build_sheet.php |
| Cold quotes report | cold_quotes_report_sheet | write (replace) | models/bcpipedrive.php:211-217 | cron cli/cb_pipedrive_update_cold_quote_sheet.php |
| Infor code-normalization report | infor_code_normalization_report_sheet | write (replace) | models/bccodenormalization.php:880-886 | cron cli/cb_infor_coi_codes_report_findings.php |
| Order tracking — PO numbers | order_tracking_sheet_add_po_number | read + per-row cell writes | models/bcordertracking.php:37,51 | cron cli/cb_order_tracking_add_po_numbers.php |
| Order tracking — ship-to addresses | order_tracking_sheet_add_shipping_address | read + batched cell writes | models/bcordertracking.php:64,85,91 | cron cli/cb_order_tracking_add_ship_to.php |
| Order tracking — customer lookup | order_tracking_sheet | read A:I | models/bcordertracking.php:148 | front-end page load (bcordertrackingresults) |
| Converted LUM codes import | hardcoded id + gid | read | models/convertedcodes.php:25 | CLI configbox_import_converted_lum_codes.php |
| Fabrication schedule export | exports_fabrication_schedule_spreadsheet + _sheet | write (replace) | models/bcfabricationschedule.php:249 | crons cb_sheet_exports_fab_schedule[_priority].php |
| Engineering schedule export | exports_engineering_schedule_spreadsheet + _sheet | write (replace) | models/bcengineeringschedule.php:213 | cron cb_sheet_exports_engineering_schedule.php |
| Assembly schedule export | exports_assembly_schedule_spreadsheet + _sheet | write (replace) | models/bcassemblyschedule.php:245 | cron cb_sheet_exports_assembly_schedule.php |
| Warehouse kitting export | exports_warehouse_kitting_spreadsheet + _sheet | write (replace) | models/bcwarehousekittingdata.php:186 | cron cb_sheet_exports_warehouse_kitting_data.php |
| Kitting BOM picklist | kitting_bom_spreadsheet_id + kitting_bom_sheet_title | write (replace) | models/bckittingpicklist.php:92 | cron cli/cb_update_kitting_picklist.php |
| Production schedule export | hardcoded id, tabs Jobs + Raw BOM Data | write (replace ×2) | models/bcproductionschedule.php:18-32 | cron cli/cb_sheet_exports_prod_schedule.php |
| Margin Analysis / costing sheet | costing_sheet_google_spreadsheet_id + _sheet_title | write (replace) | models/bccostingsheet.php:44 | cron cli/cb_costing_sheet_update_google_sheet.php; admin generation |
| Price-list import feedback | pricelist_key + pricelist_feedback_tab | clear + append | models/adminbcpricelistlinear.php:1466,1470,1511 | during a price-list import |
| Accessible-sheets cache warm | — | read (metadata) | models/googlesheets.php:229 | cron cli/cb_google_sheets_refresh_cache.php (all environments) |
| Test harness assertions | quote_stage_sync_sheet, quote_nudge_sheet | read A1:V5000 | system_overrides/BcTestSupport.php:686,788 | functional test harness |
Each schedule export also has a legacy twin (…Old) reading the older *_spreadsheet_id / *_sheet_title
settings. No live caller was found for any of them — treat them as dead code pending removal.
Bypassing the shared client
These build a Google_Client inline against reps_file_path. They hold a spreadsheet id plus a tab title
in plain string settings, so they get no picker, no cached listing and no getAccessErrorStatus()
pre-flight.
| Feature | Settings | R/W | Call site |
|---|---|---|---|
| Commission tiers import | pricelist_key, pricelist_matrices_tab, pricelist_feedback_tab | read | models/adminbctiersimport.php:18-33,79-87 |
| Price-list import (validation + data) | same | read | models/adminbcpricelistlinear.php:27-41,92-100 |
| Price-list import (legacy issue writer) | pricelist_key + pricelist_feedback_tab | clear + write | models/adminbcpricelistlinear.php:1542-1556 |
| Job BOM calculation | job_bom_calc_source_* / job_bom_calc_target_* | read + write | models/bcproductionschedule.php:373-382,405+ |
| CSI orders / order scheduling | order_scheduling_sheet_id + tab-name settings | read + clear + write | models/adminbccsiorders.php:48-61,137-145 |
The price-list and commission-tier imports read from Google Sheets, not from an uploaded file — a common misreading, since both screens look like file importers.
Empty-result handling
Behaviour differs per consumer, and the differences matter:
- SQL exports — the sheet is left untouched.
models/sqlexports.php:141-144returns early when the query yields no rows, logging "Query returned no rows, leaving the sheet unaltered." A stale destination sheet therefore means "the query found nothing", not "the export is broken". (Side effect: the audit row in#__configbox_external_sql_export_logis still written, withrows_written = 0andsuccessnever set.) - Schedule exports — the tab is blanked. They call
writeSheetValues()unconditionally, so an Infor query returning nothing wipes the destination. - Nudge sheet — clear + append, deliberately.
models/bcquotenudge.php:98-110avoidswriteSheetValues()because Google refuses to shrink a tab with a frozen header row to a single row — exactly the zero-due-rows case. Zero rows still rewrites the header so stale rows disappear. - Rep / branch imports — validated, transactional, and abort cleanly. Fetch failure, zero rows, a header
row that doesn't match the configured
*_header_keyword_*settings, or bad data each abort before any write, with a specific message. The rep import replaces the whole table inside a transaction; the branch import soft-deletes rows missing from the sheet and only hard-deletes those with no customers attached. - Performance data — delete-then-reinsert inside a transaction. An unknown product id throws and rolls back, so a bad sheet leaves the previous data intact.
- Order tracking writes are incremental, not replace. They fill only empty cells, writing the literal
n/awhen the Infor lookup finds nothing.
Products-page filters
Worth its own note, because it is the least defended consumer and it is on a public page.
getProductFilters() (models/bcconfigurator.php:307-357) reads the sheet at fixed row offsets — row 0 =
filter group names, row 2 = filter values, rows 3+ = one row per product with TRUE in the columns that
apply. Results are cached in APCu under products.filters with no TTL, and refreshed only by the
Refresh Product Filters button.
- There are no guards. A blank setting, a missing
#, or an empty sheet (remember:getSheetValues()returnsnull) will fatal rather than degrade. The admin refresh path catchesThrowableand reports a generic error; the front-end path catches nothing, so a broken sheet takes the public products page down. - Inserting a row at the top of the sheet silently corrupts every filter, because the offsets are positional.
- A blank setting is therefore not a safe "off switch" here, unlike the follow-up sheets.
The operator-facing counterpart is
Admin Guide → Browse filters (admin-guide/products-configurator/manage-browse-filters.md).
Logging
Per-area log types: custom_google_sheet_cache, custom_sql_exports, custom_reps_api, custom_pd_imports,
custom_costing_sheet, custom_converted_lum_code_import, and custom_sheet_exports_* per schedule.
Related docs
- Overview — the client, auth, caching and the picker
- settings.md — the settings behind every row above