From 34e79ef18fc6260a4f255e6087b011d8ff741a43 Mon Sep 17 00:00:00 2001
From: Trygve Laugstøl <trygvis@inamo.no>
Date: Fri, 2 Aug 2019 15:09:07 +0200
Subject: odoo: wip

---
 src/ee/odoo/__init__.py               | 113 ++++++++++++++++++++++++++++++++++
 src/ee/project/__init__.py            |   8 ++-
 src/ee/tools/__init__.py              |  13 ++++
 src/ee/tools/init.py                  |  25 ++++++++
 src/ee/tools/ninja.py                 |  17 +++++
 src/ee/tools/odoo-restructure.py      |  26 ++++++++
 src/ee/tools/templates/build.ninja.j2 |   9 +++
 7 files changed, 208 insertions(+), 3 deletions(-)
 create mode 100644 src/ee/odoo/__init__.py
 create mode 100644 src/ee/tools/odoo-restructure.py

(limited to 'src/ee')

diff --git a/src/ee/odoo/__init__.py b/src/ee/odoo/__init__.py
new file mode 100644
index 0000000..af872b4
--- /dev/null
+++ b/src/ee/odoo/__init__.py
@@ -0,0 +1,113 @@
+import csv
+from pathlib import Path
+
+from ee.logging import log
+from ee.project import Project
+
+
+def restructure(in_path: Path, in_format, out_path: Path, out_format):
+    log.info("Creating {}".format(out_path))
+    if in_format == "digikey-order":
+        with in_path.open("r") as f:
+            data = list(csv.reader(f))
+
+        header = {k: index for index, k in enumerate(data[0])}
+        description_i = header["Description"]
+        pn_i = header["Part Number"]
+        mpn_i = header["Manufacturer Part Number"]
+        unit_price_i = header["Unit Price"]
+        extended_price_i = header["Extended Price"]
+
+        # If you search in Odoo for Digikey this is the correct name.
+        digikey_name = "Digi-Key Electronics"
+
+        rows = ([row[description_i], row[pn_i], row[mpn_i], row[unit_price_i], row[extended_price_i]]
+                for row in data[1:-1])
+        with out_path.open("w") as f:
+            out = csv.writer(f)
+            header = ["External ID",
+                      "Can be Purchased",
+                      "Product Type",
+                      # "Description",  # Internal notes
+                      "Name",
+                      "Internal Reference",
+                      "Cost",
+                      "Product Category",
+                      # "Vendors / External ID",
+                      # "seller_ids/name",
+                      # "Vendors / Vendor Product Name",
+                      # "Vendors / Vendor Product Code",
+                      # "Vendors / Price",
+                      ]
+            out.writerow(header)
+            for description, pn, mpn, price, e_price in rows:
+                external_id = "ee/mpn:" + mpn
+                vendor_external_id = "ee/spn:{}".format(pn)
+
+                row = [external_id, "yes", "Storable Product", description, mpn, price, "All / Electronics"]
+                # row.extend([vendor_external_id, digikey_name, description, pn, price])
+                out.writerow(row)
+                # break
+
+
+def init_project(project: Project):
+    odoo = project.get_or_create_section("odoo")
+    odoo["enabled"] = "yes"
+
+
+def generate_ninja(project: Project):
+    head = """
+rule odoo-restructure
+    command = ee odoo-restructure --in $in --in-format $in_format --out $out --out-format $out_format
+    """.strip()
+    orders_dir = project.orders_dir
+
+    files = []
+    targets = []
+    # print("orders_dir={}".format(orders_dir))
+    if orders_dir.is_dir():
+        for file in sorted(orders_dir.iterdir()):
+            if file.name.endswith(".csv"):
+                with file.open("r") as f:
+                    data = list(csv.reader(f))
+
+                if len(data) < 1:
+                    continue
+
+                in_format = _classify(data)
+
+                if in_format is None:
+                    continue
+
+                out_format = "product-list"
+
+                target = "$public_dir/odoo/{}/{}".format(out_format, file.name)
+                files.append("build {}: odoo-restructure $orders_dir/{}\n"
+                             "    in_format = {}\n"
+                             "    out_format = {}\n".format(target, file.name, in_format, out_format))
+
+                # This was an attempt to get ninja to run "ee ninja" when the input csv files went away.
+                # files.append("build $orders_dir/{}: ee-ninja".format(file.name))
+
+                targets.append(target)
+
+    lines = []
+    lines.extend(head.splitlines())
+    lines.append("")
+    lines.extend(files)
+    lines.append("build odoo-restructure: phony $orders_dir ee.ninja $\n" + " $\n".join(["    " + t for t in targets]))
+    lines.append("default odoo-restructure")
+    return "\n".join(lines)
+
+
+def _classify(data):
+    header = data[0]
+    if len(header) < 5:
+        return None
+
+    last_row = data[-1]
+    print(last_row)
+    print(last_row[-2])
+
+    if last_row[-2] == "Subtotal":
+        return "digikey-order"
diff --git a/src/ee/project/__init__.py b/src/ee/project/__init__.py
index c9e02f8..1d7ea1d 100644
--- a/src/ee/project/__init__.py
+++ b/src/ee/project/__init__.py
@@ -30,15 +30,17 @@ class SupplierDescriptor(object):
 
 class Project(object):
     def __init__(self, project_dir: Path, cfg: configparser.ConfigParser):
