From 43a14eba2c558f3a246cc9e4755deef2da508c51 Mon Sep 17 00:00:00 2001 From: Edwin Eames Date: Sun, 1 Feb 2026 19:03:37 -0500 Subject: [PATCH] Remove service endpoints and migrate to dedicated service API - Delete app/service module (moved to eamco_service) - Update delivery views to remove service-related imports - Clean up delivery_data views - Part of microservices architecture refactoring --- app/__init__.py | 3 - app/delivery/views.py | 14 +- app/delivery_data/views.py | 2 +- app/service/__init__.py | 7 - app/service/views.py | 438 ------------------------------------- 5 files changed, 13 insertions(+), 451 deletions(-) delete mode 100644 app/service/__init__.py delete mode 100644 app/service/views.py diff --git a/app/__init__.py b/app/__init__.py index 114f150..3992650 100755 --- a/app/__init__.py +++ b/app/__init__.py @@ -243,9 +243,6 @@ app.register_blueprint(promo_blueprint, url_prefix='/promo') from .social import social as social_blueprint app.register_blueprint(social_blueprint, url_prefix='/social') -from .service import service as service_blueprint -app.register_blueprint(service_blueprint, url_prefix='/service') - def check_db_connection(): """ diff --git a/app/delivery/views.py b/app/delivery/views.py index 2ee7aa1..2cd6d7a 100755 --- a/app/delivery/views.py +++ b/app/delivery/views.py @@ -471,7 +471,7 @@ def get_deliveries_today(): return success_response({"deliveries": customer_schema.dump(deliveries)}) -@delivery.route("/edit/", methods=["POST"]) +@delivery.route("/edit/", methods=["POST", "PUT"]) @common_login_required def edit_a_delivery(delivery_id): """ @@ -787,7 +787,7 @@ def create_a_delivery(user_id): return success_response({'delivery_id': new_delivery.id}) -@delivery.route("/cancel/", methods=["POST"]) +@delivery.route("/cancel/", methods=["POST", "PUT"]) @common_login_required def cancel_a_delivery(delivery_id): """ @@ -806,6 +806,16 @@ def cancel_a_delivery(delivery_id): return success_response() +@delivery.route("/cancelled/", methods=["PUT"]) +@common_login_required +def mark_as_cancelled_alias(delivery_id): + """ + Alias for cancel_a_delivery to support frontend calls to /cancelled/ + """ + return cancel_a_delivery(delivery_id) + + + @delivery.route("/delivered/", methods=["POST"]) @common_login_required def mark_as_delivered(delivery_id): diff --git a/app/delivery_data/views.py b/app/delivery_data/views.py index 895835b..eeaa3b9 100755 --- a/app/delivery_data/views.py +++ b/app/delivery_data/views.py @@ -113,7 +113,7 @@ def office_finalize_delivery(delivery_id): gallons_delivered = request.json["gallons_delivered"] check_number = request.json["check_number"] - fill_location = request.json["fill_location"] + fill_location = request.json.get("fill_location") # update driver diff --git a/app/service/__init__.py b/app/service/__init__.py deleted file mode 100644 index 800ef82..0000000 --- a/app/service/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# coding=utf-8 - -from flask import Blueprint - -service = Blueprint('service', __name__) - -from . import views \ No newline at end of file diff --git a/app/service/views.py b/app/service/views.py deleted file mode 100644 index 3c4cd97..0000000 --- a/app/service/views.py +++ /dev/null @@ -1,438 +0,0 @@ -import logging -from flask import request -from app.service import service -from app import db -from app.common.responses import error_response, success_response -from datetime import datetime, date, timedelta -from app.classes.customer import (Customer_Customer) -from app.classes.service import (Service_Service, - Service_Service_schema, Service_Parts, Service_Parts_schema, - Service_Plans, Service_Plans_schema - ) -from app.classes.auto import Auto_Delivery -from flask_login import login_required -from app.constants import DEFAULT_PAGE_SIZE - -logger = logging.getLogger(__name__) - -@service.route("/all", methods=["GET"]) -@login_required -def get_all_service_calls(): - logger.info("GET /service/all - Fetching all service calls for calendar") - try: - all_services = Service_Service.query.all() - color_map = { - 0: {"backgroundColor": "blue", "textColor": "white"}, 1: {"backgroundColor": "red", "textColor": "white"}, - 2: {"backgroundColor": "green", "textColor": "white"}, 3: {"backgroundColor": "yellow", "textColor": "black"}, - 4: {"backgroundColor": "black", "textColor": "white"} - } - service_type_map = {0: 'Tune-up', 1: 'No Heat', 2: 'Fix', 3: 'Tank Install', 4: 'Other'} - - calendar_events = [] - for service_record in all_services: - service_type_text = service_type_map.get(service_record.type_service_call, 'Service') - event_title = f"{service_type_text}: {service_record.customer_name}" - event_colors = color_map.get(service_record.type_service_call, {"backgroundColor": "gray", "textColor": "white"}) - - # Use the schema to safely get the date string - serialized_record = Service_Service_schema().dump(service_record) - start_date = serialized_record.get('scheduled_date') - - event_data = { - "id": service_record.id, - "title": event_title, - "start": start_date, - "end": None, - "extendedProps": { - "customer_id": service_record.customer_id, - "description": service_record.description, - "type_service_call": service_record.type_service_call, - "service_cost": str(service_record.service_cost) if service_record.service_cost is not None else None - }, - "backgroundColor": event_colors.get("backgroundColor"), - "textColor": event_colors.get("textColor"), - "borderColor": event_colors.get("backgroundColor") - } - calendar_events.append(event_data) - - return success_response({"events": calendar_events}) - except Exception as e: - logger.error(f"Error in /service/all: {e}") - return error_response(str(e), 500) - - -# --- THIS IS THE FIX --- -# The logic from /all has been copied here to ensure a consistent data structure. -@service.route("/upcoming", methods=["GET"]) -@login_required -def get_upcoming_service_calls(): - """ - Fetches a list of all future service calls from today onwards. - """ - logger.info("GET /service/upcoming - Fetching upcoming service calls") - now = datetime.now() - upcoming_services = ( - Service_Service.query - .filter(Service_Service.scheduled_date >= now) - .order_by(Service_Service.scheduled_date.asc()) - .limit(DEFAULT_PAGE_SIZE) - .all() - ) - - service_schema = Service_Service_schema(many=True) - result = service_schema.dump(upcoming_services) - - return success_response({"services": result}) - - -@service.route("/past", methods=["GET"]) -@login_required -def get_past_service_calls(): - """ - Fetches a list of all past service calls before today. - """ - past_services = ( - Service_Service.query - .filter(Service_Service.scheduled_date < datetime.combine(date.today(), datetime.min.time())) - .order_by(Service_Service.scheduled_date.asc()) - .limit(DEFAULT_PAGE_SIZE) - .all() - ) - - service_schema = Service_Service_schema(many=True) - result = service_schema.dump(past_services) - - return success_response({"services": result}) - - -@service.route("/today", methods=["GET"]) -@login_required -def get_today_service_calls(): - """ - Fetches a list of all service calls for today. - """ - start_of_today = datetime.combine(date.today(), datetime.min.time()) - start_of_tomorrow = datetime.combine(date.today() + timedelta(days=1), datetime.min.time()) - today_services = ( - Service_Service.query - .filter(Service_Service.scheduled_date >= start_of_today) - .filter(Service_Service.scheduled_date < start_of_tomorrow) - .order_by(Service_Service.scheduled_date.asc()) - .limit(DEFAULT_PAGE_SIZE) - .all() - ) - - service_schema = Service_Service_schema(many=True) - result = service_schema.dump(today_services) - - return success_response({"services": result}) - - -@service.route("/upcoming/count", methods=["GET"]) -@login_required -def get_upcoming_service_calls_count(): - now = datetime.now() - try: - count = (db.session.query(Service_Service).filter(Service_Service.scheduled_date >= now).count()) - return success_response({"count": count}) - except Exception as e: - return error_response(str(e), 500) - -@service.route("/for-customer/", methods=["GET"]) -@login_required -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 success_response({"services": result}) - -@service.route("/create", methods=["POST"]) -@login_required -def create_service_call(): - data = request.get_json() - if not data: return error_response("No data provided", 400) - cus_id=data.get('customer_id') - get_customer = (db.session.query(Customer_Customer).filter(Customer_Customer.id == cus_id).first()) - if not get_customer: return error_response(f"Customer with id {cus_id} not found.", 404) - scheduled_datetime_str = data.get('expected_delivery_date') - scheduled_datetime_obj = datetime.fromisoformat(scheduled_datetime_str) - new_service_call = Service_Service( - 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_state=get_customer.customer_state, customer_zip=get_customer.customer_zip, - type_service_call=data.get('type_service_call'), when_ordered=datetime.utcnow(), - scheduled_date=scheduled_datetime_obj, description=data.get('description'), service_cost=None, - ) - db.session.add(new_service_call) - db.session.commit() - return success_response({"id": new_service_call.id}, 201) - -@service.route("/update-cost/", methods=["PUT"]) -@login_required -def update_service_cost(id): - """ - Dedicated endpoint to update only the service cost for a service call. - This is used after payment capture/charge to update the actual amount. - """ - try: - # Find the service - service_record = Service_Service.query.get_or_404(id) - - # Get request data - only service_cost - data = request.get_json() - if not data: - return error_response("No data provided", 400) - - # Extract and validate the service_cost - new_cost = data.get('service_cost') - if new_cost is None: - return error_response("service_cost is required", 400) - - # Convert to float for validation - try: - new_cost_float = float(new_cost) - except (ValueError, TypeError): - return error_response("service_cost must be a valid number", 400) - - # Update the service_cost - service_record.service_cost = new_cost_float - - # Commit the transaction - db.session.commit() - - # Return success response - return success_response({ - "service_id": id, - "service_cost_updated": new_cost_float, - "message": f"Service {id} cost updated to ${new_cost_float}" - }) - - except Exception as e: - db.session.rollback() - logger.error(f"Error updating service cost for service {id}: {e}") - return error_response(str(e), 500) - -@service.route("/update/", methods=["PUT"]) -@login_required -def update_service_call(id): - service_record = Service_Service.query.get_or_404(id) - data = request.get_json() - if not data: return error_response("No data provided", 400) - scheduled_datetime_str = data.get('scheduled_date') - if 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.description = data.get('description', service_record.description) - service_record.service_cost = data.get('service_cost', service_record.service_cost) - - try: - db.session.commit() - service_schema = Service_Service_schema(many=False) - return success_response({"service": service_schema.dump(service_record)}) - except Exception as e: - db.session.rollback() - return error_response(str(e), 500) - - -# Service Plans CRUD endpoints -@service.route("/plans/active", methods=["GET"]) -@login_required -def get_active_service_plans(): - """ - Get all active service plans (contract_plan > 0) - """ - try: - plans = Service_Plans.query.filter(Service_Plans.contract_plan > 0).all() - plans_schema = Service_Plans_schema(many=True) - result = plans_schema.dump(plans) - - # Add customer info to each plan - for plan in result: - customer = Customer_Customer.query.get(plan['customer_id']) - if customer: - plan['customer_name'] = f"{customer.customer_first_name} {customer.customer_last_name}" - plan['customer_address'] = customer.customer_address - plan['customer_town'] = customer.customer_town - - return success_response({"plans": result}) - except Exception as e: - return error_response(str(e), 500) - - -@service.route("/plans/customer/", methods=["GET"]) -@login_required -def get_customer_service_plan(customer_id): - """ - Get service plan for a specific customer - """ - try: - plan = Service_Plans.query.filter_by(customer_id=customer_id).first() - if plan: - plan_schema = Service_Plans_schema() - return success_response({"plan": plan_schema.dump(plan)}) - else: - return success_response({"plan": None}) - except Exception as e: - return error_response(str(e), 500) - - -@service.route("/plans/create", methods=["POST"]) -@login_required -def create_service_plan(): - """ - Create a new service plan for a customer - """ - data = request.get_json() - if not data: - return error_response("No data provided", 400) - - try: - new_plan = Service_Plans( - customer_id=data['customer_id'], - contract_plan=data['contract_plan'], - contract_years=data['contract_years'], - contract_start_date=datetime.fromisoformat(data['contract_start_date']) - ) - db.session.add(new_plan) - db.session.commit() - - plan_schema = Service_Plans_schema() - return success_response({"plan": plan_schema.dump(new_plan)}, 201) - except Exception as e: - db.session.rollback() - return error_response(str(e), 500) - - -@service.route("/plans/update/", methods=["PUT"]) -@login_required -def update_service_plan(customer_id): - """ - Update existing service plan for a customer - """ - data = request.get_json() - if not data: - return error_response("No data provided", 400) - - try: - plan = Service_Plans.query.filter_by(customer_id=customer_id).first() - if not plan: - # Create new plan if it doesn't exist - plan = Service_Plans(customer_id=customer_id) - db.session.add(plan) - - plan.contract_plan = data.get('contract_plan', plan.contract_plan) - plan.contract_years = data.get('contract_years', plan.contract_years) - if data.get('contract_start_date'): - plan.contract_start_date = datetime.fromisoformat(data['contract_start_date']) - - db.session.commit() - - plan_schema = Service_Plans_schema() - return success_response({"plan": plan_schema.dump(plan)}) - except Exception as e: - db.session.rollback() - return error_response(str(e), 500) - - -@service.route("/plans/delete/", methods=["DELETE"]) -@login_required -def delete_service_plan(customer_id): - """ - Delete service plan for a customer - """ - try: - plan = Service_Plans.query.filter_by(customer_id=customer_id).first() - if not plan: - return error_response("Service plan not found", 404) - - db.session.delete(plan) - db.session.commit() - return success_response({"message": "Service plan deleted successfully"}) - except Exception as e: - db.session.rollback() - return error_response(str(e), 500) - -@service.route("/", methods=["GET"]) -@login_required -def get_service_by_id(id): - service_record = Service_Service.query.get_or_404(id) - service_schema = Service_Service_schema() - return success_response({"service": service_schema.dump(service_record)}) - -@service.route("/delete/", methods=["DELETE"]) -@login_required -def delete_service_call(id): - service_record = Service_Service.query.get_or_404(id) - try: - db.session.delete(service_record) - db.session.commit() - return success_response({"message": "Service deleted successfully"}) - except Exception as e: - db.session.rollback() - return error_response(str(e), 500) - -@service.route("/parts/customer/", methods=["GET"]) -@login_required -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 success_response({"parts": parts_schema.dump(parts)}) - else: - return success_response({"parts": { - "customer_id": customer_id, "oil_filter": "", "oil_filter_2": "", - "oil_nozzle": "", "oil_nozzle_2": "", "hot_water_tank": 0 - }}) - -@service.route("/parts/update/", methods=["POST"]) -@login_required -def update_service_parts(customer_id): - try: - data = request.get_json() - - if not data: - return error_response("No data provided", 400) - - get_customer = db.session.query(Customer_Customer).filter(Customer_Customer.id == customer_id).first() - parts = Service_Parts.query.filter_by(customer_id=customer_id).first() - if not parts: - parts = Service_Parts(customer_id=customer_id) - db.session.add(parts) - parts.oil_filter = data.get('oil_filter', parts.oil_filter) - 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) - parts.hot_water_tank = data.get('hot_water_tank', parts.hot_water_tank if parts.hot_water_tank is not None else 0) - - # Sync to Auto_Delivery if customer is automatic - if get_customer and get_customer.customer_automatic == 1: - get_auto = db.session.query(Auto_Delivery).filter(Auto_Delivery.customer_id == customer_id).first() - if get_auto: - get_auto.hot_water_summer = parts.hot_water_tank - db.session.add(get_auto) - - db.session.commit() - return success_response({"message": "Service parts updated successfully"}) - except Exception as e: - db.session.rollback() - return error_response(str(e), 500) - - -@service.route("/payment//", methods=["PUT"]) -@login_required -def process_service_payment(service_id, payment_type): - service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first() - if not service: - return error_response("Service not found", 404) - - # Set payment columns as specified - service.payment_type = payment_type # e.g., 1 for Tiger - service.payment_status = 2 # As specified - # payment_card_id retains the selected card's ID if set in the service record - - try: - db.session.commit() - return success_response() - except Exception as e: - db.session.rollback() - return error_response(str(e), 500)