OptimaAI Logo

Field Mapping

Odoo field names mapped to ML training CSV columns

Field Mapping

This page maps Odoo technical field names to the CSV columns expected by the ML training pipeline.

Revenue Model Features

Odoo ObjectOdoo FieldCSV ColumnTypeNotes
sale.order.lineproduct_uom_qtyquantity_soldFloatUnits per line item
sale.order.lineprice_unitpriceFloatPrice before discount
sale.order.linediscountdiscount_percentFloat0–100
sale.orderdate_ordermonthIntExtracted month (1–12)
sale.orderdate_orderquarterIntExtracted quarter (1–4)
computed—seasonal_indexFloatmonth / 6.5 (normalised)
computed—gross_margin_pctFloat(price - cost) / price
sale.order.lineprice_subtotalnet_revenueFloatTarget variable

Churn Model Features

Odoo ObjectOdoo FieldCSV ColumnTypeNotes
res.partneraggregateddays_since_last_orderIntDays since last sale.order
res.partneraggregatedtotal_ordersIntCOUNT of confirmed orders
res.partneraggregatedavg_days_between_ordersFloatMean inter-order gap
res.partnercustom fieldchurn_risk_scoreFloat0–1 CRM risk score
res.partneraggregatedtotal_spentFloatSUM of amount_total
res.partneraggregatedavg_order_valueFloatAVG of amount_total
res.partnercomputedchurnedIntTarget (0 = active, 1 = churned)

Growth Model Features

SourceCSV ColumnTypeNotes
Sales analysisperiodStringe.g. "2026-Q1"
Sales analysistotal_revenueFloatPeriod revenue total
Sales analysisorder_countIntOrders in period
Sales analysisnew_customersIntNew partners in period
Sales analysisavg_order_valueFloatPeriod average
Computed (3m lag)revenue_growth_3mFloatTarget variable

Computed Field Reference

seasonal_index

seasonal_index = month / 6.5
# Ranges approximately 0.15 (Jan) → 1.85 (Dec)
# Captures cyclical monthly patterns

churned Label

# A customer is churned if they have not ordered in 90+ days
from datetime import datetime, timedelta
cutoff = datetime.now() - timedelta(days=90)
df['churned'] = (df['last_order_date'] < cutoff).astype(int)

revenue_growth_3m (target)

# 3-period forward revenue (shifted for supervised learning)
df['revenue_growth_3m'] = df['total_revenue'].shift(-3)
df.dropna(subset=['revenue_growth_3m'], inplace=True)

On this page