# Metrics: gl — raw-GL basis metrics (topic gl_lines), matching modules/expenses.py definitions # EXACTLY (the parity anchor): opex = Σ balance of posted lines to expense-type accounts # ('expense','expense_depreciation'), COGS ('expense_direct_cost') EXCLUDED; gl_revenue = income # accounts negated. Filtered measures use store_filter_sql (aliases: l=line, m=move, a=account). topic: gl_lines metrics: - key: opex label: Operating expense agg: sum field: balance store_filter_sql: "a.account_type IN ('expense', 'expense_depreciation')" format: usd description: "Posted operating expense from the GL (all expense-type accounts; COGS excluded) — the Expenses dashboard's basis." ai_context: "Company-level; includes payroll JEs/depreciation/fees that never hit vendor bills. Watch close-lag: the newest month is often still being booked." validate: method: gl_opex note: "Store-path opex must equal the live Odoo aggregate (posted, expense-type accounts) to the cent." - key: gl_cogs label: COGS (GL) agg: sum field: balance store_filter_sql: "a.account_type = 'expense_direct_cost'" format: usd description: "Cost of goods sold on the GL basis (expense_direct_cost accounts)." ai_context: "Distinct from the sales-margin COGS (revenue - margin on order lines) — different basis, reconcile deliberately, never mix silently." - key: gl_revenue label: Revenue (GL) agg: sum field: balance negate: true store_filter_sql: "a.account_type IN ('income', 'income_other')" format: usd description: "GL-basis revenue: income-type account balances, negated to read positively." ai_context: "ALL-channel and accrual-basis — will not equal wholesale order revenue (sales_lines); that difference is structural (Amazon channel + timing), not an error."