fix all pylint warnings, add tests (wip) fix recap

This commit is contained in:
2026-03-06 00:00:01 +01:00
parent 60812652cf
commit b4b4fa7643
25 changed files with 845 additions and 376 deletions

View File

@@ -18,11 +18,24 @@ def generate_html_contract(
reccurents: list[dict],
recurrent_price: float | None = None,
total_price: float | None = None
):
) -> bytes:
"""Generate a html contract
Arguments:
contract(models.Contract): Contract source.
cheques(list[dict]): cheques formated in dict.
occasionals(list[dict]): occasional products.
reccurents(list[dict]): recurrent products.
recurrent_price(float | None = None): total price of recurent products.
total_price(float | None = Non): total price.
Return:
result(bytes): contract file in pdf as bytes.
"""
template_dir = pathlib.Path("./src/contracts/templates").resolve()
template_loader = jinja2.FileSystemLoader(searchpath=template_dir)
template_env = jinja2.Environment(
loader=template_loader, autoescape=jinja2.select_autoescape(["html", "xml"]))
loader=template_loader,
autoescape=jinja2.select_autoescape(["html", "xml"])
)
template_file = "layout.html"
template = template_env.get_template(template_file)
output_text = template.render(
@@ -65,13 +78,16 @@ def generate_html_contract(
def flatten(xss):
"""flatten a list of list.
"""
return [x for xs in xss for x in xs]
def create_column_style_width(size: str) -> odfdo.Style:
"""Create a table columm style for a given width.
Paramenters:
size(str): size of the style (format <number><unit>) unit can be in, cm... see odfdo documentation.
size(str): size of the style (format <number><unit>)
unit can be in, cm... see odfdo documentation.
Returns:
odfdo.Style with the correct column-width attribute.
"""
@@ -85,7 +101,8 @@ def create_column_style_width(size: str) -> odfdo.Style:
def create_row_style_height(size: str) -> odfdo.Style:
"""Create a table height style for a given height.
Paramenters:
size(str): size of the style (format <number><unit>) unit can be in, cm... see odfdo documentation.
size(str): size of the style (format <number><unit>)
unit can be in, cm... see odfdo documentation.
Returns:
odfdo.Style with the correct column-height attribute.
"""
@@ -97,10 +114,17 @@ def create_row_style_height(size: str) -> odfdo.Style:
def create_currency_style(name:str = 'currency-euro'):
"""Create a table currency style.
Paramenters:
name(str): name of the style (default to `currency-euro`).
Returns:
odfdo.Style with the correct column-height attribute.
"""
return odfdo.Element.from_tag(
f"""
<number:currency-style style:name="{name}">
<number:number number:min-integer-digits="1" number:decimal-places="2"/>
<number:number number:min-integer-digits="1"
number:decimal-places="2"/>
<number:text> €</number:text>
</number:currency-style>"""
)
@@ -113,6 +137,18 @@ def create_cell_style(
color: str = '#000000',
currency: bool = False,
) -> odfdo.Style:
"""Create a cell style
Paramenters:
name(str): name of the style (default to `centered-cell`).
font_size(str): font_size of the cell (default to `10pt`).
bold(str): is the text bold (default to `False`).
background_color(str): background_color of the cell
(default to `#FFFFFF`).
color(str): color of the text of the cell (default to `#000000`).
currency(str): is the cell a currency (default to `False`).
Returns:
odfdo.Style with the correct column-height attribute.
"""
bold_attr = """
fo:font-weight="bold"
style:font-weight-asian="bold"
@@ -138,7 +174,13 @@ def create_cell_style(
)
def apply_cell_style(document: odfdo.Document, table: odfdo.Table, currency_cols: list[int]):
def apply_cell_style(
document: odfdo.Document,
table: odfdo.Table,
currency_cols: list[int]
):
"""Apply cell style
"""
document.insert_style(
style=create_currency_style(),
)
@@ -151,7 +193,6 @@ def apply_cell_style(document: odfdo.Document, table: odfdo.Table, currency_cols
color="#FFF"
)
)
body_style_even = document.insert_style(
create_cell_style(
name="body-style-even",
@@ -160,7 +201,6 @@ def apply_cell_style(document: odfdo.Document, table: odfdo.Table, currency_cols
color="#000000",
)
)
body_style_odd = document.insert_style(
create_cell_style(
name="body-style-odd",
@@ -169,7 +209,6 @@ def apply_cell_style(document: odfdo.Document, table: odfdo.Table, currency_cols
color="#000000",
)
)
footer_style = document.insert_style(
create_cell_style(
name="footer-cells",
@@ -177,7 +216,6 @@ def apply_cell_style(document: odfdo.Document, table: odfdo.Table, currency_cols
font_size='12pt',
)
)
body_style_even_currency = document.insert_style(
create_cell_style(
name="body-style-even-currency",
@@ -187,7 +225,6 @@ def apply_cell_style(document: odfdo.Document, table: odfdo.Table, currency_cols
currency=True,
)
)
body_style_odd_currency = document.insert_style(
create_cell_style(
name="body-style-odd-currency",
@@ -197,7 +234,6 @@ def apply_cell_style(document: odfdo.Document, table: odfdo.Table, currency_cols
currency=True,
)
)
footer_style_currency = document.insert_style(
create_cell_style(
name="footer-cells-currency",
@@ -206,7 +242,6 @@ def apply_cell_style(document: odfdo.Document, table: odfdo.Table, currency_cols
currency=True,
)
)
for index, row in enumerate(table.get_rows()):
style = body_style_even
currency_style = body_style_even_currency
@@ -228,7 +263,12 @@ def apply_cell_style(document: odfdo.Document, table: odfdo.Table, currency_cols
cell.style = style
def apply_column_height_style(document: odfdo.Document, table: odfdo.Table):
def apply_column_height_style(
document: odfdo.Document,
table: odfdo.Table
):
"""Apply column height for a given table
"""
header_style = document.insert_style(
style=create_row_style_height('1.60cm'), name='1.60cm', automatic=True
)
@@ -241,19 +281,29 @@ def apply_column_height_style(document: odfdo.Document, table: odfdo.Table):
else:
row.style = body_style
def apply_cell_style_by_column(table: odfdo.Table, style: odfdo.Style, col_index: int):
def apply_cell_style_by_column(
table: odfdo.Table,
style: odfdo.Style,
col_index: int
):
"""Apply cell style for a given table
"""
for cell in table.get_column_cells(col_index):
print(cell.style)
cell.style = style
print(cell.serialize())
def apply_column_width_style(document: odfdo.Document, table: odfdo.Table, widths: list[str]):
def apply_column_width_style(
document: odfdo.Document,
table: odfdo.Table,
widths: list[str]
):
"""Apply column width style to a table.
Parameters:
document(odfdo.Document): Document where the table is located.
table(odfdo.Table): Table to apply columns widths.
widths(list[str]): list of width in format <number><unit> unit ca be in, cm... see odfdo documentation.
widths(list[str]): list of width in format <number><unit> unit ca be
in, cm... see odfdo documentation.
"""
styles = []
for w in widths:
@@ -268,6 +318,12 @@ def apply_column_width_style(document: odfdo.Document, table: odfdo.Table, width
def generate_ods_letters(n: int):
"""Generate letters following excel format.
Arguments:
n(int): `n` letters to generate.
Return:
result(list[str]): list of `n` letters that follow excel pattern.
"""
letters = string.ascii_lowercase
result = []
for i in range(n):
@@ -282,6 +338,8 @@ def generate_ods_letters(n: int):
def compute_contract_prices(contract: models.Contract) -> dict:
"""Compute price for a give contract.
"""
occasional_contract_products = list(
filter(
lambda contract_product: (
@@ -313,6 +371,8 @@ def compute_contract_prices(contract: models.Contract) -> dict:
def transform_formula_cells(sheet: odfdo.Spreadsheet):
"""Transform cell value to a formula using odfdo.
"""
for row in sheet.get_rows():
for cell in row.get_cells():
if not cell.value or cell.get_attribute("office:value-type") == "float":
@@ -330,6 +390,8 @@ def merge_shipment_cells(
occasionnals: list[str],
shipments: list[models.Shipment]
):
"""Merge cells for shipment header.
"""
index = len(prefix_header) + len(recurrents) + 1
for _ in enumerate(shipments):
startcol = index
@@ -341,19 +403,23 @@ def generate_recap(
contracts: list[models.Contract],
form: models.Form,
):
"""Generate excel recap for a list of contracts.
"""
product_unit_map = {
'1': 'g',
'2': 'Kg',
'3': 'Piece'
}
recurrents = [
f'{pr.name}{f' - {pr.quantity}{pr.quantity_unit}' if pr.quantity else ''} ({product_unit_map[pr.unit]})'
f'{pr.name}{f' - {pr.quantity}{pr.quantity_unit}'
if pr.quantity else ''} ({product_unit_map[pr.unit]})'
for pr in form.productor.products
if pr.type == models.ProductType.RECCURENT
]
recurrents.sort()
occasionnals = [
f'{pr.name}{f' - {pr.quantity}{pr.quantity_unit}' if pr.quantity else ''} ({product_unit_map[pr.unit]})'
f'{pr.name}{f' - {pr.quantity}{pr.quantity_unit}'
if pr.quantity else ''} ({product_unit_map[pr.unit]})'
for pr in form.productor.products
if pr.type == models.ProductType.OCCASIONAL
]
@@ -402,7 +468,8 @@ def generate_recap(
len(info_header)+len(payment_formula_letters)+len(recurrents) + 1
]
occasionnals_formula_letters = letters[
len(info_header)+len(payment_formula_letters)+len(recurent_formula_letters):
len(info_header)+len(payment_formula_letters)+
len(recurent_formula_letters):
len(info_header)+len(payment_formula_letters) +
len(recurent_formula_letters)+len(occasionnals_header) + 1
]
@@ -421,11 +488,17 @@ def generate_recap(
for index, contract in enumerate(contracts):
prices = compute_contract_prices(contract)
occasionnal_sorted = sorted(
[product for product in contract.products if product.product.type == models.ProductType.OCCASIONAL],
[
product for product in contract.products
if product.product.type == models.ProductType.OCCASIONAL
],
key=lambda x: (x.shipment.name, x.product.name)
)
recurrent_sorted = sorted(
[product for product in contract.products if product.product.type == models.ProductType.RECCURENT],
[
product for product in contract.products
if product.product.type == models.ProductType.RECCURENT
],
key=lambda x: x.product.name
)