SPB Git forge

spb/uqo-chat

Public
14commits 1branches 0releases
1.4 MBsize
maindefault branch
17 days agolast push
Python 64.6% TypeScript 33.7% CSS 0.8%
5.6 KB · 105 lines python
Raw Blame History
1import io23import pytest4from openpyxl import load_workbook56from app.tools import excel_ops7from app.tools.appraisal_calc import FUNCS8from app.tools.create_docx import build as build_docx9from app.tools.create_excel import build_workbook10from app.tools.excel_templates import TEMPLATES11from app.tools.make_chart import render12from app.tools.unit_convert import convert131415def _workbook() -> bytes:16    return build_workbook(TEMPLATES["comparables_ajustes"]({}))[0]171819def test_inspect_and_preview() -> None:20    data = _workbook()21    info = excel_ops.inspect(data)22    assert any(s["name"] == "Comparables" for s in info["sheets"])23    assert any("=" in line for s in info["sheets"] for line in s["cells"])24    pv = excel_ops.preview(data)25    assert pv["sheet"] == "Comparables" and len(pv["all"]) >= 2262728def test_edit_operations_add_column_row_sheet_chart() -> None:29    data = _workbook()30    hr = excel_ops._header_row(load_workbook(io.BytesIO(data))["Comparables"])31    new, log = excel_ops.apply_operations(data, [32        {"op": "add_column", "sheet": "Comparables", "header": "Piscine ($)", "formula": "=B{r}*0.02", "format": "currency"},33        {"op": "set_cell", "sheet": "Comparables", "cell": "B4", "value": "1 250 pi²", "input": True},34        {"op": "add_sheet", "name": "Synthèse", "title": "Synthèse", "table": {"columns": ["Poste", "Montant ($)"],35                                                                                 "rows": [["Terrain", "120 000 $"], ["Bâtiment", 300000]],36                                                                                 "totals": {"label": "Total", "formula": "=B5+B6"}}},37        {"op": "add_chart", "sheet": "Synthèse", "type": "pie", "categories_range": "A5:A6", "values_range": "B5:B6", "anchor": "E4"},38        {"op": "add_note", "sheet": "Comparables", "cell": "A1", "text": "Grille révisée"},39        {"op": "format", "sheet": "Comparables", "range": "B4:B4", "format": "area", "bold": True},40    ])41    wb = load_workbook(io.BytesIO(new))42    ws = wb["Comparables"]43    headers = [c.value for c in ws[hr]]44    assert "Piscine ($)" in headers45    col = headers.index("Piscine ($)") + 146    assert ws.cell(row=hr + 1, column=col).value == f"=B{hr + 1}*0.02"47    assert ws["B4"].value == 1250 and ws["A1"].comment is not None48    assert "Synthèse" in wb.sheetnames and wb["Synthèse"]["B7"].value == "=B5+B6"49    assert len(log) == 6505152def test_edit_unknown_op_raises() -> None:53    with pytest.raises(excel_ops.ExcelOpError):54        excel_ops.apply_operations(_workbook(), [{"op": "explode"}])555657def test_appraisal_functions() -> None:58    ca = FUNCS["cost_approach"]({"land_value": "120 000 $", "cost_new": 322000, "effective_age": 15, "economic_life": 60})59    assert round(ca["value"]) == 36150060    bd = FUNCS["breakdown_depreciation"]({61        "cost_new": 500000,62        "curable_physical": [{"item": "peinture", "cost_to_cure": 8000}],63        "short_lived": [{"item": "toiture", "cost_new": 30000, "effective_age": 10, "life": 20}],64        "long_lived": {"effective_age": 15, "economic_life": 60},65        "functional": [{"item": "cuisine", "type": "déficience", "cost_to_cure": 25000, "cost_if_new": 15000}],66        "external": {"rent_loss_annual": 2400, "cap_rate": "8 %", "building_share": 0.8},67    })68    assert bd["components"]["curable_physical"] == 8000 and bd["components"]["short_lived"] == 1500069    assert round(bd["components"]["long_lived"]) == round((500000 - 8000 - 30000) * 15 / 60)70    assert bd["components"]["functional"] == 10000 and round(bd["components"]["external"]) == 2400071    grid = FUNCS["adjust_comparables"]({72        "subject": {"superficie": 1200, "garage": "Oui", "etat": "bon"},73        "rates": {"superficie": 120, "garage": 15000, "etat": 10000},74        "monthly_trend": "0,5 %",75        "comparables": [{"address": "A", "price": 425000, "months": 6, "superficie": 1150, "garage": "Oui", "etat": "bon"},76                        {"address": "B", "price": 398000, "months": 8, "superficie": 1250, "garage": "Non", "etat": "moyen"}],77    })78    a = grid["comparables"][0]79    assert round(a["time_adjusted"]) == round(425000 * 1.03) and a["adjustments"]["superficie"] == 600080    b = grid["comparables"][1]81    assert b["adjustments"]["garage"] == 15000 and b["adjustments"]["etat"] == 1000082    assert grid["stats"]["least_adjusted"] == "A"83    dc = FUNCS["direct_capitalization"]({"potential_gross_income": 100000, "vacancy_pct": 5, "operating_expenses": 40000, "cap_rate": 7})84    assert round(dc["value"]) == round(55000 / 0.07)858687def test_unit_convert() -> None:88    assert abs(convert(100, "m2", "pi2")["result"] - 1076.39) < 0.0189    assert abs(convert(2450, "$/m2", "$/pi2")["result"] - 227.61) < 0.0190    assert abs(convert(1, "arpent", "m2")["result"] - 3418.894) < 0.0191    with pytest.raises(ValueError):92        convert(1, "m2", "pi")939495def test_make_chart_and_docx() -> None:96    png = render({"type": "bar", "title": "Prix ajustés", "x": ["A", "B", "C"],97                  "series": [{"name": "Prix", "values": [425000, "398 000 $", 449000]}], "value_format": "currency",98                  "annotate": True})99    assert png[:8] == b"\x89PNG\r\n\x1a\n" and len(png) > 5000100    docx = build_docx({"title": "Fiche — Dépréciation", "course": "IMM1033", "subtitle": "",101                       "markdown": "# Définitions\n\nLa **dépréciation** est $D = \\frac{A_e}{DVE} \\times C_N$.\n\n"102                                   "- physique\n- fonctionnelle\n\n| Type | Exemple |\n|---|---|\n| Physique | toiture |\n\n"103                                   "1. étape un\n2. étape deux\n\n> Rappel : le terrain ne se déprécie pas."})104    assert docx[:2] == b"PK" and len(docx) > 10000105