Query icon
Log icon
IonToCsv icon
Upload icon
SlackIncomingWebhook icon
Schedule icon

Export Odoo invoices to an S3 warehouse staging bucket

Nightly Kestra flow that exports one day of Odoo invoices to CSV in S3, with retries, Slack alerting, and backfill-safe partitioning.

Categories
Business

Pull customer invoice data out of Odoo on a nightly schedule and land it in your cloud warehouse staging area so analysts can model revenue, receivables, and tax downstream. This Odoo to S3 pipeline solves the gap between an ERP that owns the transactional truth and a data warehouse that needs clean, date-partitioned files. It runs unattended: each remote call retries on transient errors, failures alert Slack, and the data window is derived from the schedule date so backfills and replays land in the right partition instead of today's.

How it works

  1. The nightly trigger (io.kestra.plugin.core.trigger.Schedule) fires at 02:00 UTC and exports the previous calendar day of invoices.
  2. query_invoices (io.kestra.plugin.odoo.Query) runs a SEARCH_READ against the account.move model, filtering on move_type = out_invoice, the selected state input, and an invoice_date window derived from {{ trigger.date ?? execution.startDate }}. It fetches a fixed field set, caps at limit: 100000, and stores the result as an ION file via fetchType: STORE.
  3. log_row_count (io.kestra.plugin.core.log.Log) surfaces how many invoices were exported so an empty day is distinguishable from a broken run.
  4. convert_to_csv (io.kestra.plugin.serdes.csv.IonToCsv) converts the ION result to a warehouse-friendly CSV using NON_NUMERIC quoting.
  5. upload_to_warehouse (io.kestra.plugin.aws.s3.Upload) lands the CSV in the staging bucket under a date-partitioned key, ready for loading into Snowflake, BigQuery, Redshift, or a lakehouse table.

What you get

  • A one-day, incremental invoice extract instead of a full re-dump of history.
  • Idempotent replays: the S3 key follows the data window, so re-running a day overwrites that day's object rather than duplicating it.
  • A date-partitioned object at s3://{{ inputs.bucket }}/odoo/invoices/yyyy/MM/dd/account_move.csv.
  • An operator-visible row count for every run.

Who it's for

  • Data engineers building an ERP to warehouse ingestion layer.
  • Analytics teams that model revenue, AR aging, and tax from Odoo.
  • RevOps and finance teams that need invoice data outside the ERP UI.

Why orchestrate this with Kestra

Odoo has no built-in scheduler for exporting data to a cloud warehouse. Kestra fills that gap: an event-driven Schedule trigger replaces brittle cron scripts, task-level retry blocks ride out flaky XML-RPC and S3 calls, the errors block guarantees a failed extract is never silent, and the whole pipeline is declarative YAML you can version and review. Execution outputs give you lineage from the Odoo query through the CSV to the uploaded object. The state input is a SELECT, so its value is constrained to a known set and never arbitrary free text flowing into the Odoo domain filter.

Prerequisites

  • A reachable Odoo instance (self-hosted or Odoo Online) with XML-RPC enabled, and a user that can read account.move records.
  • An Amazon S3 bucket for warehouse staging plus an identity that can s3:PutObject. Static IAM keys are shown here; in production prefer the AWS default credentials chain (instance profile, IRSA) or an assumed role for least privilege.

Secrets

  • ODOO_URL: base URL of the Odoo instance, including scheme and port.
  • ODOO_DB: Odoo database name.
  • ODOO_USERNAME: Odoo login used for XML-RPC authentication.
  • ODOO_PASSWORD: password for that Odoo user.
  • AWS_DEFAULT_REGION: AWS region of the staging bucket.
  • AWS_ACCESS_KEY_ID: AWS access key id for the S3 upload.
  • AWS_SECRET_ACCESS_KEY: AWS secret access key for the S3 upload.
  • SLACK_WEBHOOK: Slack incoming webhook URL used for failure alerts.

Quick start

  1. Add the eight secrets above to your namespace or tenant.
  2. Set the bucket input to your staging bucket name and pick the invoice state.
  3. Adjust the filters and fields lists to match the invoices and columns you want.
  4. Run the flow manually, or let the nightly Schedule trigger run it at 02:00 UTC. To backfill a past day, start a backfill from the Triggers tab; the window and S3 key follow the backfilled date automatically.

How to extend

  • Add a downstream load task (Snowflake COPY, BigQuery load, dbt run) once the CSV lands.
  • Export other Odoo models such as account.move.line, res.partner, or sale.order by adding more Query tasks.
  • Swap the state filter or add currency and partner filters for multi-entity exports.
  • If a backfill day could exceed limit: 100000, narrow the window or add an offset loop.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.