added script for calculating auto useage

This commit is contained in:
2025-11-04 22:45:12 -05:00
parent 45a27b01f3
commit b8bb71900d
3 changed files with 208 additions and 2 deletions

205
app/routers/fixstuff.py Normal file
View File

@@ -0,0 +1,205 @@
from fastapi import APIRouter
from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder
from database import session
from sqlalchemy import func
from datetime import date
from decimal import Decimal
from app.models.auto import Auto_Delivery, Tickets_Auto_Delivery, Auto_Temp
from app.models.delivery import Delivery
# Constants from fuel_estimator
HOT_WATER_DAILY_USAGE = Decimal('2.0')
K_FACTOR_SMOOTHING_WEIGHT = Decimal('0.7')
router = APIRouter(
prefix="/fixstuff",
tags=["fixstuff"],
responses={404: {"description": "Not found"}},
)
@router.get("/lastdelivered", status_code=200)
def fix_customer_last_delivered():
"""
Updates the last_fill date in the auto_delivery table for each customer
by finding the most recent completed delivery (ticket with non-NULL fill_date)
from the auto_tickets table, matched by account_number.
Returns statistics and a list of changes made.
"""
auto_deliveries = session.query(Auto_Delivery).all()
changes = []
total_customers = len(auto_deliveries)
tickets_found = 0
updates_made = 0
for ad in auto_deliveries:
latest_ticket = session.query(Tickets_Auto_Delivery).filter(
Tickets_Auto_Delivery.account_number == ad.account_number,
Tickets_Auto_Delivery.fill_date.isnot(None)
).order_by(Tickets_Auto_Delivery.fill_date.desc()).first()
if latest_ticket:
tickets_found += 1
if ad.last_fill != latest_ticket.fill_date:
updates_made += 1
old_date = ad.last_fill
ad.last_fill = latest_ticket.fill_date
changes.append({
"id": ad.id,
"customer_full_name": ad.customer_full_name,
"before_date": str(old_date) if old_date else None,
"new_date": str(latest_ticket.fill_date)
})
session.add(ad)
session.commit()
result = {
"total_customers": total_customers,
"tickets_found": tickets_found,
"updates_made": updates_made,
"changes": changes
}
return JSONResponse(content=jsonable_encoder(result))
@router.get("/estimate_gallons/{update_db}", status_code=200)
def estimate_customer_gallons(update_db: int):
"""
Estimates current gallons for each customer based on delivery history and weather.
update_db: 0 for estimation only (no DB changes), 1 for estimation with DB updates.
No tickets: assume 100 gallons. Single delivery: use weather for 2000 sq ft home.
Multiple deliveries: use historical average. Includes address and scaling factor.
When update_db=1, updates estimated_gallons_left and house_factor in database.
"""
auto_deliveries = session.query(Auto_Delivery).all()
estimates = []
for ad in auto_deliveries:
tickets = session.query(Tickets_Auto_Delivery).filter(
Tickets_Auto_Delivery.account_number == ad.account_number,
Tickets_Auto_Delivery.fill_date.isnot(None)
).order_by(Tickets_Auto_Delivery.fill_date).all()
# Get tank size and hot water setting
tank_size = Decimal(ad.tank_size) if ad.tank_size else Decimal('275')
# Adjust effective tank capacity (not filled to 100%)
if tank_size == 275:
effective_tank = Decimal('250')
elif tank_size == 330:
effective_tank = Decimal('300')
else:
effective_tank = tank_size
hot_water = ad.hot_water_summer == 1
calculated_scaling = None # For DB update
if not tickets:
estimated_gallons = Decimal('100')
else:
last_fill = tickets[-1].fill_date
estimated_gallons_left = effective_tank
today = date.today()
if len(tickets) == 1:
# Single delivery: use weather data for 2000 sq ft home, only heat when temp <=70
if last_fill < today:
# Get daily weather data
temp_days = session.query(Auto_Temp).filter(
Auto_Temp.todays_date > last_fill,
Auto_Temp.todays_date <= today
).all()
heating_usage = Decimal('0')
hot_water_usage = Decimal('0')
house_factor_2000_sqft = Decimal('0.005') # gallons per degree day
for temp in temp_days:
degree_day = max(0, 65 - float(temp.temp_avg))
heating_usage += house_factor_2000_sqft * Decimal(degree_day)
if hot_water:
hot_water_usage += HOT_WATER_DAILY_USAGE
total_usage = heating_usage + hot_water_usage
estimated_gallons_left = max(Decimal('0'), estimated_gallons_left - total_usage)
else:
# Multiple deliveries: calculate house_factor (gallons per degree day)
daily_heating_usages = []
avg_degree_per_days = []
for i in range(len(tickets) - 1):
prev_ticket = tickets[i]
next_ticket = tickets[i + 1]
days = (next_ticket.fill_date - prev_ticket.fill_date).days
if days > 0:
# Calculate degree days for this interval from temp_avg
interval_temps = session.query(Auto_Temp).filter(
Auto_Temp.todays_date > prev_ticket.fill_date,
Auto_Temp.todays_date <= next_ticket.fill_date
).all()
total_degree_days = sum(max(0, 65 - float(temp.temp_avg)) for temp in interval_temps)
total_degree_days = Decimal(total_degree_days)
avg_degree_per_day = total_degree_days / days
total_hot_water = HOT_WATER_DAILY_USAGE * days
gallons_heating = prev_ticket.gallons_delivered - total_hot_water
if gallons_heating > 0 and total_degree_days > 0:
daily_heating = gallons_heating / days
daily_heating_usages.append(daily_heating)
avg_degree_per_days.append(avg_degree_per_day)
if daily_heating_usages and avg_degree_per_days:
average_daily_heating = sum(daily_heating_usages) / len(daily_heating_usages)
average_degree_days_per_day = sum(avg_degree_per_days) / len(avg_degree_per_days)
house_factor = average_daily_heating / average_degree_days_per_day
calculated_scaling = house_factor
else:
house_factor = Decimal('0.005') # Default
calculated_scaling = house_factor
# Calculate usage from last_fill to today using temperature-dependent heating
if last_fill < today:
temp_days = session.query(Auto_Temp).filter(
Auto_Temp.todays_date > last_fill,
Auto_Temp.todays_date <= today
).all()
heating_usage = Decimal('0')
hot_water_usage = Decimal('0')
for temp in temp_days:
degree_day = max(0, 65 - float(temp.temp_avg))
heating_usage += house_factor * Decimal(degree_day)
if hot_water:
hot_water_usage += HOT_WATER_DAILY_USAGE
total_usage = heating_usage + hot_water_usage
estimated_gallons_left = max(Decimal('0'), estimated_gallons_left - total_usage)
estimated_gallons = estimated_gallons_left
# Update database if requested
if update_db == 1:
ad.estimated_gallons_left = estimated_gallons
if calculated_scaling is not None:
ad.house_factor = calculated_scaling
session.add(ad)
last_5 = tickets[-5:] if tickets else []
scaling_factor = float(ad.house_factor) if ad.house_factor else None
estimates.append({
"id": ad.id,
"customer_full_name": ad.customer_full_name,
"account_number": ad.account_number,
"address": ad.customer_address,
"estimated_gallons": float(estimated_gallons),
"scaling_factor": scaling_factor,
"last_5_deliveries": [
{
"fill_date": str(t.fill_date),
"gallons_delivered": float(t.gallons_delivered),
"price_per_gallon": float(t.price_per_gallon),
"total_amount_customer": float(t.total_amount_customer)
} for t in last_5
]
})
if update_db == 1:
session.commit()
return JSONResponse(content=jsonable_encoder(estimates))

View File

@@ -1,5 +1,5 @@
from fastapi import FastAPI
from app.routers import main, delivery, confirm
from app.routers import main, delivery, confirm, fixstuff
from fastapi.middleware.cors import CORSMiddleware
import os
from config import load_config
@@ -14,6 +14,7 @@ app = FastAPI()
app.include_router(main.router)
app.include_router(delivery.router)
app.include_router(confirm.router)
app.include_router(fixstuff.router)
# print(ApplicationConfig.origins)