-        self.public_dir = project_dir / "ee"
-        self.report_dir = self.public_dir / "reports"
-        self.cache_dir = self.public_dir / "cache"
         self.project_dir = project_dir
         self._cfg = cfg
 
         project = self.get_or_create_section("project")
         project["uuid"] = project.get("uuid", str(uuid.uuid4()))
 
+        self.public_dir = self.project_dir / "ee"
+        self.report_dir = self.public_dir / "reports"
+        self.cache_dir = self.public_dir / "cache"
+        self.orders_dir = Path(project.get("orders-dir", self.public_dir / "orders"))
+
         # TODO: read from config
         self._suppliers = []
         digikey_store = DigikeyStore.from_store_code("us")
diff --git a/src/ee/tools/__init__.py b/src/ee/tools/__init__.py
index 0d4ef14..d6d1298 100644
--- a/src/ee/tools/__init__.py
+++ b/src/ee/tools/__init__.py
@@ -67,3 +67,16 @@ def process_default_argparse_group(args):
     log_level = log_level if log_level is not None else "info"
 
     log.set_level(log_level)
+
+
+def parse_bool(v):
+    if isinstance(v, bool):
+        return v
+
+    if v.lower() in ("yes", "true", "t", "y", "1"):
+        return True
+
+    if v.lower() in ("no", "false", "f", "n", "0"):
+        return False
+
+    raise argparse.ArgumentTypeError("Boolean value expected.")
diff --git a/src/ee/tools/init.py b/src/ee/tools/init.py
index 9b3bcf4..e78ab9a 100644
--- a/src/ee/tools/init.py
+++ b/src/ee/tools/init.py
@@ -4,6 +4,7 @@ from pathlib import Path
 from typing import List
 
 import ee.tools
+from ee.tools import parse_bool
 from ee.project import Project
 
 
@@ -49,12 +50,31 @@ def init_seeed_opl(project: Project):
     ee.supplier.seeed.init_project(project)
 
 
+def init_odoo(project: Project, args):
+    enabled = parse_bool(project.cfg.get("odoo", "enabled", fallback=False))
+    # print("odoo enabled: {}".format(enabled))
+
+    if args.enable_odoo is not None:
+        # print("using args: {}".format(args.enable_odoo))
+        enabled = args.enable_odoo
+
+    if not enabled:
+        if "odoo" not in project.cfg:
+            return
+        project.cfg["odoo"]["enabled"] = "no"
+        return
+
+    import ee.odoo
+    ee.odoo.init_project(project)
+
+
 def init(project_dir: Path, basedir: Path, args):
     project = Project.load(project_dir)
 
     init_kicad_project(basedir, project, args)
     init_digikey(project)
     init_seeed_opl(project)
