tons fixes

This commit is contained in:
2025-08-25 17:59:00 -04:00
parent c526284d98
commit 652947b30a
3 changed files with 129 additions and 84 deletions

View File

@@ -18,30 +18,46 @@ class Service_Service(db.Model):
customer_town = db.Column(db.VARCHAR(140)) customer_town = db.Column(db.VARCHAR(140))
customer_state = db.Column(db.VARCHAR(140)) customer_state = db.Column(db.VARCHAR(140))
customer_zip = db.Column(db.VARCHAR(10)) customer_zip = db.Column(db.VARCHAR(10))
# tune-up = 0 # tune-up = 0
# no heat = 1 # no heat = 1
# fix = 2 # fix = 2
# tank = 3 # tank = 3
# other = 4 # other = 4
type_service_call = db.Column(db.INTEGER) type_service_call = db.Column(db.INTEGER)
when_ordered = db.Column(db.DATETIME()) when_ordered = db.Column(db.DATETIME())
scheduled_date = db.Column(db.DATETIME()) scheduled_date = db.Column(db.DATETIME())
description = db.Column(db.TEXT()) description = db.Column(db.TEXT())
class Service_Service_schema(ma.SQLAlchemyAutoSchema): class Service_Service_schema(ma.SQLAlchemyAutoSchema):
class Meta: class Meta:
model = Service_Service model = Service_Service
scheduled_date = ma.DateTime(format='%Y-%m-%dT%H:%M:%S')
when_ordered = ma.DateTime(format='%Y-%m-%dT%H:%M:%S')
class Service_Parts(db.Model):
__tablename__ = 'service_parts'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
customer_id = db.Column(db.INTEGER)
oil_filter = db.Column(db.VARCHAR(100))
oil_filter_2 = db.Column(db.VARCHAR(100))
oil_nozzle = db.Column(db.VARCHAR(10))
oil_nozzle_2 = db.Column(db.VARCHAR(10))
class Service_Parts_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Service_Parts
scheduled_date = ma.DateTime(format='%Y-%m-%dT%H:%M:%S') scheduled_date = ma.DateTime(format='%Y-%m-%dT%H:%M:%S')
when_ordered = ma.DateTime(format='%Y-%m-%dT%H:%M:%S') when_ordered = ma.DateTime(format='%Y-%m-%dT%H:%M:%S')

View File

