DocHub
How to extract data from the legacy system and import it into Odoo — repeatable process

Data Migration Pipeline

This document describes how to get data from Captain Van’s legacy system into Odoo. This process will need to be repeated whenever there’s a fresh data export from the store.

Pipeline Overview

[Legacy Access DB]  →  [CSV Export]  →  [convert_data.py]  →  [Odoo CSVs]  →  [import_data.py]  →  [Odoo]
     (.mdb)            (37 tables)       (format mapping)     (4 files)        (XML-RPC API)

Step 1: Export from Legacy System

The store runs a Microsoft Access database (CVAND*.mdb, ~205 MB). Data must be exported as CSV files.

Key tables needed from Access:

Access Table Maps To Purpose
Items / Products odoo_products.csv Product catalog
Customers odoo_customers.csv Customer list
Suppliers odoo_suppliers.csv Supplier contacts
Categories odoo_categories.csv Product categories

The original January 2026 export produced 37 CSV tables. Only 4 are used for the Odoo import.

Step 2: Convert to Odoo Format

Script: convert_data.py

This script reads the legacy CSV format (OSPOS-style columns) and outputs Odoo-compatible CSVs.

Input: Legacy CSVs from the Access export (expected in a source directory) Output: 4 files in data/ directory

Product Conversion

Legacy Field Odoo Field Notes
item_name name Product name
barcode barcode + default_code Used for both fields
unit_price list_price Sale price
cost_price standard_price Purchase cost
category categ_id Mapped as All / {category}
tax_1_name + tax_1_percent taxes_id Mapped to ISV 15%, ISV 18%, or Exento
description description Product description
quantity qty_available Stock quantity (reference only)

All products are marked: available_in_pos = TRUE, sale_ok = TRUE, purchase_ok = TRUE

Tax Mapping

Legacy Tax Rate Odoo Tax Name
ISV at 15% 15% ISV 15%
ISV at 18% 18% ISV 18% (alcohol, tobacco)
ISV at 0% 0% Exento
No tax / default 15% ISV 15%

Customer Conversion

Legacy Field Odoo Field Notes
first_name + last_name name Combined full name
company_name company_name Business name
phone_number phone Phone
email email Email
address_1, address_2 street, street2 Address lines
city city City
country country_id Mapped to Honduras
discount_percent comment Stored in comments (no native discount field in Community)
comments comment Appended to comment field

All customers marked: customer_rank = 1, is_company = FALSE

Supplier Conversion

Legacy Field Odoo Field Notes
company_name name Supplier name
phone phone Phone

All suppliers marked: supplier_rank = 1, is_company = TRUE

Important: The convert_data.py script has hardcoded paths (lines 20-21). Update these to match the actual file locations before running:

OSPOS_DIR = Path("/path/to/legacy/csv/files")
OUTPUT_DIR = Path("/path/to/CaptainVans-Odoo/data")

Step 3: Import into Odoo

Script: import_data.py

This script uses Odoo’s XML-RPC API to create records directly in the running Odoo instance.

Prerequisites:

  • Odoo must be running (./start-odoo.sh)
  • Database captainvans must exist
  • Admin user must be authenticated

Configuration (top of script):

URL = 'http://localhost:8069'
DB = 'captainvans'
USERNAME = 'admin'
PASSWORD = 'admin'
DATA_DIR = Path('/path/to/CaptainVans-Odoo/data')  # Update this path

Import order (dependencies matter):

  1. Categories — Creates product categories under “All” parent. Skips existing.
  2. Taxes — Gets or creates ISV 15%, ISV 18%, Exento. Skips existing.
  3. Products — 2,505 products in batches of 50. Links to categories and taxes.
  4. Customers — 1,895 customers in batches of 100. Sets Honduras country.
  5. Suppliers — 36 suppliers. Marked as company contacts.

Runtime: ~2-5 minutes total

Error handling: Script continues on individual record errors and reports summary. First 5 errors per type are printed.

Step 4: Verify

After import, verify in Odoo:

Products:   Point of Sale > Products (should show ~2,505)
Customers:  Contacts > filter by "Customers" (should show ~1,895)
Suppliers:  Contacts > filter by "Vendors" (should show ~36)
Categories: Inventory > Configuration > Product Categories (should show 15+)

Repeating the Process

When fresh data arrives from the store:

  1. Export new CSVs from the Access database
  2. Back up current Odoo database:
    docker exec captainvans-odoo-db pg_dump -U odoo captainvans > backup_before_reimport.sql
    
  3. Decide on strategy:
    • Clean reimport: Drop and recreate database, run full setup + import
    • Delta import: Modify import_data.py to check for existing records and update/skip
  4. Update paths in convert_data.py to point to new CSV files
  5. Run conversion: python3 convert_data.py
  6. Run import: python3 import_data.py

Warning: The current import script creates new records without checking for duplicates (except categories and taxes). Running it twice will create duplicate products and customers. For re-imports, either start with a fresh database or modify the script to handle duplicates.

Data Volumes

Data Type Count CSV Size
Products 2,505 285 KB
Customers 1,895 146 KB
Suppliers 36 ~2 KB
Categories 15 ~1 KB

Known Limitations

  • Customer discounts are stored in the comment field as text (e.g., “Discount: 10%”) because Odoo Community has no native per-customer discount field
  • Stock quantities from the legacy system are captured in the CSV but not imported as actual inventory movements — only as reference. Proper stock initialization would need a separate inventory adjustment in Odoo
  • No transaction history is migrated — only master data (products, customers, suppliers)