Skip to content

Commit

Permalink
fixup
Browse files Browse the repository at this point in the history
  • Loading branch information
bealdav committed Oct 22, 2024
1 parent 7caf213 commit 8d4d7fc
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 34 deletions.
5 changes: 5 additions & 0 deletions sheet_dataframe_process/data/demo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,10 @@
<record id="file_config_contact_date" model="file.field">
<field name="config_id" ref="file_config_contact" />
<field name="field_id" ref="base.field_res_partner__write_date" />
<field name="check_type" eval="1" />
</record>
<record id="file_config_contact_color" model="file.field">
<field name="config_id" ref="file_config_contact" />
<field name="field_id" ref="base.field_res_partner__color" />
</record>
</odoo>
3 changes: 3 additions & 0 deletions sheet_dataframe_process/models/file_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ class FileField(models.Model):
required = fields.Boolean(
help="Prevent to import missing data if field is missing in some records",
)
check_type = fields.Boolean(
help="Check data type is compatible",
)
Binary file modified sheet_dataframe_process/tests/files/4_fields.xlsx
Binary file not shown.
Binary file modified sheet_dataframe_process/tests/files/missing_required_column.xlsx
Binary file not shown.
Binary file not shown.
20 changes: 16 additions & 4 deletions sheet_dataframe_process/tests/test_module.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from lxml import etree

from odoo.tests.common import TransactionCase


Expand All @@ -14,14 +16,24 @@ def setUpClass(cls):
def test_missing(self):
wiz = self.get_wizard(self.file_records, "missing_required")
self.assertTrue(wiz.partner_id)
self.assertEqual(wiz.missing_cols, "['street']")
comment = sanitize(str(wiz.comment))
root = etree.fromstring(comment)
self.assertEqual(
root.xpath('//div[@id="missing-name-values"]/div')[0].text,
"Missing 'name' values",
)

def test_four_fields(self):
wiz = self.get_wizard(self.file_records, "4_fields")
self.assertFalse(wiz.missing_cols)
# def test_four_fields(self):
# wiz = self.get_wizard(self.file_records, "4_fields")
# self.assertFalse(wiz.missing_cols)

def get_wizard(self, file_recs, file_str):
action = file_recs.filtered(
lambda s, file_str=file_str: file_str in s.name
).try_import()
return self.env["sheet.dataframe.transient"].browse(action.get("res_id"))


def sanitize(string):
string = string.replace("<br>", "<br />")
return string
1 change: 1 addition & 0 deletions sheet_dataframe_process/views/file_field.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
/>
<field name="field_id" context="{'technical_name': 1}" />
<field name="required" />
<field name="check_type" />
</list>
</field>
</record>
Expand Down
91 changes: 62 additions & 29 deletions sheet_dataframe_process/wizards/sheet_dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import polars as pl

from odoo import _, exceptions, fields, models
from odoo import exceptions, fields, models

MODULE = __name__[12 : __name__.index(".", 13)]

Expand All @@ -14,11 +14,10 @@ class SheetDataframeTransient(models.TransientModel):

config_id = fields.Many2one(comodel_name="file.config", required=True)
partner_id = fields.Many2one(comodel_name="res.partner")
comment = fields.Char()
comment = fields.Html(readonly=True)
sample = fields.Html(readonly=True)
filename = fields.Char()
file = fields.Binary(attachment=False)
missing_cols = fields.Char()

def create(self, vals):
res = super().create(vals)
Expand All @@ -28,44 +27,68 @@ def create(self, vals):

def _pre_process(self):
self.ensure_one()
comment = ""
df = pl.read_excel(source=base64.b64decode(self.file))
spe_records = self.config_id.field_match_ids.filtered(
lambda s, df_cols=df.columns: s.matching_column in df_cols
)
partner, specific_names = self._guess_partner(df, spe_records)
attribs = {}
df, specific_recs = self._get_base_info()
partner, specific_names = self._guess_partner(df, specific_recs)
if partner:
self.partner_id = partner.id
self.missing_cols = self._check_missing_cols(df, spe_records, partner)
if self.missing_cols:
comment += _(f"\nMissing columns: {self.missing_cols}")
self._dataframe2html(df)
self.comment = comment
map_cols = self._get_map_cols(df, specific_recs, partner)
# TODO improve miss_col
# attribs["miss_col"] = self._check_missing_cols(df, map_cols)
df = self._rename_df_columns(df, map_cols)
attribs.update(self._check_missing_values(df))
self.sample = f"<pre>\n{self._2html(df)}\n</pre>"
self.comment = "<pre>%s</pre>" % (" ".join(
[
f'<div id="{self._slug_me(key)}"><div>{key}</div>{self._2html(data)}</div>'
for key, data in attribs.items()
])
)
self._reload()

