Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,6 @@ odoo19-shadow/backups/

# Node / web (if present)
node_modules/

# Excel files
*.xlsx
20 changes: 14 additions & 6 deletions config.example.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
{
"host": "your.server.example",
"port": 22,
"user": "ubuntu",
"auth_method": "key",
"key_path": "C:\\Users\\<you>\\.ssh\\id_rsa",
"password": ""
"ssh": {
"host": "your.server.example",
"port": 22,
"user": "ubuntu",
"auth_method": "key",
"key_path": "C:\\Users\\<you>\\.ssh\\id_rsa",
"password": ""
},
"odoo": {
"url": "https://your_odoo_instance.com",
"db": "your_database_name",
"login": "your_username",
"password": "your_password"
}
}
25 changes: 21 additions & 4 deletions import_pos_menu.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import argparse
import json
import os
import re
from typing import Any, Dict, List, Optional, Tuple

Expand All @@ -11,6 +12,18 @@
from odoo_jsonrpc import OdooClient, OdooRPCError


def load_config(path: str = "config.json") -> dict:
"""Loads config, falling back to example."""
if not os.path.exists(path):
alt = os.path.join(os.path.dirname(__file__), "config.example.json")
if not os.path.exists(alt):
raise FileNotFoundError("Missing config: create config.json or keep config.example.json")
path = alt
print(f"[info] Using example config: {path}")
with open(path, "r", encoding="utf-8") as f:
return json.load(f)


def guess_columns(headers: List[str]) -> Dict[str, int]:
"""Best-effort column name guessing for common menu formats.
Returns a mapping: {"name": idx, "price": idx, "category": idx, "sku": idx}
Expand Down Expand Up @@ -236,13 +249,17 @@ def vals(base_price: Optional[float], cat_id: Optional[int]) -> Dict[str, Any]:


def main() -> None:
# Load config first to set defaults
cfg = load_config()
odoo_cfg = cfg.get("odoo", {})

ap = argparse.ArgumentParser(description="Import POS menu from Excel into Odoo")
ap.add_argument("--source", required=True, help="Excel file path (.xlsx)")
ap.add_argument("--sheet", help="Sheet name (default: active)")
ap.add_argument("--url", default="http://34.80.194.190", help="Odoo base URL")
ap.add_argument("--login", default="admin@wuchang.life", help="Odoo login")
ap.add_argument("--password", default="poiuY926", help="Odoo password")
ap.add_argument("--db", help="Database name (optional)")
ap.add_argument("--url", default=odoo_cfg.get("url"), help="Odoo base URL")
ap.add_argument("--login", default=odoo_cfg.get("login"), help="Odoo login")
ap.add_argument("--password", default=odoo_cfg.get("password"), help="Odoo password")
ap.add_argument("--db", default=odoo_cfg.get("db"), help="Database name (optional)")
ap.add_argument("--apply", action="store_true", help="Apply changes to Odoo (default: dry-run)")
ap.add_argument("--update-existing", action="store_true", help="Update existing products if found")
ap.add_argument("--skip-ambiguous", action="store_true", help="Skip items with uncertain fields (price/category/combo)")
Expand Down