+    init_odoo(project, args)
 
     if args.create_bom_strategy:
         create_bom = project.get_or_create_section("create-bom")
@@ -78,6 +98,11 @@ parser.add_argument("--create-bom-strategy",
                     required=False,
                     metavar="PY CALLABLE")
 
+parser.add_argument("--enable-odoo",
+                    type=parse_bool, nargs="?",
+                    const=True, default=None,
+                    metavar="BOOL")
+
 args = parser.parse_args()
 ee.tools.process_default_argparse_group(args)
 
diff --git a/src/ee/tools/ninja.py b/src/ee/tools/ninja.py
index 7d73d8f..3df8796 100644
--- a/src/ee/tools/ninja.py
+++ b/src/ee/tools/ninja.py
@@ -1,5 +1,6 @@
 import argparse
 import os.path
+import pydoc
 import sys
 from pathlib import Path
 from typing import List, Union
@@ -126,11 +127,27 @@ def generate(project: Project):
                           "default ee-reports\n",
                           ])
 
+    # Hooks
+    hooks = [("odoo", "ee.odoo.generate_ninja")]
+    hook_fragments = {}
+    for name, function in hooks:
+        f = pydoc.locate(function)
+        hook_fragments[name] = f(project)
+
     with ee_ninja.open("w") as f:
         env = _create_env()
         template = env.get_template("build.ninja.j2")
         f.write(template.render(**params))
 
+        f.write("\n")
+        if len(hooks):
+            for name, _ in hooks:
+                f.write("# Hook: {}\n".format(name))
+                fragment_name = hook_fragments[name]
+                f.write(fragment_name)
+                if not fragment_name.endswith("\n"):
+                    f.write("\n")
+
 
 parser = argparse.ArgumentParser()
 ee.tools.add_default_argparse_group(parser)
diff --git a/src/ee/tools/odoo-restructure.py b/src/ee/tools/odoo-restructure.py
new file mode 100644
index 0000000..38e67b6
--- /dev/null
+++ b/src/ee/tools/odoo-restructure.py
@@ -0,0 +1,26 @@
+import argparse
+from pathlib import Path
+
+import ee.odoo
+import ee.tools
+
+parser = argparse.ArgumentParser()
+ee.tools.add_default_argparse_group(parser)
+
+parser.add_argument("--in",
+                    dest="in_path",
+                    required=True)
+
+parser.add_argument("--out",
+                    required=True)
+
+parser.add_argument("--in-format",
+                    required=True)
+
+parser.add_argument("--out-format",
+                    required=True)
+
+args = parser.parse_args()
+ee.tools.process_default_argparse_group(args)
+
+ee.odoo.restructure(Path(args.in_path), args.in_format, Path(args.out), args.out_format)
diff --git a/src/ee/tools/templates/build.ninja.j2 b/src/ee/tools/templates/build.ninja.j2
index 016c7da..4817b7b 100644
--- a/src/ee/tools/templates/build.ninja.j2
+++ b/src/ee/tools/templates/build.ninja.j2
@@ -3,6 +3,7 @@ ee = {{ ee }}
 uuid = {{ project.uuid }}
 public_dir = {{ project.public_dir }}
 report_dir = {{ project.report_dir }}
+orders_dir = {{ project.orders_dir }}
 {%- if sch is defined %}
 sch = {{ sch | ninja_path }}
 sch_files = {{ sch_files | ninja_path }}
@@ -196,6 +197,14 @@ build $public_dir/seeed/opl/{{ opl }}.xml: seeed-download-opl
 {%- endfor %}
 {%- endif %}
 
+rule ee-ninja
+    command = ee ninja && touch $out
+
+build build.ninja ee.ninja: ee-ninja eeconfig $orders_dir
+    generator = yes
+
+default ee.ninja
+
 # Reports
 build ee-reports: phony {{ " ".join(reports) }}
 build ee-part-dbs: phony {%- for s in suppliers %} {{ s.part_db }}{% endfor %}
-- 
cgit v1.2.3