grosze
This commit is contained in:
+48
-2
@@ -190,17 +190,63 @@ async def nbp_rate():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
CSV_MONEY_FIELDS = {
|
||||||
|
"rata",
|
||||||
|
"kapital",
|
||||||
|
"odsetki",
|
||||||
|
"nadplata",
|
||||||
|
"prowizja_nadplaty",
|
||||||
|
"saldo",
|
||||||
|
"odsetki_narastajaco",
|
||||||
|
"koszt_narastajaco",
|
||||||
|
"nadplaty_narastajaco",
|
||||||
|
}
|
||||||
|
CSV_SUMMARY_MONEY_FIELDS = {
|
||||||
|
"total_paid",
|
||||||
|
"total_interest",
|
||||||
|
"total_overpayment",
|
||||||
|
"total_overpayment_fees",
|
||||||
|
"interest_saved",
|
||||||
|
"baseline_interest",
|
||||||
|
"average_payment",
|
||||||
|
"max_payment",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _csv_money(value: float) -> str:
|
||||||
|
return f"{float(value):.2f}".replace(".", ",")
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/export/csv")
|
@app.post("/api/export/csv")
|
||||||
def export_csv(req: SimulationRequest):
|
def export_csv(req: SimulationRequest):
|
||||||
result = simulate(req)
|
result = simulate(req)
|
||||||
buf = io.StringIO()
|
buf = io.StringIO()
|
||||||
writer = csv.writer(buf, delimiter=";")
|
writer = csv.writer(buf, delimiter=";")
|
||||||
writer.writerow(["miesiac", "data_splaty", "dni", "oprocentowanie", "rata", "kapital", "odsetki", "nadplata", "prowizja_nadplaty", "saldo", "karencja", "odsetki_narastajaco", "koszt_narastajaco", "nadplaty_narastajaco"])
|
headers = ["miesiac", "data_splaty", "dni", "oprocentowanie", "rata", "kapital", "odsetki", "nadplata", "prowizja_nadplaty", "saldo", "karencja", "odsetki_narastajaco", "koszt_narastajaco", "nadplaty_narastajaco"]
|
||||||
|
writer.writerow(headers)
|
||||||
for row in result.schedule:
|
for row in result.schedule:
|
||||||
writer.writerow([row.month, row.due_date, row.days, row.rate, row.payment, row.principal_part, row.interest_part, row.overpayment, row.overpayment_fee, row.remaining, row.grace_type.value, row.cumulative_interest, row.cumulative_cost, row.cumulative_overpayment])
|
values = {
|
||||||
|
"miesiac": row.month,
|
||||||
|
"data_splaty": row.due_date,
|
||||||
|
"dni": row.days,
|
||||||
|
"oprocentowanie": row.rate,
|
||||||
|
"rata": row.payment,
|
||||||
|
"kapital": row.principal_part,
|
||||||
|
"odsetki": row.interest_part,
|
||||||
|
"nadplata": row.overpayment,
|
||||||
|
"prowizja_nadplaty": row.overpayment_fee,
|
||||||
|
"saldo": row.remaining,
|
||||||
|
"karencja": row.grace_type.value,
|
||||||
|
"odsetki_narastajaco": row.cumulative_interest,
|
||||||
|
"koszt_narastajaco": row.cumulative_cost,
|
||||||
|
"nadplaty_narastajaco": row.cumulative_overpayment,
|
||||||
|
}
|
||||||
|
writer.writerow([_csv_money(values[h]) if h in CSV_MONEY_FIELDS else values[h] for h in headers])
|
||||||
writer.writerow([])
|
writer.writerow([])
|
||||||
writer.writerow(["Podsumowanie"])
|
writer.writerow(["Podsumowanie"])
|
||||||
for key, value in result.summary.model_dump().items():
|
for key, value in result.summary.model_dump().items():
|
||||||
|
if key in CSV_SUMMARY_MONEY_FIELDS:
|
||||||
|
value = _csv_money(value)
|
||||||
writer.writerow([key, value])
|
writer.writerow([key, value])
|
||||||
data = buf.getvalue().encode("utf-8-sig")
|
data = buf.getvalue().encode("utf-8-sig")
|
||||||
return StreamingResponse(
|
return StreamingResponse(
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
const $ = (id) => document.getElementById(id);
|
const $ = (id) => document.getElementById(id);
|
||||||
const money = (v) => new Intl.NumberFormat('pl-PL', { style: 'currency', currency: 'PLN', maximumFractionDigits: 0 }).format(v || 0);
|
const money = (v) => new Intl.NumberFormat('pl-PL', { style: 'currency', currency: 'PLN', minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(Number(v) || 0);
|
||||||
const num = (id) => Number($(id).value || 0);
|
const num = (id) => Number($(id).value || 0);
|
||||||
|
|
||||||
let lineChart, pieChart, barChart, detailChart;
|
let lineChart, pieChart, barChart, detailChart;
|
||||||
|
|||||||
@@ -13,13 +13,13 @@
|
|||||||
<div class="card-body d-flex flex-wrap align-items-center justify-content-between gap-3">
|
<div class="card-body d-flex flex-wrap align-items-center justify-content-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="h3 mb-1">Symulator kredytu hipotecznego</h1>
|
<h1 class="h3 mb-1">Symulator kredytu hipotecznego</h1>
|
||||||
<p class="text-muted mb-0">@linuxiarz.pl</p>
|
<p class="text-muted mb-0">Dane liczone są w backendzie ale nie są przechowywane na serwerze, może swoje wyliczenia eksportować na na swój dysk</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex gap-2 flex-wrap justify-content-end">
|
<div class="d-flex gap-2 flex-wrap justify-content-end">
|
||||||
<button id="themeToggle" class="btn btn-outline-secondary btn-sm" type="button" aria-label="Przełącz motyw">☀️ Jasny</button>
|
<button id="themeToggle" class="btn btn-outline-secondary btn-sm" type="button" aria-label="Przełącz motyw">☀️ Jasny</button>
|
||||||
<button id="loadNbp" class="btn btn-outline-primary btn-sm">Pobierz stopę NBP</button>
|
<button id="loadNbp" class="btn btn-outline-primary btn-sm">Pobierz stopę NBP</button>
|
||||||
<button id="exportJson" class="btn btn-outline-secondary btn-sm">Eksport JSON</button>
|
<button id="exportJson" class="btn btn-outline-secondary btn-sm">Eksport</button>
|
||||||
<button id="importJson" class="btn btn-outline-secondary btn-sm">Import JSON</button>
|
<button id="importJson" class="btn btn-outline-secondary btn-sm">Import </button>
|
||||||
<button id="exportCsv" class="btn btn-outline-secondary btn-sm">CSV</button>
|
<button id="exportCsv" class="btn btn-outline-secondary btn-sm">CSV</button>
|
||||||
<button id="exportPdf" class="btn btn-primary btn-sm">PDF</button>
|
<button id="exportPdf" class="btn btn-primary btn-sm">PDF</button>
|
||||||
<input id="jsonFile" type="file" accept="application/json,.json" hidden>
|
<input id="jsonFile" type="file" accept="application/json,.json" hidden>
|
||||||
|
|||||||
Reference in New Issue
Block a user