← Back to Blog
AI by

Late Payment Predictor: How an Odoo-Based Manufacturer Reduced DSO by 11 Days

Late Payment Predictor: How an Odoo-Based Manufacturer Reduced DSO by 11 Days

An MLA subfield of artificial intelligence where systems learn from data to improve performance on tasks without being explicitly programmed. ML algorithms identify patterns, make decisions, and generate… modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or… trained on Odoo payment history predicted late payers with 79% precision — and cut Days Sales Outstanding by 11 days in four months.

Key Takeaways: A late payment predictor built on top of Odoo’s existing account.move.line data can reach useful accuracy without a data warehouse or a data science team. FeatureAn individual measurable property or characteristic of the data used as input to a model. Feature engineering — selecting, transforming, and creating features — is a critical step in the ML pipeline. engineering matters more than algorithm choice — customer payment history is the dominant signal by a wide margin. Integrating predictions into the Odoo Invoicing dashboard turned the modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or… from an interesting experiment into something the AR team actually changed their behaviour around. The client reduced DSO by 11 days over four months, freeing up the working capital equivalent of roughly one month’s payroll.


The company’s accounts receivable team sent the same payment reminder emails on day 30, day 45, and day 60 for every customer. That schedule wasn’t based on anything — not risk, not history, not the amount on the invoice. It was just the default.

Their DSO sat at 52 days. The industry average for their segment was around 38. The gap wasn’t a mystery: some customers reliably paid late, and the team knew who they were. They just had no systematic way to act on that knowledge before an invoice went overdue.

The goal was specific: predict, at the time of invoicing, which invoices were likely to be paid late — and use that to prioritise AR follow-up before the due date, not after.

The Data Was Already There

This is the part that surprises most finance teams. The trainingThe process of exposing a machine learning model to labeled or unlabeled data so it can learn patterns. During training, the model adjusts its internal parameters (weights) to minimize a loss… data for a late payment predictor doesn’t require a data warehouse or months of data engineering. It lives in account.move and account.move.line, already structured.

Every posted invoice in Odoo has an invoice_date_due, a payment_state, and a link to res.partner for the customer. Payment journal entries create matching lines in account.move.line with an actual payment date. The difference between invoice_date_due and the actual payment date is your labelThe ground-truth output or target value associated with a training example in supervised learning. Labels are what the model is trained to predict (e.g., spam/not-spam, price, sentiment).: paid on time, or paid late by N days.

For this manufacturer — a mid-size industrial components producer in Vietnam issuing both VND domestic invoices and USD export invoices — the Odoo instance had four years of invoice history: roughly 14,000 posted invoices across 280 active customers. We excluded invoices under dispute, credit notes, and intra-group transactions, which left about 11,200 clean samples. The labelThe ground-truth output or target value associated with a training example in supervised learning. Labels are what the model is trained to predict (e.g., spam/not-spam, price, sentiment). was binary: paid more than 7 days after the due date was “late.” About 31% of invoices qualified.

Feature Engineering: What Actually Predicts Late Payment

This is where most of the work happened. The features we engineered fell into three groups.

Customer payment history. For each invoice, we computed the customer’s historical on-time payment rate over the preceding 12 months, their average days-past-due across all prior invoices, and the number of invoices they’d received in the last 90 days. These three variables were the strongest predictors by a wide margin. A customer who has paid late 60% of the time in the past year is not going to pay this invoice on time — the modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or… learns that fast.

Invoice-level attributes. Invoice amount, currency, and the day of week the invoice was issued. The day-of-week signal was weaker than expected, though invoices issued on Friday afternoon showed a slightly elevated late rate — probably because approvals in the customer’s AP department didn’t start until the following week. We kept it in, but it barely moved the needle.

Relationship and terms signals. Credit term length (pulled from payment_term_id via account.move), whether the customer was in the top 20% by revenue, and the industry segment stored in a custom field on res.partner. The revenue tier mattered in a non-obvious way: large, strategically important customers had negotiated longer net terms, but their actual payment behaviour within those terms was more reliable. Industry segment had weak predictive power overall, though two sectors — construction and consumer retail — showed noticeably higher late-payment rates.

One featureAn individual measurable property or characteristic of the data used as input to a model. Feature engineering — selecting, transforming, and creating features — is a critical step in the ML pipeline. we tried and dropped: open helpdesk tickets. The client used Odoo Helpdesk, and we theorised that dissatisfied customers would pay later. There was a correlation, but it was driven almost entirely by the same customers who already had poor payment history. The featureAn individual measurable property or characteristic of the data used as input to a model. Feature engineering — selecting, transforming, and creating features — is a critical step in the ML pipeline. wasn’t adding signal beyond what payment history already captured.

