feat: rework admin portal with pricing breakdown and document management

- Added pricing snapshot columns to the leads table: daily_subtotal, weekend_subtotal, subtotal_eur, vat_eur, total_eur, deposit_eur, total_days, weekday_count, weekend_day_count.
- Updated create_lead RPC to accept and store new pricing parameters.
- Enhanced frontend app.js to compute and send pricing details during lead creation.
- Introduced new UI elements in admin.html for displaying pricing and documents in a tabbed dialog.
- Updated i18n.js with new translation keys for pricing and document management.
- Improved styles in styles.css for new dialog components and pricing cards.
- Added migration script 06-admin-pricing-documents.sql for database schema changes.
This commit is contained in:
LagoESP
2026-04-29 17:27:37 +02:00
parent bc61ffa206
commit 30e296f61b
9 changed files with 1187 additions and 40 deletions
+34 -9
View File
@@ -410,16 +410,41 @@ document.querySelector("#bpfSubmit").addEventListener("click", async () => {
bookingFeedback.textContent = "...";
const vehicle = state.vehicles.find(v => v.id === bpfCar.value);
const { from, to } = getBpfDates();
const vFrom = parseYmdLocal(from);
const vTo = parseYmdLocal(to);
let weekdayCost = 0, weekendCost = 0, subtotal = 0, vat = 0, total = 0, deposit = 0;
let totalDays = 0, weekdays = 0, weekendDays = 0;
if (vehicle && vFrom && vTo && vTo > vFrom) {
totalDays = Math.ceil((vTo - vFrom) / (1000 * 60 * 60 * 24));
weekendDays = bpfDurationMode === "weekend" ? 2 : calcWeekendDays(from, to);
weekdays = bpfDurationMode === "weekend" ? 0 : (totalDays - weekendDays);
weekdayCost = weekdays * vehicle.daily_price_eur;
weekendCost = weekendDays * (vehicle.weekend_price_eur || vehicle.daily_price_eur);
subtotal = weekdayCost + weekendCost;
vat = Math.round(subtotal * 0.20);
total = subtotal + vat;
deposit = vehicle.kaution_eur || 5000;
}
const payload = {
p_name: bpfName.value,
p_email: bpfEmail.value,
p_phone: bpfPhone.value || "",
p_vehicle_id: bpfCar.value || null,
p_vehicle_label: vehicle ? `${vehicle.brand} ${vehicle.model}` : "",
p_date_from: bpfFrom.value || null,
p_date_to: bpfTo.value || null,
p_message: bpfMessage.value || "",
p_source: "website",
p_name: bpfName.value,
p_email: bpfEmail.value,
p_phone: bpfPhone.value || "",
p_vehicle_id: bpfCar.value || null,
p_vehicle_label: vehicle ? `${vehicle.brand} ${vehicle.model}` : "",
p_date_from: bpfFrom.value || null,
p_date_to: bpfTo.value || null,
p_message: bpfMessage.value || "",
p_source: "website",
p_daily_subtotal: weekdayCost,
p_weekend_subtotal: weekendCost,
p_subtotal_eur: subtotal,
p_vat_eur: vat,
p_total_eur: total,
p_deposit_eur: deposit,
p_total_days: totalDays,
p_weekday_count: weekdays,
p_weekend_day_count: weekendDays,
};
// Create lead via RPC (returns inserted id without anon SELECT privileges)