zestawienia
This commit is contained in:
+131
-1
@@ -101,6 +101,51 @@ def parse_fuel_entry_form(entry):
|
||||
entry.wholesale_source = (request.form.get("wholesale_source") or "").strip() or None
|
||||
return vehicle
|
||||
|
||||
|
||||
def calculate_entry_settlement(entry, fallback_settings=None):
|
||||
"""Calculate retail, invoice and effective company cost for one fuel entry."""
|
||||
entry_settings = entry.vehicle.company or (entry.vehicle.owner.company if entry.vehicle and entry.vehicle.owner else None) or fallback_settings or CompanySettings.query.first()
|
||||
vat_rate = effective_vat_rate(entry_settings.vat_rate, entry.fueled_at)
|
||||
vat_deduction_percent = entry_settings.vat_deduction_percent
|
||||
retail_price = Decimal(entry.price_per_liter)
|
||||
rule = FuelCardStationRule.query.filter_by(
|
||||
fuel_card_id=entry.fuel_card_id,
|
||||
station_company_id=entry.station_company_id,
|
||||
).first() if entry.used_fuel_card and entry.fuel_card_id and entry.station_company_id else None
|
||||
uses_last_price = bool(rule and rule.use_orlen_last_price and entry.wholesale_price is not None)
|
||||
|
||||
if uses_last_price:
|
||||
settlement_net = Decimal(entry.wholesale_price)
|
||||
else:
|
||||
settlement_net = retail_price / (Decimal("1") + Decimal(str(vat_rate)) / Decimal("100"))
|
||||
if rule:
|
||||
settlement_net *= Decimal("1") - Decimal(rule.discount_net_percent or 0) / Decimal("100")
|
||||
settlement_net += Decimal(rule.surcharge_net_per_liter or 0)
|
||||
settlement_net = max(settlement_net, Decimal("0"))
|
||||
|
||||
price_costs = calculate_net_price_costs(settlement_net, vat_rate, vat_deduction_percent)
|
||||
liters = Decimal(entry.liters)
|
||||
retail_gross = retail_price * liters
|
||||
invoice_gross = price_costs["invoice_gross"] * liters
|
||||
deductible_vat = price_costs["deductible_vat"] * liters
|
||||
effective_cost = price_costs["effective_cost"] * liters
|
||||
last_price_saving = retail_gross - invoice_gross if uses_last_price else Decimal("0")
|
||||
return {
|
||||
"liters": liters,
|
||||
"retail_price": retail_price,
|
||||
"settlement_net": settlement_net,
|
||||
"invoice_price": price_costs["invoice_gross"],
|
||||
"effective_price": price_costs["effective_cost"],
|
||||
"retail_gross": retail_gross,
|
||||
"invoice_gross": invoice_gross,
|
||||
"deductible_vat": deductible_vat,
|
||||
"effective_cost": effective_cost,
|
||||
"last_price_saving": last_price_saving,
|
||||
"uses_last_price": uses_last_price,
|
||||
"vat_rate": Decimal(str(vat_rate)),
|
||||
"vat_deduction_percent": Decimal(str(vat_deduction_percent)),
|
||||
}
|
||||
|
||||
def accessible_vehicles():
|
||||
if current_user.role == "admin":
|
||||
return Vehicle.query.order_by(Vehicle.name).all()
|
||||
@@ -118,7 +163,7 @@ def dashboard():
|
||||
try: year, mon = map(int, month.split("-"))
|
||||
except ValueError: year, mon = datetime.now().year, datetime.now().month; month=f"{year:04d}-{mon:02d}"
|
||||
entries = FuelEntry.query.filter(FuelEntry.vehicle_id.in_(ids), extract("year", FuelEntry.fueled_at)==year, extract("month", FuelEntry.fueled_at)==mon).order_by(FuelEntry.fueled_at.desc()).all() if ids else []
|
||||
totals = {"gross": Decimal("0"), "deductible_vat": Decimal("0"), "final_cost": Decimal("0"), "liters": Decimal("0")}
|
||||
totals = {"gross": Decimal("0"), "deductible_vat": Decimal("0"), "final_cost": Decimal("0"), "liters": Decimal("0"), "last_price_saving": Decimal("0")}
|
||||
by_vehicle = defaultdict(lambda: {"gross": 0, "payable": 0, "liters": 0}); invoices = defaultdict(lambda: {"gross": 0, "payable": 0, "count": 0}); settlements = {}
|
||||
for e in entries:
|
||||
entry_settings = e.vehicle.company or settings
|
||||
@@ -148,6 +193,8 @@ def dashboard():
|
||||
totals["deductible_vat"] += deductible_vat
|
||||
totals["final_cost"] += effective_gross
|
||||
totals["liters"] += liters
|
||||
last_price_saving = Decimal(str(e.gross)) - invoice_gross if uses_station_last_price else Decimal("0")
|
||||
totals["last_price_saving"] += last_price_saving
|
||||
settlements[e.id] = {
|
||||
"normal_price": normal_price,
|
||||
"net_price": float(settlement_net),
|
||||
@@ -157,6 +204,7 @@ def dashboard():
|
||||
"invoice_gross": float(invoice_gross),
|
||||
"payable_gross": float(effective_gross),
|
||||
"uses_last_price": uses_station_last_price,
|
||||
"last_price_saving": float(last_price_saving),
|
||||
"vat_rate": float(vat_rate),
|
||||
"vat_deduction_percent": float(vat_deduction_percent),
|
||||
}
|
||||
@@ -456,6 +504,88 @@ def orlen_sync():
|
||||
|
||||
|
||||
|
||||
|
||||
@main.get("/admin/reports")
|
||||
@login_required
|
||||
@roles("boss", "admin")
|
||||
def admin_reports():
|
||||
today = date.today()
|
||||
period = request.args.get("period", "month")
|
||||
company_id = request.args.get("company_id", type=int)
|
||||
month = request.args.get("month", today.strftime("%Y-%m"))
|
||||
year = request.args.get("year", today.year, type=int)
|
||||
date_from_raw = request.args.get("date_from", "")
|
||||
date_to_raw = request.args.get("date_to", "")
|
||||
|
||||
if current_user.role == "boss":
|
||||
company_id = current_user.company_id
|
||||
companies = CompanySettings.query.order_by(CompanySettings.name).all() if current_user.role == "admin" else [current_user.company]
|
||||
|
||||
try:
|
||||
if period == "year":
|
||||
start_date, end_date = date(year, 1, 1), date(year, 12, 31)
|
||||
elif period == "custom":
|
||||
start_date = date.fromisoformat(date_from_raw)
|
||||
end_date = date.fromisoformat(date_to_raw)
|
||||
if end_date < start_date:
|
||||
raise ValueError
|
||||
else:
|
||||
period = "month"
|
||||
selected_year, selected_month = map(int, month.split("-"))
|
||||
start_date = date(selected_year, selected_month, 1)
|
||||
if selected_month == 12:
|
||||
end_date = date(selected_year, 12, 31)
|
||||
else:
|
||||
end_date = date(selected_year, selected_month + 1, 1)
|
||||
end_date = date.fromordinal(end_date.toordinal() - 1)
|
||||
except (TypeError, ValueError):
|
||||
period = "month"
|
||||
month = today.strftime("%Y-%m")
|
||||
start_date = date(today.year, today.month, 1)
|
||||
next_month = date(today.year + (today.month == 12), 1 if today.month == 12 else today.month + 1, 1)
|
||||
end_date = date.fromordinal(next_month.toordinal() - 1)
|
||||
|
||||
query = FuelEntry.query.join(Vehicle).join(User, Vehicle.owner_id == User.id).filter(
|
||||
FuelEntry.fueled_at >= datetime.combine(start_date, datetime.min.time()),
|
||||
FuelEntry.fueled_at < datetime.combine(date.fromordinal(end_date.toordinal() + 1), datetime.min.time()),
|
||||
)
|
||||
if company_id:
|
||||
query = query.filter(or_(Vehicle.company_id == company_id, and_(Vehicle.company_id.is_(None), User.company_id == company_id)))
|
||||
entries = query.order_by(FuelEntry.fueled_at.asc()).all()
|
||||
|
||||
zero = Decimal("0")
|
||||
totals = {"retail": zero, "invoice": zero, "effective": zero, "vat_deducted": zero, "saving": zero, "liters": zero, "count": 0, "last_price_count": 0}
|
||||
by_month = defaultdict(lambda: {"retail": 0.0, "invoice": 0.0, "effective": 0.0, "saving": 0.0, "liters": 0.0, "count": 0})
|
||||
by_vehicle = defaultdict(lambda: {"retail": 0.0, "invoice": 0.0, "effective": 0.0, "saving": 0.0, "liters": 0.0, "count": 0})
|
||||
by_company = defaultdict(lambda: {"retail": 0.0, "invoice": 0.0, "effective": 0.0, "saving": 0.0, "liters": 0.0, "count": 0})
|
||||
|
||||
for entry in entries:
|
||||
row = calculate_entry_settlement(entry)
|
||||
totals["retail"] += row["retail_gross"]
|
||||
totals["invoice"] += row["invoice_gross"]
|
||||
totals["effective"] += row["effective_cost"]
|
||||
totals["vat_deducted"] += row["deductible_vat"]
|
||||
totals["saving"] += row["last_price_saving"]
|
||||
totals["liters"] += row["liters"]
|
||||
totals["count"] += 1
|
||||
totals["last_price_count"] += int(row["uses_last_price"])
|
||||
company = entry.vehicle.company or entry.vehicle.owner.company
|
||||
keys = ((by_month, entry.fueled_at.strftime("%Y-%m")), (by_vehicle, entry.vehicle.name), (by_company, company.name if company else "Bez firmy"))
|
||||
for bucket, key in keys:
|
||||
bucket[key]["retail"] += float(row["retail_gross"])
|
||||
bucket[key]["invoice"] += float(row["invoice_gross"])
|
||||
bucket[key]["effective"] += float(row["effective_cost"])
|
||||
bucket[key]["saving"] += float(row["last_price_saving"])
|
||||
bucket[key]["liters"] += float(row["liters"])
|
||||
bucket[key]["count"] += 1
|
||||
|
||||
totals["saving_percent"] = (totals["saving"] / totals["retail"] * Decimal("100")) if totals["retail"] else zero
|
||||
return render_template(
|
||||
"admin_reports.html", companies=[c for c in companies if c], company_id=company_id, period=period, month=month, year=year,
|
||||
date_from=date_from_raw, date_to=date_to_raw, start_date=start_date, end_date=end_date, totals=totals,
|
||||
by_month=dict(sorted(by_month.items())), by_vehicle=dict(sorted(by_vehicle.items())), by_company=dict(sorted(by_company.items())),
|
||||
)
|
||||
|
||||
@main.get("/admin/fuel-entries")
|
||||
@login_required
|
||||
@roles("boss", "admin")
|
||||
|
||||
Reference in New Issue
Block a user