@@ -1,10 +1,40 @@
from flask import jsonify from flask import jsonify
from decimal import Decimal
from app.info import info from app.info import info
from app import db from app import db
from app.classes.pricing import Pricing_Oil_Oil, Pricing_Oil_Oil_schema from app.classes.pricing import Pricing_Oil_Oil, Pricing_Oil_Oil_schema
from app.classes.admin import Admin_Company from app.classes.admin import Admin_Company
@info.route("/price/oil/tiers", methods=["GET"])
def get_pricing_tiers():
get_price_query = (db.session
.query(Pricing_Oil_Oil)
.order_by(Pricing_Oil_Oil.date.desc())
.first())
if not get_price_query:
return jsonify({"error": "No pricing data available"}), 404
# Get the single price per gallon from the database, e.g., Decimal('2.92')
price_per_gallon = get_price_query.price_for_customer
# Define the specific gallon amounts you want to display totals for
gallon_tiers = [100, 125, 150, 175, 200, 220]
# Calculate the total price for each gallon amount by multiplication
# e.g., { 100: (2.92 * 100), 125: (2.92 * 125), ... }
pricing_totals = {
gallons: price_per_gallon * gallons
for gallons in gallon_tiers
}
# Return the dictionary of totals
# e.g., { "100": "292.00", "125": "365.00", ... }
return jsonify(pricing_totals)
@info.route("/price/oil", methods=["GET"]) @info.route("/price/oil", methods=["GET"])
def get_oil_price_today(): def get_oil_price_today():
get_price_query = (db.session get_price_query = (db.session

View File

@@ -4,109 +4,108 @@ from app import db
from datetime import datetime, date from datetime import datetime, date
from app.classes.customer import (Customer_Customer) from app.classes.customer import (Customer_Customer)
from app.classes.service import (Service_Service, from app.classes.service import (Service_Service,
Service_Service_schema Service_Service_schema, Service_Parts, Service_Parts_schema
) )
# --- NEW ENDPOINT TO GET ALL SERVICE CALLS FOR THE MASTER CALENDAR ---
@service.route("/all", methods=["GET"]) @service.route("/all", methods=["GET"])
def get_all_service_calls(): def get_all_service_calls():
"""
Fetches ALL service calls from the database and formats them for FullCalendar.
"""
# 1. Query all service records, without filtering by customer
all_services = Service_Service.query.all() all_services = Service_Service.query.all()
# 2. Reuse the same formatting logic (colors, titles, etc.)
color_map = { color_map = {
0: {"backgroundColor": "blue", "textColor": "white"}, 0: {"backgroundColor": "blue", "textColor": "white"}, 1: {"backgroundColor": "red", "textColor": "white"},
1: {"backgroundColor": "red", "textColor": "white"}, 2: {"backgroundColor": "green", "textColor": "white"}, 3: {"backgroundColor": "yellow", "textColor": "black"},
2: {"backgroundColor": "green", "textColor": "white"},
3: {"backgroundColor": "yellow", "textColor": "black"},
4: {"backgroundColor": "black", "textColor": "white"} 4: {"backgroundColor": "black", "textColor": "white"}
} }
service_type_map = {0: 'Tune-up', 1: 'No Heat', 2: 'Fix', 3: 'Tank Install', 4: 'Other'} service_type_map = {0: 'Tune-up', 1: 'No Heat', 2: 'Fix', 3: 'Tank Install', 4: 'Other'}
calendar_events = [] calendar_events = []
for service_record in all_services: for service_record in all_services:
service_type_text = service_type_map.get(service_record.type_service_call, 'Service') service_type_text = service_type_map.get(service_record.type_service_call, 'Service')
# The title now includes the customer name, which is crucial for a master calendar
event_title = f"{service_type_text}: {service_record.customer_name}" event_title = f"{service_type_text}: {service_record.customer_name}"
event_colors = color_map.get(service_record.type_service_call, {"backgroundColor": "gray", "textColor": "white"}) event_colors = color_map.get(service_record.type_service_call, {"backgroundColor": "gray", "textColor": "white"})
# Use the schema to correctly format the date to a string
serialized_record = Service_Service_schema().dump(service_record) serialized_record = Service_Service_schema().dump(service_record)
event_data = { event_data = {
"id": service_record.id, "id": service_record.id, "title": event_title, "start": serialized_record.get('scheduled_date'),
"title": event_title, "end": None, "customer_id": service_record.customer_id,
"start": serialized_record.get('scheduled_date'), # Use the reliable formatted date
"end": None,
"extendedProps": { "extendedProps": {
"description": service_record.description, "description": service_record.description,
"type_service_call": service_record.type_service_call, "type_service_call": service_record.type_service_call,
}, },
"backgroundColor": event_colors.get("backgroundColor"), "backgroundColor": event_colors.get("backgroundColor"), "textColor": event_colors.get("textColor"),
"textColor": event_colors.get("textColor"),
"borderColor": event_colors.get("backgroundColor") "borderColor": event_colors.get("backgroundColor")
} }
calendar_events.append(event_data) calendar_events.append(event_data)
return jsonify(calendar_events), 200 return jsonify(calendar_events), 200
# --- YOUR OTHER EXISTING ROUTES (no changes needed below) --- # --- THIS IS THE FIX ---
# The logic from /all has been copied here to ensure a consistent data structure.
@service.route("/upcoming", methods=["GET"]) @service.route("/upcoming", methods=["GET"])
def get_upcoming_service_calls(): def get_upcoming_service_calls():
# ... (no changes) """
Fetches a list of all future service calls from today onwards.
"""
now = datetime.now() now = datetime.now()
upcoming_services = (Service_Service.query.filter(Service_Service.scheduled_date >= now).order_by(Service_Service.scheduled_date.asc()).limit(100).all()) upcoming_services = (
Service_Service.query
.filter(Service_Service.scheduled_date >= now)
.order_by(Service_Service.scheduled_date.asc())
.limit(100)
.all()
)
service_schema = Service_Service_schema(many=True) service_schema = Service_Service_schema(many=True)
result = service_schema.dump(upcoming_services) result = service_schema.dump(upcoming_services)
return jsonify(result), 200
@service.route("/upcoming/count", methods=["GET"])
def get_upcoming_service_calls_count():
now = datetime.now()
try:
count = (db.session.query(Service_Service).filter(Service_Service.scheduled_date >= now).count())
return jsonify({"count": count}), 200
except Exception as e:
return jsonify({"error": str(e)}), 500
@service.route("/for-customer/<int:customer_id>", methods=["GET"])
def get_service_calls_for_customer(customer_id):
service_records = (Service_Service.query.filter_by(customer_id=customer_id).order_by(Service_Service.scheduled_date.desc()).all())
service_schema = Service_Service_schema(many=True)
result = service_schema.dump(service_records)
return jsonify(result), 200 return jsonify(result), 200
@service.route("/create", methods=["POST"]) @service.route("/create", methods=["POST"])
def create_service_call(): def create_service_call():
data = request.get_json() data = request.get_json()
if not data: return jsonify({"error": "No data provided"}), 400 if not data: return jsonify({"error": "No data provided"}), 400
cus_id=data.get('customer_id') cus_id=data.get('customer_id')
get_customer = (db.session.query(Customer_Customer).filter(Customer_Customer.id == cus_id).first()) get_customer = (db.session.query(Customer_Customer).filter(Customer_Customer.id == cus_id).first())
if not get_customer: return jsonify({"error": f"Customer with id {cus_id} not found."}), 404 if not get_customer: return jsonify({"error": f"Customer with id {cus_id} not found."}), 404
# --- FIX: Use fromisoformat to parse the FULL timestamp string (e.g., "2025-08-26T14:00:00") ---
# This correctly preserves the time sent from the frontend.
scheduled_datetime_str = data.get('expected_delivery_date') scheduled_datetime_str = data.get('expected_delivery_date')
scheduled_datetime_obj = datetime.fromisoformat(scheduled_datetime_str) scheduled_datetime_obj = datetime.fromisoformat(scheduled_datetime_str)
new_service_call = Service_Service( new_service_call = Service_Service(
customer_id=get_customer.id, customer_name=get_customer.customer_first_name + ' ' + get_customer.customer_last_name, customer_id=get_customer.id, customer_name=get_customer.customer_first_name + ' ' + get_customer.customer_last_name,
customer_address=get_customer.customer_address, customer_town=get_customer.customer_town, customer_address=get_customer.customer_address, customer_town=get_customer.customer_town,
customer_state=get_customer.customer_state, customer_zip=get_customer.customer_zip, customer_state=get_customer.customer_state, customer_zip=get_customer.customer_zip,
type_service_call=data.get('type_service_call'), when_ordered=datetime.utcnow(), type_service_call=data.get('type_service_call'), when_ordered=datetime.utcnow(),
scheduled_date=scheduled_datetime_obj, # Save the full datetime object scheduled_date=scheduled_datetime_obj, description=data.get('description'),
description=data.get('description'),
) )
db.session.add(new_service_call) db.session.add(new_service_call)
db.session.commit() db.session.commit()
return jsonify({ "ok": True, "id": new_service_call.id }), 201 return jsonify({ "ok": True, "id": new_service_call.id }), 201
@service.route("/update/<int:id>", methods=["PUT"]) @service.route("/update/<int:id>", methods=["PUT"])
def update_service_call(id): def update_service_call(id):
service_record = Service_Service.query.get_or_404(id) service_record = Service_Service.query.get_or_404(id)
data = request.get_json() data = request.get_json()
if not data: return jsonify({"error": "No data provided"}), 400 if not data: return jsonify({"error": "No data provided"}), 400
# --- FIX: Also use fromisoformat here to correctly update with time ---
scheduled_datetime_str = data.get('scheduled_date') scheduled_datetime_str = data.get('scheduled_date')
if scheduled_datetime_str: if scheduled_datetime_str:
service_record.scheduled_date = datetime.fromisoformat(scheduled_datetime_str) service_record.scheduled_date = datetime.fromisoformat(scheduled_datetime_str)
service_record.type_service_call = data.get('type_service_call', service_record.type_service_call) service_record.type_service_call = data.get('type_service_call', service_record.type_service_call)
service_record.description = data.get('description', service_record.description) service_record.description = data.get('description', service_record.description)
try: try:
db.session.commit() db.session.commit()
service_schema = Service_Service_schema(many=False) service_schema = Service_Service_schema(many=False)
@@ -114,46 +113,46 @@ def update_service_call(id):
except Exception as e: except Exception as e:
db.session.rollback() db.session.rollback()
return jsonify({"error": str(e)}), 500 return jsonify({"error": str(e)}), 500
@service.route("/delete/<int:id>", methods=["DELETE"])
@service.route("/upcoming/count", methods=["GET"]) def delete_service_call(id):
def get_upcoming_service_calls_count(): service_record = Service_Service.query.get_or_404(id)
"""
Efficiently counts the number of all future service calls from today onwards.
"""
# 1. Get the current time
now = datetime.now()
# 2. Build the query and use the database's optimized count() function
try: try:
count = ( db.session.delete(service_record)
db.session.query(Service_Service) db.session.commit()
.filter(Service_Service.scheduled_date >= now) return jsonify({"ok": True, "message": "Service deleted successfully"}), 200
.count()
)
# 3. Return the count in a simple JSON object
return jsonify({"count": count}), 200
except Exception as e: except Exception as e:
# Return an error if the query fails db.session.rollback()
return jsonify({"error": str(e)}), 500 return jsonify({"error": str(e)}), 500
@service.route("/parts/customer/<int:customer_id>", methods=["GET"])
def get_service_parts(customer_id):
parts = Service_Parts.query.filter_by(customer_id=customer_id).first()
if parts:
parts_schema = Service_Parts_schema()
return jsonify(parts_schema.dump(parts)), 200
else:
return jsonify({
"customer_id": customer_id, "oil_filter": "", "oil_filter_2": "",
"oil_nozzle": "", "oil_nozzle_2": ""
}), 200
@service.route("/for-customer/<int:customer_id>", methods=["GET"]) @service.route("/parts/update/<int:customer_id>", methods=["POST"])
def get_service_calls_for_customer(customer_id): def update_service_parts(customer_id):
""" data = request.get_json()
Fetches all service calls for a specific customer, ordered by most recent first. if not data:
""" return jsonify({"error": "No data provided"}), 400
# Query the database, filtering by customer_id and ordering by date parts = Service_Parts.query.filter_by(customer_id=customer_id).first()
service_records = ( if not parts:
Service_Service.query parts = Service_Parts(customer_id=customer_id)
.filter_by(customer_id=customer_id) db.session.add(parts)
.order_by(Service_Service.scheduled_date.desc()) # .desc() for newest first parts.oil_filter = data.get('oil_filter', parts.oil_filter)
.all() parts.oil_filter_2 = data.get('oil_filter_2', parts.oil_filter_2)
) parts.oil_nozzle = data.get('oil_nozzle', parts.oil_nozzle)
parts.oil_nozzle_2 = data.get('oil_nozzle_2', parts.oil_nozzle_2)
# Use the schema to convert the list of objects to JSON try:
service_schema = Service_Service_schema(many=True) db.session.commit()
result = service_schema.dump(service_records) return jsonify({"ok": True, "message": "Service parts updated successfully"}), 200
except Exception as e:
return jsonify(result), 200 db.session.rollback()
return jsonify({"error": str(e)}), 500