Model Selection: Gradient Boosting Won, Barely

We tested logistic regression, a random forest, and XGBoost. Logistic regression was interpretable but underfit — the relationship between payment history and late payment isn’t linear. Random forest and XGBoost performed similarly.

XGBoost won on the metric that mattered: precision at the threshold we chose for flagging invoices. The finance team didn’t want to manually review 30% of their invoice book — that defeats the purpose. We calibrated the threshold so the modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or… flagged roughly 20% of new invoices as high-risk, with a precision of 79%. In plain terms: 79% of flagged invoices actually paid late. Recall was lower (around 55%), meaning the modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or… missed some late payers, but the team accepted that tradeoff. Acting early on the 79% was more valuable than a lower-precision modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or… that flagged everything.

FeatureAn individual measurable property or characteristic of the data used as input to a model. Feature engineering — selecting, transforming, and creating features — is a critical step in the ML pipeline. importance from XGBoost confirmed what we expected: customer historical on-time payment rate was the dominant variable at about 41% of total importance. Average days-past-due across prior invoices added another 22%. Invoice amount contributed 14%. Everything else — day of week, credit terms, industry, currency — split the remaining 23%.

One honest limitation: the modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or… struggles with new customers who have fewer than five invoices in history. For those, we defaulted to a medium-risk flag. About 8% of monthly invoices fell into this category.

Getting Predictions Into Odoo Invoicing

A modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or… that lives in a Jupyter notebook helps nobody.

We added a custom field, payment_risk_score, to account.move — a float storing the modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or…’s probability output, populated automatically when an invoice is confirmed. A second computed field, payment_risk_label, maps that to Low / Medium / High using the calibrated threshold.

The score is computed by a lightweight Python service called when an invoice moves to “Posted” status via a server action. The modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or… is serialised with joblib and loaded into memory at service startup — inferenceThe process of using a trained model to generate predictions or outputs on new data. Unlike training (which is computationally intensive), inference is typically faster and is the production-time… on a single invoice takes under 50ms.

In the Invoicing dashboard, we added payment_risk_label as a visible column in the default “Customer Invoices” list view, filterable and sortable. AR staff can now sort their open invoice list by risk, not just by due date. High-risk invoices get a follow-up call before the due date. Medium-risk invoices get an early email reminder. Low-risk invoices follow the standard process.

We also added a Kanban group-by option so the team could view their week’s invoices segmented by risk bucket at a glance — a small addition that turned out to matter a lot for daily workflow adoption.

The Impact: 11 Days Off DSO in Four Months

The team ran a controlled transition: for the first two months after deployment, the new risk-segmented workflow ran alongside the old uniform reminder schedule. Months three and four, the team switched fully to risk-based follow-up.

DSO dropped from 52 days to 41 days over the four-month window. On an invoice book of approximately €6.2 million annualised, 11 days of DSO represents roughly €187,000 in improved working capital. That’s not a rounding error.

The improvement wasn’t evenly distributed. The largest gains came from two segments: mid-size domestic customers with inconsistent payment history, and export customers on 60-day net terms with a pattern of requesting extensions. Both groups had been treated identically under the old process. Under the new one, they received earlier, more direct contact.

The modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or…’s accuracy held through the four months without retraining. Retraining quarterly is probably the right cadence — customer payment behaviour is reasonably stable, but it shifts, particularly when a customer’s financial position changes and payment delays are the first visible symptom.

What the Model Doesn’t Do

A few things this predictor can’t handle, and shouldn’t be expected to.

It doesn’t know about external shocks. If a customer’s major distributor collapses, or a credit crunch hits a sector, the modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or… will keep predicting based on historical behaviour until that behaviour shows up in the data — which takes months. These situations require human judgment.

It doesn’t explain why. A high-risk flag is driven by history. The modelA mathematical function trained on data that maps inputs to outputs. In ML, a model is the artifact produced after training — it encapsulates learned patterns and is used to make predictions or… doesn’t distinguish between a customer who always pays at day 45 (reliable but slow) and one who paid on time for two years then missed the last three invoices. For the AR team, those require different conversations. We surfaced raw payment history alongside the score to help, but that distinction stays with the human.

It’s not a credit decision system. Using predictions to automatically block orders or refuse customers would require a different risk framework and a very different conversation with credit and legal teams. This is a workflow prioritisation tool — and that’s intentional.

At Trobz, we build late payment predictors and similar finance intelligence tools directly on top of Odoo’s existing data — no separate data warehouse required. If your AR team is managing this manually and you’re curious what your own account.move.line history would tell you, reach out.

Ready to put AI to work?

Let's explore how Trobz AI can automate your processes, enhance your ERP, and help your team make better decisions — faster.