def process(self):
"""
- apply skip to record when required not respected
"""

def _check_missing_value(self, df):
df.rename({"foo": "apple"})
def _get_base_info(self):
df = pl.read_excel(source=base64.b64decode(self.file)).with_row_index(
name="N°", offset=1
)
specific_recs = self.config_id.field_match_ids.filtered(
lambda s, df_cols=df.columns: s.matching_column in df_cols
)
return df, specific_recs

def _check_missing_cols(self, df, spe_records, partner):
map_cols = {
def _get_map_cols(self, df, specific_recs, partner):
return {
x.matching_column: x.field_id.name
for x in spe_records.filtered(lambda s, part=partner: s.partner_id == part)
for x in specific_recs.filtered(
lambda s, part=partner: s.partner_id == part
)
}

def _rename_df_columns(self, df, map_cols):
new_cols = {x: map_cols.get(x) for x in df.columns if x in map_cols}
return df.rename(new_cols)

def _check_missing_values(self, df):
requireds = self.config_id.field_ids.filtered(
lambda s: s.required and s.field_id.name in df.columns
).mapped("field_id.name")
dico = {}
for req in requireds:
res = df.filter(pl.col(req).is_null())
if len(res):
dico[f"Missing '{req}' values"] = res
return dico

def _check_missing_cols(self, df, map_cols):
file_techn_name_cols = [map_cols.get(x, x) for x in df.columns]
required = self.config_id.field_ids.filtered(lambda s: s.required).mapped(

Check warning on line 83 in sheet_dataframe_process/wizards/sheet_dataframe.py

View check run for this annotation

Codecov / codecov/patch

sheet_dataframe_process/wizards/sheet_dataframe.py#L82-L83

Added lines #L82 - L83 were not covered by tests
"field_id.name"
)
missing = [x for x in required if x not in file_techn_name_cols]
return missing or ""

Check warning on line 87 in sheet_dataframe_process/wizards/sheet_dataframe.py

View check run for this annotation

Codecov / codecov/patch

sheet_dataframe_process/wizards/sheet_dataframe.py#L86-L87

Added lines #L86 - L87 were not covered by tests

def _guess_partner(self, df, spe_records):
def _guess_partner(self, df, specific_recs):
cols_by_part = defaultdict(list)
for line in spe_records:
for line in specific_recs:
cols_by_part[line.partner_id].append(line.matching_column)
if len(cols_by_part) > 1:
self._manage_several_partners(cols_by_part.keys())

Check warning on line 94 in sheet_dataframe_process/wizards/sheet_dataframe.py

View check run for this annotation

Codecov / codecov/patch

sheet_dataframe_process/wizards/sheet_dataframe.py#L94

Added line #L94 was not covered by tests
Expand All @@ -76,9 +99,15 @@ def _guess_partner(self, df, spe_records):
# Not supported case
return False, []

Check warning on line 100 in sheet_dataframe_process/wizards/sheet_dataframe.py

View check run for this annotation

Codecov / codecov/patch

sheet_dataframe_process/wizards/sheet_dataframe.py#L100

Added line #L100 was not covered by tests

def _dataframe2html(self, df):
sample = str(df.__repr__)[:-1].replace("\n", "<br />")
self.sample = f"<pre>\n{sample}\n</pre>"
def process(self):
"""
- apply skip to record when required not respected
"""

def _2html(self, df):
if isinstance(df, pl.dataframe.frame.DataFrame):
return str(df.__repr__)[:-1].replace("\n", "<br />").replace("null", " ")
return df

Check warning on line 110 in sheet_dataframe_process/wizards/sheet_dataframe.py

View check run for this annotation

Codecov / codecov/patch

sheet_dataframe_process/wizards/sheet_dataframe.py#L110

Added line #L110 was not covered by tests

def _reload(self):
action = self.env.ref(
Expand All @@ -91,3 +120,7 @@ def _manage_several_partners(self, partners):
raise exceptions.UserError(

Check warning on line 120 in sheet_dataframe_process/wizards/sheet_dataframe.py

View check run for this annotation

Codecov / codecov/patch

sheet_dataframe_process/wizards/sheet_dataframe.py#L120

Added line #L120 was not covered by tests
f"Several partners found {partners.mapped('name')}:\n\nNot implemented case"
)

def _slug_me(self, string):
string = string.replace("'", "").replace(" ", "-").lower()
return string
2 changes: 1 addition & 1 deletion sheet_dataframe_process/wizards/sheet_dataframe.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@
<field name="name">Process Spreadsheet</field>
<field name="res_model">sheet.dataframe.transient</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="target">inline</field>
</record>
</odoo>

0 comments on commit 8d4d7fc

Please sign in to comment.