major claude changes

This commit is contained in:
2026-01-28 21:55:10 -05:00
parent 3f311980db
commit 2dbd3ea53f
41 changed files with 1235 additions and 278 deletions

View File

@@ -1,20 +1,56 @@
# coding=utf-8
import logging
import sys
from flask import Flask, jsonify
from flask_bcrypt import Bcrypt
from flask_cors import CORS
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_session import Session
from flask_login import LoginManager
from sqlalchemy.orm import sessionmaker
from werkzeug.routing import BaseConverter
from flask_mail import Mail
from config import load_config
import re
import re
from sqlalchemy import text
ApplicationConfig = load_config()
# Configure logging
def setup_logging():
"""Configure structured logging for the application."""
log_level = logging.DEBUG if ApplicationConfig.CURRENT_SETTINGS != 'PRODUCTION' else logging.INFO
# Create formatter
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
# Configure root logger
root_logger = logging.getLogger()
root_logger.setLevel(log_level)
# Remove existing handlers to avoid duplicates
root_logger.handlers.clear()
# Console handler
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(log_level)
console_handler.setFormatter(formatter)
root_logger.addHandler(console_handler)
# Reduce noise from third-party libraries
logging.getLogger('werkzeug').setLevel(logging.WARNING)
logging.getLogger('sqlalchemy.engine').setLevel(logging.WARNING)
return logging.getLogger('eamco_office_api')
logger = setup_logging()
app = Flask(__name__,
static_url_path='',
static_folder='static',
@@ -55,6 +91,7 @@ app.config['SECRET_KEY'] = ApplicationConfig.SECRET_KEY
session.configure(bind=ApplicationConfig.SQLALCHEMY_DATABASE_URI)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
bcrypt = Bcrypt(app)
app.config['SESSION_SQLALCHEMY'] = db
server_session = Session(app)
@@ -93,15 +130,8 @@ def load_user_from_request(request):
# If no valid key is found in header or args, return None
return None
# api_main = {
# "origins": [ApplicationConfig.ORIGIN_URL],
# "methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"],
# "allow_headers": ['Authorization', 'application/json', 'authorization', 'Content-Type',
# 'Access-Control-Allow-Headers', 'Origin,Accept',
# 'X-Requested-With', 'Content-Type', 'Access-Control-Request-cMethod',
# 'Access-Control-Request-Headers']
# }
cors = CORS(app,
cors = CORS(app,
supports_credentials=True,
resources={r"/*": {"origins": ApplicationConfig.CORS_ALLOWED_ORIGINS}
})
@@ -217,8 +247,32 @@ from .service import service as service_blueprint
app.register_blueprint(service_blueprint, url_prefix='/service')
def check_db_connection():
"""
Test database connectivity.
"""
try:
db.session.execute(text("SELECT 1"))
return True
except Exception:
return False
with app.app_context():
db.configure_mappers()
db.create_all()
db.session.commit()
# Startup logging
logger.info("🚀 eamco_office_api STARTING")
mode = ApplicationConfig.CURRENT_SETTINGS.upper()
if mode in ['DEVELOPMENT', 'DEV']:
logger.info("🤖🤖🤖🤖🤖 Mode: Development 🤖🤖🤖🤖🤖")
elif mode in ['PRODUCTION', 'PROD']:
logger.info("💀💀💀💀💀💀💀💀💀💀 ⚠️ WARNING PRODUCTION 💀💀💀💀💀💀💀💀💀💀")
logger.info(f"DB: {ApplicationConfig.SQLALCHEMY_DATABASE_URI[:30]}...")
logger.info(f"CORS: {len(ApplicationConfig.CORS_ALLOWED_ORIGINS)} origins configured")
# Test database connection
if check_db_connection():
logger.info("DB Connection: ✅ OK")
else:
logger.info("DB Connection: ❌ FAILED")

View File

@@ -1,3 +1,4 @@
import logging
from flask import request, jsonify
from flask_login import current_user, logout_user, login_user, login_required
from app.admin import admin
@@ -7,12 +8,17 @@ from app.classes.pricing import (
Pricing_Oil_Oil,
Pricing_Oil_Oil_schema)
from app.classes.admin import Admin_Company, Admin_Company_schema, Call
from app.common.decorators import admin_required
logger = logging.getLogger(__name__)
@admin.route("/oil/create", methods=["POST"])
@admin_required
def create_oil_price():
"""
Changes the price for oil deliveries
"""
logger.info("POST /admin/oil/create - Creating new oil price")
now = datetime.utcnow()
price_from_supplier = request.json["price_from_supplier"]
price_for_customer = request.json["price_for_customer"]
@@ -50,10 +56,12 @@ def create_oil_price():
@admin.route("/oil/get", methods=["GET"])
@admin_required
def get_oil_price():
"""
gets oil prices
"""
logger.info("GET /admin/oil/get - Fetching current oil prices")
get_oil_prices = (db.session
.query(Pricing_Oil_Oil)
.order_by(Pricing_Oil_Oil.date.desc())
@@ -63,7 +71,9 @@ def get_oil_price():
@admin.route("/company/<int:company_id>", methods=["GET"])
@admin_required
def get_company(company_id):
logger.info(f"GET /admin/company/{company_id} - Fetching company data")
get_data_company = (db.session
.query(Admin_Company)
.first())
@@ -72,11 +82,12 @@ def get_company(company_id):
return jsonify(company_schema.dump(get_data_company))
@admin.route("/voip_routing", methods=["GET"])
@admin_required
def get_voip_routing():
"""
Gets the current VOIP routing (latest Call record's current_phone)
"""
logger.info("GET /admin/voip_routing - Fetching current VoIP routing")
latest_call = (db.session
.query(Call)
.order_by(Call.created_at.desc())

View File

@@ -1,3 +1,4 @@
import logging
from flask import request, jsonify
from flask_login import current_user, logout_user, login_required
from app.auth import auth
@@ -5,9 +6,12 @@ from app import db, bcrypt
from datetime import datetime
from uuid import uuid4
from app.classes.auth import Auth_User
from app.classes.employee import Employee_Employee
from app.classes.employee import Employee_Employee
from app.schemas import LoginSchema, RegisterSchema, ChangePasswordSchema, validate_request
import re
logger = logging.getLogger(__name__)
@auth.route("/whoami", methods=["GET"])
def check_session():
"""
@@ -25,7 +29,7 @@ def check_session():
user = db.session.query(Auth_User).filter(Auth_User.api_key == api_key).first()
if not user:
print("no user found with that api key")
logger.warning("Authentication failed: no user found with provided API key")
return jsonify({"ok": False, "error": "Invalid token"}), 401
# Now, build the complete response with both user and employee data.
@@ -73,9 +77,11 @@ def logout():
@auth.route("/login", methods=["POST"])
@validate_request(LoginSchema)
def login():
username = request.json["username"]
password = request.json["password"]
data = request.validated_data
username = data["username"]
password = data["password"]
user = db.session.query(Auth_User).filter_by(username=username).first()
@@ -103,15 +109,17 @@ def login():
}), 200
@auth.route("/register", methods=["POST"])
@validate_request(RegisterSchema)
def register_user():
"""
Main post function to register a user
"""
data = request.validated_data
now = datetime.utcnow()
username = request.json["username"]
email = request.json["email"]
password = request.json["password"]
username = data["username"]
email = data["email"]
password = data["password"]
part_one_code = uuid4().hex
part_two_code = uuid4().hex
@@ -172,6 +180,7 @@ def register_user():
@auth.route('/change-password', methods=['POST'])
@validate_request(ChangePasswordSchema)
def change_password():
auth_header = request.headers.get('Authorization')
if not auth_header:
@@ -184,8 +193,9 @@ def change_password():
if not user:
return jsonify({"error": "Invalid token"}), 401
new_password = request.json["new_password"]
new_password_confirm = request.json["password_confirm"]
data = request.validated_data
new_password = data["new_password"]
new_password_confirm = data["password_confirm"]
if str(new_password) != str(new_password_confirm):
return jsonify({"error": "Error: Incorrect Passwords"}), 200
@@ -214,7 +224,7 @@ def admin_change_password():
if not user:
return jsonify({"error": "Invalid token"}), 401
if user.admin_role != 0:
if user.admin_role == 0:
return jsonify({"error": "Admin access required"}), 403
employee_id = request.json.get("employee_id")

View File

@@ -1,5 +1,5 @@
from flask_login import current_user
from flask import abort
from flask import abort, jsonify
from functools import wraps
@@ -14,3 +14,12 @@ def login_required(f):
return f(*args, **kwargs)
return decorated_function
def admin_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not current_user.is_authenticated or not current_user.admin_role:
return jsonify({"error": "Admin access required"}), 403
return f(*args, **kwargs)
return decorated_function

46
app/constants.py Normal file
View File

@@ -0,0 +1,46 @@
"""
EAMCO Office API Constants
This file contains all status code constants used throughout the application
to eliminate magic numbers and improve code maintainability.
"""
class DeliveryStatus:
"""Delivery status codes"""
WAITING = 0
CANCELLED = 1
OUT_FOR_DELIVERY = 2
TOMORROW = 3
PARTIAL_DELIVERY = 4
ISSUE = 5
UNKNOWN = 6
PENDING_PAYMENT = 9
FINALIZED = 10
DELIVERED = 11 # New: Replaces previous use of 1 for delivered
class PaymentStatus:
"""Payment status codes"""
UNPAID = 0
PRE_AUTHORIZED = 1
PROCESSING = 2
PAID = 3
FAILED = 4
class AutoStatus:
"""Automatic delivery status codes"""
DEFAULT = 0
WILL_CALL = 1
READY_FOR_FINALIZATION = 3
class TransactionStatus:
"""Transaction status codes"""
APPROVED = 0
DECLINED = 1
class CustomerAutomaticStatus:
"""Customer automatic delivery status"""
WILL_CALL = 0
AUTOMATIC = 1
# Additional constants can be added here as needed
# For example: ServiceStatus, UserRoles, etc.

View File

@@ -1,8 +1,12 @@
import logging
from flask import request, jsonify
from flask_login import login_required
from geopy.geocoders import Nominatim
from app.customer import customer
from app import db
from app.common.decorators import login_required as common_login_required
logger = logging.getLogger(__name__)
from datetime import datetime
from app.classes.cards import Card_Card
from app.classes.customer import \
@@ -16,6 +20,7 @@ from app.classes.service import Service_Parts
from app.classes.admin import Admin_Company
from app.classes.auto import Auto_Delivery,Auto_Delivery_schema
from app.classes.stats_customer import Stats_Customer
from app.schemas import CreateCustomerSchema, UpdateCustomerSchema, validate_request
import string
import random
@@ -33,8 +38,9 @@ def generate_random_number_string(length):
@customer.route("/all", methods=["GET"])
@common_login_required
def all_customers_around():
logger.info("GET /customer/all - Fetching all customers")
customer_list = db.session \
.query(Customer_Customer) \
.all()
@@ -43,12 +49,12 @@ def all_customers_around():
@customer.route("/all/<int:page>", methods=["GET"])
@common_login_required
def all_customers(page):
"""
pagination all customers
"""
logger.info(f"GET /customer/all/{page} - Fetching customers page {page}")
per_page_amount = 100
if page is None:
offset_limit = 0
@@ -67,9 +73,11 @@ def all_customers(page):
@customer.route("/<int:customer_id>", methods=["GET"])
@common_login_required
def get_a_customer(customer_id):
"""
"""
logger.info(f"GET /customer/{customer_id} - Fetching customer")
get_customer = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.id == customer_id)
@@ -79,10 +87,12 @@ def get_a_customer(customer_id):
@customer.route("/description/<int:customer_id>", methods=["GET"])
@common_login_required
def get_a_customer_description(customer_id):
"""
"""
logger.info(f"GET /customer/description/{customer_id} - Fetching customer description")
get_customer_description = (db.session
.query(Customer_Description)
.filter(Customer_Description.customer_id == customer_id)
@@ -112,10 +122,12 @@ def get_a_customer_description(customer_id):
@customer.route("/tank/<int:customer_id>", methods=["GET"])
@common_login_required
def get_a_customer_tank(customer_id):
"""
"""
logger.info(f"GET /customer/tank/{customer_id} - Fetching customer tank info")
get_customer_tank = (db.session
.query(Customer_Tank_Inspection)
.filter(Customer_Tank_Inspection.customer_id == customer_id)
@@ -142,56 +154,50 @@ def get_a_customer_tank(customer_id):
@customer.route("/create", methods=["POST"])
@validate_request(CreateCustomerSchema)
@common_login_required
def create_customer():
"""
Create a new customer with validated input data.
"""
logger.info("POST /customer/create - Creating new customer")
# Get validated data from request
data = request.validated_data
now = datetime.utcnow()
get_company = (db.session
.query(Admin_Company)
.filter(Admin_Company.id == 1)
.first())
get_company = (db.session
.query(Admin_Company)
.filter(Admin_Company.id == 1)
.first())
random_string = generate_random_number_string(6)
made_account_number = str(get_company.account_prefix) + '-' + str(random_string)
see_if_exists = (db.session.query(Customer_Customer).filter(Customer_Customer.account_number == made_account_number).first())
if see_if_exists is not None:
random_string = generate_random_number_string(10)
made_account_number = str(get_company.account_prefix) + '-' + str(random_string)
see_if_exists = (db.session.query(Customer_Customer).filter(Customer_Customer.account_number == made_account_number).first())
if see_if_exists is not None:
random_string = generate_random_number_string(10)
made_account_number = str(get_company.account_prefix) + '-' + str(random_string)
see_if_exists = (db.session.query(Customer_Customer).filter(Customer_Customer.account_number == made_account_number).first())
response_customer_last_name = request.json["customer_last_name"]
response_customer_first_name = request.json["customer_first_name"]
response_customer_town = request.json["customer_town"]
response_customer_state = request.json["customer_state"]
response_customer_zip = request.json["customer_zip"]
response_customer_email = request.json["customer_email"]
response_customer_home_type = request.json["customer_home_type"]
customer_phone_number = request.json["customer_phone_number"]
customer_address = request.json["customer_address"]
customer_apt = request.json["customer_apt"]
customer_description_msg = request.json["customer_description"]
# Use validated data instead of direct request.json access
response_customer_last_name = data["customer_last_name"]
response_customer_first_name = data["customer_first_name"]
response_customer_town = data["customer_town"]
response_customer_state = data["customer_state"]
response_customer_zip = str(data["customer_zip"])
response_customer_email = data.get("customer_email")
response_customer_home_type = data["customer_home_type"]
customer_phone_number = data.get("customer_phone_number")
customer_address = data["customer_address"]
customer_apt = data.get("customer_apt")
customer_description_msg = data.get("customer_description")
int_customer_home_type = int(response_customer_home_type)
response_customer_zip = str(response_customer_zip)
response_customer_state = int(response_customer_state)
@@ -204,51 +210,18 @@ def create_customer():
else:
the_state = 'MA'
# if response_customer_town == 0:
# the_town = 'Auburn'
# elif response_customer_town == 1:
# the_town = 'Charlton'
# elif response_customer_town == 2:
# the_town = 'Cherry Valley'
# elif response_customer_town == 3:
# the_town = 'Dudley'
# elif response_customer_town == 4:
# the_town = 'Grafton'
# elif response_customer_town == 5:
# the_town = 'Leicester'
# elif response_customer_town == 6:
# the_town = 'Millbury'
# elif response_customer_town == 7:
# the_town = 'N Oxford'
# elif response_customer_town == 8:
# the_town = 'Oxford'
# elif response_customer_town == 9:
# the_town = 'Rochdale'
# elif response_customer_town == 10:
# the_town = 'Shrewsbury'
# elif response_customer_town == 11:
# the_town = 'Southbridge'
# elif response_customer_town == 12:
# the_town = 'Spencer'
# elif response_customer_town == 13:
# the_town = 'Sturbridge'
# elif response_customer_town == 14:
# the_town = 'Webster'
# elif response_customer_town == 15:
# the_town = 'Worcester'
# else:
# the_town = 'NA'
geolocator = Nominatim(user_agent="auburnoil")
address_string = customer_address + ' ' + response_customer_town+ ' ' + the_state
try:
location = geolocator.geocode(address_string)
user_lat =location.latitude
user_lat = location.latitude
user_long = location.longitude
cor_ad = True
except:
user_lat =None
except Exception:
user_lat = None
user_long = None
cor_ad = False
@@ -323,70 +296,95 @@ def create_customer():
@customer.route("/edit/<int:customer_id>", methods=["PUT"])
@login_required
@validate_request(UpdateCustomerSchema)
def edit_customer(customer_id):
"""
"""
logger.info(f"PUT /customer/edit/{customer_id} - Editing customer")
get_customer = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.id == customer_id)
.first())
if not get_customer:
return jsonify({"error": "Customer not found"}), 404
get_customer_description = (db.session
.query(Customer_Description)
.filter(Customer_Description.customer_id == customer_id)
.first())
response_customer_last_name = request.json["customer_last_name"]
response_customer_first_name = request.json["customer_first_name"]
response_customer_town = request.json["customer_town"]
response_customer_state = request.json["customer_state"]
response_customer_zip = request.json["customer_zip"]
response_customer_phone_number = request.json["customer_phone_number"]
response_customer_email = request.json["customer_email"]
response_customer_home_type = request.json["customer_home_type"]
response_customer_address = request.json["customer_address"]
response_customer_apt = request.json["customer_apt"]
response_customer_description = request.json["customer_description"]
response_customer_fill_location = request.json["customer_fill_location"]
data = request.validated_data
response_customer_last_name = data.get("customer_last_name")
response_customer_first_name = data.get("customer_first_name")
response_customer_town = data.get("customer_town")
response_customer_state = data.get("customer_state")
response_customer_zip = data.get("customer_zip")
response_customer_phone_number = data.get("customer_phone_number")
response_customer_email = data.get("customer_email")
response_customer_home_type = data.get("customer_home_type")
response_customer_address = data.get("customer_address")
response_customer_apt = data.get("customer_apt")
response_customer_description = data.get("customer_description")
response_customer_fill_location = data.get("customer_fill_location")
# Update description if provided
if get_customer_description is not None:
get_customer_description.description = response_customer_description
get_customer_description.fill_location = response_customer_fill_location
if response_customer_description is not None:
get_customer_description.description = response_customer_description
if response_customer_fill_location is not None:
get_customer_description.fill_location = response_customer_fill_location
db.session.add(get_customer_description)
if response_customer_state == 0:
the_state = 'MA'
elif response_customer_state == 1:
the_state = 'RI'
elif response_customer_state == 1:
the_state = 'NH'
else:
the_state = 'MA'
# Only update fields that were provided in the request
if response_customer_last_name is not None:
get_customer.customer_last_name = response_customer_last_name
if response_customer_first_name is not None:
get_customer.customer_first_name = response_customer_first_name
if response_customer_town is not None:
get_customer.customer_town = response_customer_town
if response_customer_state is not None:
get_customer.customer_state = response_customer_state
if response_customer_zip is not None:
get_customer.customer_zip = response_customer_zip
if response_customer_phone_number is not None:
get_customer.customer_phone_number = response_customer_phone_number
if response_customer_email is not None:
get_customer.customer_email = response_customer_email
if response_customer_home_type is not None:
get_customer.customer_home_type = response_customer_home_type
if response_customer_apt is not None:
get_customer.customer_apt = response_customer_apt
geolocator = Nominatim(user_agent="auburnoil")
address_string = response_customer_address + ' ' + response_customer_town+ ' ' + the_state
try:
location = geolocator.geocode(address_string, timeout=10)
get_customer.customer_latitude = location.latitude
get_customer.customer_longitude = location.longitude
cor_ad = True
except:
get_customer.customer_latitude = None
get_customer.customer_longitude = None
cor_ad = False
# Re-geocode if address fields changed
if response_customer_address is not None or response_customer_town is not None or response_customer_state is not None:
get_customer.customer_address = response_customer_address if response_customer_address is not None else get_customer.customer_address
get_customer.customer_address = response_customer_address
get_customer.customer_home_type = response_customer_home_type
get_customer.customer_phone_number = response_customer_phone_number
get_customer.customer_last_name = response_customer_last_name
get_customer.customer_first_name = response_customer_first_name
get_customer.customer_town = response_customer_town
get_customer.customer_state = response_customer_state
get_customer.customer_zip = response_customer_zip
get_customer.customer_email = response_customer_email
get_customer.customer_apt = response_customer_apt
get_customer.correct_address = cor_ad
state_code = response_customer_state if response_customer_state is not None else get_customer.customer_state
if state_code == 0:
the_state = 'MA'
elif state_code == 1:
the_state = 'RI'
elif state_code == 2:
the_state = 'NH'
else:
the_state = 'MA'
town = response_customer_town if response_customer_town is not None else get_customer.customer_town
address = get_customer.customer_address
geolocator = Nominatim(user_agent="auburnoil")
address_string = address + ' ' + town + ' ' + the_state
try:
location = geolocator.geocode(address_string, timeout=10)
get_customer.customer_latitude = location.latitude
get_customer.customer_longitude = location.longitude
get_customer.correct_address = True
except Exception:
get_customer.customer_latitude = None
get_customer.customer_longitude = None
get_customer.correct_address = False
db.session.add(get_customer)
@@ -407,6 +405,7 @@ def edit_customer(customer_id):
def delete_customer(customer_id):
"""
"""
logger.info(f"DELETE /customer/delete/{customer_id} - Deleting customer")
get_customer = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.id == customer_id)
@@ -436,6 +435,7 @@ def delete_customer(customer_id):
def customer_count():
"""
"""
logger.info("GET /customer/count - Getting customer count")
get_customer = (db.session
.query(Customer_Customer)
.count())
@@ -451,6 +451,7 @@ def customer_count():
def customer_automatic_status(customer_id):
"""
"""
logger.info(f"GET /customer/automatic/status/{customer_id} - Checking auto delivery status")
get_customer = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.id == customer_id)
@@ -475,7 +476,7 @@ def get_all_automatic_deliveries():
"""
Get all automatic deliveries for the table.
"""
logger.info("GET /customer/automatic/deliveries - Fetching all auto deliveries")
try:
deliveries = Auto_Delivery.query.all()
schema = Auto_Delivery_schema(many=True)
@@ -491,6 +492,7 @@ def get_all_automatic_deliveries():
def customer_automatic_assignment(customer_id):
"""
"""
logger.info(f"GET /customer/automatic/assign/{customer_id} - Toggling auto delivery assignment")
get_customer = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.id == customer_id)
@@ -578,6 +580,7 @@ def edit_customer_tank(customer_id):
"""
Safely edits or creates tank and description details for a customer.
"""
logger.info(f"PUT /customer/edit/tank/{customer_id} - Editing customer tank info")
get_customer = db.session.query(Customer_Customer).filter(Customer_Customer.id == customer_id).one_or_none()
if not get_customer:
return jsonify({"ok": False, "error": "Customer not found"}), 404

View File

@@ -1,8 +1,12 @@
import logging
from flask import request, jsonify
from flask_login import current_user
from datetime import date, datetime, timedelta
from app.delivery import delivery
from app import db
from app.common.decorators import login_required as common_login_required
logger = logging.getLogger(__name__)
from sqlalchemy import or_
from app.classes.customer import (Customer_Customer)
from app.classes.delivery import (Delivery_Delivery,
@@ -20,6 +24,7 @@ from app.classes.auto import Tickets_Auto_Delivery, Tickets_Auto_Delivery_schema
# This endpoint is fine, but I've added some comments for clarity.
@delivery.route("/updatestatus", methods=["GET"])
@common_login_required
def move_deliveries():
"""
Batch updates delivery statuses based on their expected delivery date relative to today.
@@ -28,6 +33,7 @@ def move_deliveries():
- Future deliveries -> "Waiting" (0)
- Past-due deliveries -> "Pending" (9)
"""
logger.info("GET /delivery/updatestatus - Batch updating delivery statuses")
counter = 0
today = date.today()
tomorrow = today + timedelta(days=1)
@@ -84,10 +90,12 @@ def move_deliveries():
@delivery.route("/<int:delivery_id>", methods=["GET"])
@common_login_required
def get_a_delivery(delivery_id):
"""
Get a single delivery's details.
"""
logger.info(f"GET /delivery/{delivery_id} - Fetching delivery")
get_delivery = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.id == delivery_id).first()
if not get_delivery:
return jsonify({"ok": False, "error": "Delivery not found"}), 404
@@ -101,8 +109,9 @@ def get_a_delivery(delivery_id):
@delivery.route("/past1/<int:customer_id>", methods=["GET"])
@common_login_required
def get_customer_past_delivery1(customer_id):
logger.info(f"GET /delivery/past1/{customer_id} - Fetching customer past deliveries (first 5)")
get_customer_past_delivery = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.customer_id == customer_id)
@@ -114,8 +123,9 @@ def get_customer_past_delivery1(customer_id):
@delivery.route("/past2/<int:customer_id>", methods=["GET"])
@common_login_required
def get_customer_past_delivery2(customer_id):
logger.info(f"GET /delivery/past2/{customer_id} - Fetching customer past deliveries (next 5)")
get_customer_past_delivery = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.customer_id == customer_id)
@@ -127,7 +137,9 @@ def get_customer_past_delivery2(customer_id):
return jsonify(delivery_schema.dump(get_customer_past_delivery))
@delivery.route("/auto/<int:customer_id>", methods=["GET"])
@common_login_required
def get_customer_auto_delivery(customer_id):
logger.info(f"GET /delivery/auto/{customer_id} - Fetching customer auto deliveries")
get_customer_past_delivery = (db.session
.query(Tickets_Auto_Delivery)
.filter(Tickets_Auto_Delivery.customer_id == customer_id)
@@ -140,6 +152,7 @@ def get_customer_auto_delivery(customer_id):
@delivery.route("/order/<int:delivery_id>", methods=["GET"])
@common_login_required
def get_a_specific_delivery(delivery_id):
"""
Get a single delivery by its ID.
@@ -155,6 +168,7 @@ def get_a_specific_delivery(delivery_id):
@delivery.route("/cash/<int:delivery_id>/<int:type_of_payment>", methods=["PUT"])
@common_login_required
def update_a_delivery_payment(delivery_id, type_of_payment):
"""
This update a delivery for example if user updates to a fill
@@ -175,6 +189,7 @@ def update_a_delivery_payment(delivery_id, type_of_payment):
@delivery.route("/all/<int:page>", methods=["GET"])
@common_login_required
def get_deliveries_all(page):
"""
This will get deliveries not done
@@ -200,6 +215,7 @@ def get_deliveries_all(page):
@delivery.route("/customer/<int:customer_id>/<int:page>", methods=["GET"])
@common_login_required
def get_deliveries_from_customer(customer_id, page):
"""
This will get deliveries not done
@@ -225,6 +241,7 @@ def get_deliveries_from_customer(customer_id, page):
@delivery.route("/all/order/<int:page>", methods=["GET"])
@common_login_required
def get_deliveries_not_delivered(page):
"""
@@ -250,6 +267,7 @@ def get_deliveries_not_delivered(page):
@delivery.route("/waiting/<int:page>", methods=["GET"])
@common_login_required
def get_deliveries_waiting(page):
"""
This will get deliveries not done
@@ -278,6 +296,7 @@ def get_deliveries_waiting(page):
@delivery.route("/pending/<int:page>", methods=["GET"])
@common_login_required
def get_deliveries_pending(page):
"""
"""
@@ -299,6 +318,7 @@ def get_deliveries_pending(page):
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/outfordelivery/<int:page>", methods=["GET"])
@common_login_required
def get_deliveries_outfordelivery(page):
"""
"""
@@ -322,6 +342,7 @@ def get_deliveries_outfordelivery(page):
@delivery.route("/tommorrow/<int:page>", methods=["GET"])
@common_login_required
def get_deliveries_tommorrow(page):
"""
This will get deliveries not done
@@ -348,6 +369,7 @@ def get_deliveries_tommorrow(page):
@delivery.route("/finalized/<int:page>", methods=["GET"])
@common_login_required
def get_deliveries_finalized(page):
"""
This will get deliveries not done
@@ -372,6 +394,7 @@ def get_deliveries_finalized(page):
@delivery.route("/cancelled/<int:page>", methods=["GET"])
@common_login_required
def get_deliveries_cancelled(page):
"""
This will get deliveries not done
@@ -396,6 +419,7 @@ def get_deliveries_cancelled(page):
@delivery.route("/partialdelivery/<int:page>", methods=["GET"])
@common_login_required
def get_deliveries_partial(page):
"""
This will get deliveries not done
@@ -420,6 +444,7 @@ def get_deliveries_partial(page):
@delivery.route("/issue/<int:page>", methods=["GET"])
@common_login_required
def get_deliveries_issue(page):
"""
This will get deliveries not done
@@ -444,6 +469,7 @@ def get_deliveries_issue(page):
@delivery.route("/time/today", methods=["GET"])
@common_login_required
def get_deliveries_today():
"""
This will get today's deliveries
@@ -460,10 +486,12 @@ def get_deliveries_today():
@delivery.route("/edit/<int:delivery_id>", methods=["POST"])
@common_login_required
def edit_a_delivery(delivery_id):
"""
This will edit a delivery using a delivery id.
"""
logger.info(f"POST /delivery/edit/{delivery_id} - Editing delivery")
data = request.json
get_delivery = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.id == delivery_id).first()
@@ -561,10 +589,12 @@ def edit_a_delivery(delivery_id):
@delivery.route("/create/<int:user_id>", methods=["POST"])
@common_login_required
def create_a_delivery(user_id):
"""
This will create a delivery using a customer id
"""
logger.info(f"POST /delivery/create/{user_id} - Creating delivery for customer")
get_customer = db.session\
.query(Customer_Customer)\
.filter(Customer_Customer.id == user_id)\
@@ -600,7 +630,7 @@ def create_a_delivery(user_id):
promo_id = request.json["promo_id"]
else:
promo_id = None
except:
except (KeyError, TypeError):
promo_id = None
if promo_id is not None:
get_promo_data = (db.session
@@ -651,7 +681,7 @@ def create_a_delivery(user_id):
card_payment_id = request.json["credit_card_id"]
else:
card_payment_id = None
except:
except (KeyError, TypeError):
card_payment_id = None
if card_payment_id is not None:
@@ -777,10 +807,12 @@ def create_a_delivery(user_id):
@delivery.route("/cancel/<int:delivery_id>", methods=["POST"])
@common_login_required
def cancel_a_delivery(delivery_id):
"""
This will cancel a delivery
"""
logger.info(f"POST /delivery/cancel/{delivery_id} - Cancelling delivery")
get_delivery = db.session\
.query(Delivery_Delivery)\
.filter(Delivery_Delivery.id == delivery_id)\
@@ -794,10 +826,12 @@ def cancel_a_delivery(delivery_id):
@delivery.route("/delivered/<int:delivery_id>", methods=["POST"])
@common_login_required
def mark_as_delivered(delivery_id):
"""
This will mark the delivery as delivered
"""
logger.info(f"POST /delivery/delivered/{delivery_id} - Marking delivery as delivered")
# how many gallons delivered
gallons_put_into_tank = request.json["gallons_put_into_tank"]
# was the tank full or not
@@ -819,6 +853,7 @@ def mark_as_delivered(delivery_id):
@delivery.route("/partial/<int:delivery_id>", methods=["POST"])
@common_login_required
def partial_delivery(delivery_id):
"""
This will mark the delivery as delivered
@@ -842,6 +877,7 @@ def partial_delivery(delivery_id):
@delivery.route("/note/technician/<int:delivery_id>", methods=["PUT"])
@common_login_required
def delivery_note_driver(delivery_id):
"""
@@ -876,10 +912,12 @@ def delivery_note_driver(delivery_id):
@delivery.route("/delete/<int:delivery_id>", methods=["DELETE"])
@common_login_required
def delete_call(delivery_id):
"""
delete a delivery call
"""
logger.info(f"DELETE /delivery/delete/{delivery_id} - Deleting delivery")
get_call_to_delete = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.id == delivery_id)
@@ -893,6 +931,7 @@ def delete_call(delivery_id):
@delivery.route("/total/<int:delivery_id>", methods=["GET"])
@common_login_required
def calculate_total(delivery_id):
"""
This will get deliveries not done

View File

@@ -1,3 +1,4 @@
import logging
from flask import request, jsonify
from datetime import datetime
from decimal import Decimal
@@ -11,6 +12,8 @@ from app.classes.stats_employee import Stats_Employee_Oil
from app.classes.auto import Auto_Delivery
from app.classes.stats_customer import Stats_Customer
logger = logging.getLogger(__name__)
@delivery_data.route("/finalize/<int:delivery_id>", methods=["PUT"])
def office_finalize_delivery(delivery_id):
"""
@@ -20,6 +23,7 @@ def office_finalize_delivery(delivery_id):
"""
Finalizes a delivery from office
"""
logger.info(f"PUT /deliverydata/finalize/{delivery_id} - Finalizing delivery from office")
now = datetime.utcnow()
get_delivery = db.session \
.query(Delivery_Delivery) \

View File

@@ -1,3 +1,4 @@
import logging
from flask import jsonify
from datetime import date, timedelta
from app.delivery_status import deliverystatus
@@ -13,6 +14,8 @@ from app.classes.transactions import Transaction
from datetime import date, timedelta, datetime
from zoneinfo import ZoneInfo
logger = logging.getLogger(__name__)
# --- NEW EFFICIENT ENDPOINT ---
@deliverystatus.route("/stats/sidebar-counts", methods=["GET"])
@@ -21,6 +24,7 @@ def get_sidebar_counts():
Efficiently gets all counts needed for the navigation sidebar in a single request.
This combines logic from all the individual /count/* endpoints.
"""
logger.info("GET /deliverystatus/stats/sidebar-counts - Fetching sidebar counts")
try:
eastern = ZoneInfo("America/New_York")
now_local = datetime.now(eastern).replace(tzinfo=None) # naive local time
@@ -73,6 +77,7 @@ def get_tomorrow_totals():
"""
Get total gallons by town for tomorrow's deliveries, including grand total.
"""
logger.info("GET /deliverystatus/tomorrow-totals - Fetching tomorrow delivery totals")
try:
deliveries = db.session.query(
Delivery_Delivery.customer_town,
@@ -101,6 +106,7 @@ def get_today_totals():
"""
Get total gallons by town for today's deliveries, including grand total.
"""
logger.info("GET /deliverystatus/today-totals - Fetching today delivery totals")
try:
deliveries = db.session.query(
Delivery_Delivery.customer_town,
@@ -129,6 +135,7 @@ def get_waiting_totals():
"""
Get total gallons by town for waiting deliveries, including grand total.
"""
logger.info("GET /deliverystatus/waiting-totals - Fetching waiting delivery totals")
try:
deliveries = db.session.query(
Delivery_Delivery.customer_town,

View File

@@ -1,3 +1,4 @@
import logging
from flask import request, jsonify
from sqlalchemy import or_
@@ -9,9 +10,12 @@ from app.classes.employee import Employee_Employee, Employee_Employee_schema
from app.classes.auth import Auth_User
from app.classes.stats_employee import Stats_Employee_Oil, Stats_Employee_Office
logger = logging.getLogger(__name__)
@employees.route("/<int:userid>", methods=["GET"])
@login_required
def get_specific_employee(userid):
logger.info(f"GET /employees/{userid} - Fetching employee by user ID")
employee = db.session \
.query(Employee_Employee) \
.filter(Employee_Employee.user_id == userid) \
@@ -31,6 +35,7 @@ def get_specific_employee(userid):
@employees.route("/byid/<int:employee_id>", methods=["GET"])
@login_required
def get_employee_by_id(employee_id):
logger.info(f"GET /employees/byid/{employee_id} - Fetching employee by ID")
employee = db.session \
.query(Employee_Employee) \
.filter(Employee_Employee.id == employee_id) \
@@ -42,6 +47,7 @@ def get_employee_by_id(employee_id):
@employees.route("/userid/<int:userid>", methods=["GET"])
@login_required
def get_specific_employee_user_id(userid):
logger.info(f"GET /employees/userid/{userid} - Fetching employee by user ID")
employee = db.session \
.query(Employee_Employee) \
.filter(Employee_Employee.user_id == userid) \
@@ -56,6 +62,7 @@ def all_employees_paginated(page):
"""
pagination all employees
"""
logger.info(f"GET /employees/all/{page} - Fetching employees page {page}")
per_page_amount = 50
if page is None:
offset_limit = 0
@@ -75,6 +82,7 @@ def all_employees_paginated(page):
@employees.route("/all", methods=["GET"])
@login_required
def all_employees():
logger.info("GET /employees/all - Fetching all employees")
employee_list = db.session \
.query(Employee_Employee) \
.all()
@@ -85,6 +93,7 @@ def all_employees():
@employees.route("/drivers", methods=["GET"])
@login_required
def all_employees_drivers():
logger.info("GET /employees/drivers - Fetching all drivers")
employee_list = db.session \
.query(Employee_Employee) \
.filter(or_(Employee_Employee.employee_type == 4,
@@ -98,6 +107,7 @@ def all_employees_drivers():
@employees.route("/techs", methods=["GET"])
@login_required
def all_employees_techs():
logger.info("GET /employees/techs - Fetching all technicians")
employee_list = db.session \
.query(Employee_Employee) \
.filter(or_(Employee_Employee.employee_type == 0,
@@ -116,6 +126,7 @@ def employee_create():
"""
This will create an employee
"""
logger.info("POST /employees/create - Creating new employee")
e_last_name = request.json["employee_last_name"]
e_first_name = request.json["employee_first_name"]
e_town = request.json["employee_town"]
@@ -180,6 +191,7 @@ def employee_edit(employee_id):
"""
This will update an employee
"""
logger.info(f"POST /employees/edit/{employee_id} - Editing employee")
e_last_name = request.json["employee_last_name"]
e_first_name = request.json["employee_first_name"]
e_town = request.json["employee_town"]

View File

@@ -1,3 +1,4 @@
import logging
from flask import jsonify
from decimal import Decimal
from app.info import info
@@ -6,10 +7,15 @@ from app.classes.pricing import Pricing_Oil_Oil, Pricing_Oil_Oil_schema
from app.classes.admin import Admin_Company
from app.classes.delivery import Delivery_Delivery
from app.classes.service import Service_Service
from flask_login import login_required
logger = logging.getLogger(__name__)
@info.route("/price/oil/tiers", methods=["GET"])
@login_required
def get_pricing_tiers():
logger.info("GET /info/price/oil/tiers - Fetching oil pricing tiers")
get_price_query = (db.session
.query(Pricing_Oil_Oil)
.order_by(Pricing_Oil_Oil.date.desc())
@@ -34,7 +40,9 @@ def get_pricing_tiers():
return jsonify(pricing_totals)
@info.route("/price/oil", methods=["GET"])
@login_required
def get_oil_price_today():
logger.info("GET /info/price/oil - Fetching current oil prices")
get_price_query = (db.session
.query(Pricing_Oil_Oil)
.order_by(Pricing_Oil_Oil.date.desc())
@@ -50,7 +58,9 @@ def get_oil_price_today():
@info.route("/price/oil/table", methods=["GET"])
@login_required
def get_pricing():
logger.info("GET /info/price/oil/table - Fetching oil pricing table")
get_price_query = (db.session
.query(Pricing_Oil_Oil)
.order_by(Pricing_Oil_Oil.date.desc())
@@ -63,7 +73,9 @@ def get_pricing():
@info.route("/company", methods=["GET"])
@login_required
def get_company():
logger.info("GET /info/company - Fetching company information")
get_data_company = (db.session
.query(Admin_Company)
.first())

View File

@@ -1,14 +1,19 @@
import logging
from flask import jsonify, Response, url_for
from app import app
logger = logging.getLogger(__name__)
@app.route("/favicon.ico")
def favicon():
logger.info("GET /favicon.ico - Serving favicon")
return url_for('static', filename='data:,')
@app.route('/robots.txt')
@app.route('/sitemap.xml')
def static_from_root():
logger.info("GET /robots.txt or /sitemap.xml - Serving robots/sitemap")
def disallow(string): return 'Disallow: {0}'.format(string)
return Response("User-agent: *\n{0}\n".format("\n".join([
disallow('/bin/*'),
@@ -19,5 +24,5 @@ def static_from_root():
@app.route('/index', methods=['GET'])
@app.route('/', methods=['GET'])
def index():
logger.info("GET / or /index - API health check")
return jsonify({"success": "Api is online"}), 200

View File

@@ -1,3 +1,4 @@
import logging
from flask import jsonify
from app.money import money
from app import db
@@ -6,6 +7,8 @@ from datetime import date
from app.classes.money import Money_delivery, Money_delivery_schema
from app.classes.delivery import Delivery_Delivery, Delivery_Delivery_schema
logger = logging.getLogger(__name__)
def get_monday_date(date_object):
"""Gets the date of the Monday for the given date."""
@@ -25,6 +28,7 @@ def get_monday_date(date_object):
@money.route("/profit/week", methods=["GET"])
def total_profit_week():
logger.info("GET /money/profit/week - Calculating weekly profit")
# Get today's date
total_profit = 0
total_deliveries = 0
@@ -52,6 +56,7 @@ def total_profit_week():
@money.route("/profit/year", methods=["GET"])
def total_profit_year():
logger.info("GET /money/profit/year - Calculating yearly profit")
# Get today's date
total_profit = 0
@@ -74,10 +79,11 @@ def total_profit_year():
def get_money_delivery(delivery_id):
"""
"""
logger.info(f"GET /money/{delivery_id} - Fetching delivery profit data")
profit = (db.session
.query(Money_delivery)
.filter(Money_delivery.delivery_id == delivery_id)
.first())
money_schema = Money_delivery_schema(many=False)
return jsonify(money_schema.dump(profit))
return jsonify(money_schema.dump(profit))

View File

@@ -1,3 +1,4 @@
import logging
from flask import jsonify, request
from app.payment import payment
from app import db
@@ -6,6 +7,9 @@ from app.classes.cards import Card_Card, Card_Card_schema
from app.classes.transactions import Transaction
from app.classes.delivery import Delivery_Delivery
from app.classes.service import Service_Service, Service_Service_schema
from flask_login import login_required
logger = logging.getLogger(__name__)
@@ -52,10 +56,12 @@ def set_card_main(user_id, card_id):
@payment.route("/cards/<int:user_id>", methods=["GET"])
@login_required
def get_user_cards(user_id):
"""
gets all cards of a user
"""
logger.info(f"GET /payment/cards/{user_id} - Fetching user cards")
get_u_cards = (db.session
.query(Card_Card)
.filter(Card_Card.user_id == user_id)
@@ -66,11 +72,12 @@ def get_user_cards(user_id):
@payment.route("/cards/onfile/<int:user_id>", methods=["GET"])
@login_required
def get_user_cards_count(user_id):
"""
gets all cards of a user
"""
logger.info(f"GET /payment/cards/onfile/{user_id} - Getting card count")
get_u_cards = (db.session
.query(Card_Card)
.filter(Card_Card.user_id == user_id)
@@ -83,6 +90,7 @@ def get_user_cards_count(user_id):
@payment.route("/card/<int:card_id>", methods=["GET"])
@login_required
def get_user_specific_card(card_id):
"""
gets a specific card of a user
@@ -99,6 +107,7 @@ def get_user_specific_card(card_id):
@payment.route("/card/main/<int:card_id>/<int:user_id>", methods=["PUT"])
@login_required
def set_main_card(user_id, card_id):
"""
updates a card of a user
@@ -130,11 +139,12 @@ def set_main_card(user_id, card_id):
@payment.route("/card/remove/<int:card_id>", methods=["DELETE"])
@login_required
def remove_user_card(card_id):
"""
removes a card
removes a card
"""
logger.info(f"DELETE /payment/card/remove/{card_id} - Removing card")
get_card = (db.session
.query(Card_Card)
.filter(Card_Card.id == card_id)
@@ -151,6 +161,7 @@ def remove_user_card(card_id):
# ... (your existing imports: jsonify, request, db, Customer_Customer, Card_Card) ...
@payment.route("/card/create/<int:user_id>", methods=["POST"])
@login_required
def create_user_card(user_id):
"""
Adds a card for a user to the local database. This is its only job.
@@ -196,17 +207,18 @@ def create_user_card(user_id):
set_card_main(user_id=get_customer.id, card_id=create_new_card.id)
db.session.commit()
print(f"SUCCESS: Card saved locally for user {user_id} with new ID {create_new_card.id}")
logger.info(f"Card saved locally for user {user_id} with ID {create_new_card.id}")
except Exception as e:
db.session.rollback()
print(f"DATABASE ERROR: Could not save card for user {user_id}. Error: {e}")
logger.error(f"Database error saving card for user {user_id}: {e}")
return jsonify({"ok": False, "error": "Failed to save card information."}), 500
# Return a success response with the card_id
return jsonify({"ok": True, "card_id": create_new_card.id}), 200
@payment.route("/card/update_payment_profile/<int:card_id>", methods=["PUT"])
@login_required
def update_card_payment_profile(card_id):
"""
Updates the auth_net_payment_profile_id for a card
@@ -230,6 +242,7 @@ def update_card_payment_profile(card_id):
@payment.route("/card/edit/<int:card_id>", methods=["PUT"])
@login_required
def update_user_card(card_id):
"""
edits a card
@@ -277,6 +290,7 @@ def update_user_card(card_id):
@payment.route("/transactions/authorize/<int:page>", methods=["GET"])
@login_required
def get_authorize_transactions(page):
"""
Gets transactions with transaction_type = 0 (charge), for the authorize page
@@ -320,6 +334,7 @@ def get_authorize_transactions(page):
@payment.route("/authorize/cleanup/<int:customer_id>", methods=["POST"])
@login_required
def cleanup_authorize_profile(customer_id):
"""
Clean up Authorize.Net profile data in local database when API check fails.
@@ -349,6 +364,7 @@ def cleanup_authorize_profile(customer_id):
@payment.route("/authorize/<int:delivery_id>", methods=["PUT"])
@login_required
def update_delivery_payment_authorize(delivery_id):
"""
Update a delivery's payment_type to 11 (CC - Authorize API) after successful preauthorization
@@ -370,6 +386,7 @@ def update_delivery_payment_authorize(delivery_id):
@payment.route("/transaction/delivery/<int:delivery_id>", methods=["GET"])
@login_required
def get_transaction_by_delivery(delivery_id):
"""
Get a single transaction by delivery_id for Authorize.net payments
@@ -403,6 +420,7 @@ def get_transaction_by_delivery(delivery_id):
@payment.route("/transactions/customer/<int:customer_id>/<int:page>", methods=["GET"])
@login_required
def get_customer_transactions(customer_id, page):
"""
Gets transactions for a specific customer
@@ -445,6 +463,7 @@ def get_customer_transactions(customer_id, page):
@payment.route("/service/payment/<int:service_id>/<int:payment_type>", methods=["PUT"])
@login_required
def process_service_payment_tiger(service_id, payment_type):
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
if not service:
@@ -464,6 +483,7 @@ def process_service_payment_tiger(service_id, payment_type):
@payment.route("/authorize/service/<int:service_id>", methods=["PUT"])
@login_required
def update_service_payment_authorize(service_id):
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
if not service:
@@ -487,6 +507,7 @@ def update_service_payment_authorize(service_id):
@payment.route("/capture/service/<int:service_id>", methods=["PUT"])
@login_required
def update_service_payment_capture(service_id):
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
if not service:
@@ -511,6 +532,7 @@ def update_service_payment_capture(service_id):
@payment.route("/transactions/service/<int:service_id>", methods=["GET"])
@login_required
def get_service_transactions(service_id):
"""
Gets all transactions for a specific service ID
@@ -544,5 +566,5 @@ def get_service_transactions(service_id):
return jsonify(transactions_data), 200
except Exception as e:
print(f"Error fetching transactions for service {service_id}: {str(e)}")
logger.error(f"Error fetching transactions for service {service_id}: {e}")
return jsonify({"ok": False, "error": str(e)}), 500

View File

@@ -1,3 +1,4 @@
import logging
from flask import request, jsonify
import decimal
from datetime import datetime
@@ -11,6 +12,8 @@ from app.classes.delivery import (Delivery_Delivery,
Delivery_Notes_Driver,
)
logger = logging.getLogger(__name__)
def convert_to_decimal(text):
try:
number = float(text)
@@ -23,9 +26,10 @@ def convert_to_decimal(text):
def get_promo(promo_id):
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
logger.info(f"GET /promo/{promo_id} - Fetching promo")
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
.first())
query_schema = Promo_Promo_schema(many=False)
return jsonify(query_schema.dump(get_promo_data))
@@ -35,6 +39,7 @@ def get_promo(promo_id):
def get_promo_price(delivery_id):
"""
"""
logger.info(f"GET /promo/promoprice/{delivery_id} - Calculating promo price")
get_delivery = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.id == delivery_id)
@@ -53,8 +58,9 @@ def get_promo_price(delivery_id):
def get_all_promo():
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
logger.info("GET /promo/all - Fetching all promos")
get_promo_data = (db.session
.query(Promo_Promo)
.all())
query_schema = Promo_Promo_schema(many=True)
return jsonify(query_schema.dump(get_promo_data))
@@ -64,11 +70,12 @@ def get_all_promo():
def delete_a_promo(promo_id):
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
logger.info(f"DELETE /promo/delete/{promo_id} - Deleting promo")
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
.first())
db.session.delete(get_promo_data)
db.session.commit()
@@ -81,6 +88,7 @@ def delete_a_promo(promo_id):
def create_promo():
"""
"""
logger.info("POST /promo/create - Creating new promo")
date_created = datetime.utcnow()
name_of_promotion = request.json["name_of_promotion"]
money_off_delivery = request.json["money_off_delivery"]
@@ -94,13 +102,13 @@ def create_promo():
name_of_promotion = name_of_promotion,
money_off_delivery = amount_off,
description = description,
date_created = date_created,
date_created = date_created,
text_on_ticket=text_on_ticket
)
db.session.add(new_promo)
db.session.commit()
return jsonify({
"ok": True,
'promo_id':new_promo.id,
@@ -112,9 +120,10 @@ def edit_promo(promo_id):
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
logger.info(f"PUT /promo/edit/{promo_id} - Editing promo")
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
.first())
text_on_ticket = request.json["text_on_ticket"]
name_of_promotion = request.json["name_of_promotion"]
@@ -144,13 +153,14 @@ def turn_on_promo(promo_id):
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
logger.info(f"PATCH /promo/on/{promo_id} - Activating promo")
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
.first())
get_promo_data.active = True
db.session.add(get_promo_data)
db.session.commit()
@@ -165,13 +175,14 @@ def turn_off_promo(promo_id):
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
logger.info(f"PATCH /promo/off/{promo_id} - Deactivating promo")
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
.first())
get_promo_data.active = False
db.session.add(get_promo_data)
db.session.commit()
@@ -179,4 +190,4 @@ def turn_off_promo(promo_id):
return jsonify({
"ok": True,
'promo_id':get_promo_data.id,
}), 200
}), 200

View File

@@ -1,34 +1,42 @@
import logging
from flask import jsonify
from app.query import query
from app import db
from app.classes.admin import Admin_Company
from app.classes.query import (Query_StateList,
Query_DeliveryStatusList,
Query_DeliveryStatusList_Schema,
Query_StateList_Schema,
Query_CustomerTypeList,
Query_DeliveryStatusList,
Query_DeliveryStatusList_Schema,
Query_StateList_Schema,
Query_CustomerTypeList,
Query_CustomerTypeList_Schema,
Query_EmployeeTypeList,
Query_EmployeeTypeList,
Query_EmployeeTypeList_Schema)
from flask_login import login_required
logger = logging.getLogger(__name__)
@query.route("/company/<int:company_id>", methods=["GET"])
@login_required
def get_company(company_id):
"""
This will get the company from env variable
"""
logger.info(f"GET /query/company/{company_id} - Fetching company data")
query_data = (db.session
.query(Admin_Company)
.filter(Admin_Company.id == company_id)
query_data = (db.session
.query(Admin_Company)
.filter(Admin_Company.id == company_id)
.first())
delivery_schema = Query_DeliveryStatusList_Schema(many=False)
return jsonify(delivery_schema.dump(query_data))
@query.route("/states", methods=["GET"])
@login_required
def get_state_list():
"""
This will get states
"""
logger.info("GET /query/states - Fetching state list")
query_data = db.session \
.query(Query_StateList) \
@@ -39,10 +47,12 @@ def get_state_list():
@query.route("/customertype", methods=["GET"])
@login_required
def get_customer_type_list():
"""
This will get types of customers
"""
logger.info("GET /query/customertype - Fetching customer type list")
query_data = db.session \
.query(Query_CustomerTypeList) \
@@ -54,10 +64,12 @@ def get_customer_type_list():
@query.route("/employeetype", methods=["GET"])
@login_required
def get_employee_type_list():
"""
This will get types of service
"""
logger.info("GET /query/employeetype - Fetching employee type list")
query_data = db.session \
.query(Query_EmployeeTypeList) \
@@ -67,16 +79,15 @@ def get_employee_type_list():
@query.route("/deliverystatus", methods=["GET"])
@login_required
def get_delivery_status_list():
"""
This will get delivery status
"""
logger.info("GET /query/deliverystatus - Fetching delivery status list")
query_data = db.session \
.query(Query_DeliveryStatusList) \
.all()
delivery_schema = Query_DeliveryStatusList_Schema(many=True)
return jsonify(delivery_schema.dump(query_data))

View File

@@ -1,3 +1,4 @@
import logging
from flask import jsonify
from sqlalchemy.sql import func
from app.reports import reports
@@ -7,14 +8,17 @@ from app.classes.customer import Customer_Customer
from app.classes.delivery import Delivery_Delivery
logger = logging.getLogger(__name__)
@reports.route("/oil/total", methods=["GET"])
def oil_total_gallons():
logger.info("GET /reports/oil/total - Calculating total oil delivered")
total_oil = db.session\
.query(func.sum(Delivery_Delivery.gallons_delivered))\
.group_by(Delivery_Delivery.id)\
.all()
return jsonify({"ok": True, "oil": total_oil }), 200
@reports.route("/customers/list", methods=["GET"])
@@ -24,6 +28,7 @@ def customer_list():
Returns account number, first name, last name, address, town, and phone number.
Ordered by last name from A to Z.
"""
logger.info("GET /reports/customers/list - Fetching customer list for reports")
customers = db.session.query(Customer_Customer).order_by(Customer_Customer.customer_last_name.asc()).all()
customer_data = [

4
app/schemas/__init__.py Normal file
View File

@@ -0,0 +1,4 @@
# Validation schemas for API requests
from .customer import CreateCustomerSchema, UpdateCustomerSchema, UpdateDescriptionSchema
from .auth import LoginSchema, RegisterSchema, ChangePasswordSchema
from .utils import validate_request, validate_json

56
app/schemas/auth.py Normal file
View File

@@ -0,0 +1,56 @@
from marshmallow import Schema, fields, validate, EXCLUDE
class LoginSchema(Schema):
"""Validation schema for user login"""
class Meta:
unknown = EXCLUDE
username = fields.Str(
required=True,
validate=validate.Length(min=3, max=100),
error_messages={"required": "Username is required"}
)
password = fields.Str(
required=True,
validate=validate.Length(min=6, max=200),
error_messages={"required": "Password is required"}
)
class RegisterSchema(Schema):
"""Validation schema for user registration"""
class Meta:
unknown = EXCLUDE
username = fields.Str(
required=True,
validate=validate.Length(min=3, max=100),
error_messages={"required": "Username is required"}
)
password = fields.Str(
required=True,
validate=validate.Length(min=6, max=200),
error_messages={"required": "Password is required"}
)
email = fields.Email(
required=True,
error_messages={"required": "Email is required"}
)
class ChangePasswordSchema(Schema):
"""Validation schema for password change"""
class Meta:
unknown = EXCLUDE
new_password = fields.Str(
required=True,
validate=validate.Length(min=6, max=200),
error_messages={"required": "New password is required"}
)
password_confirm = fields.Str(
required=True,
validate=validate.Length(min=6, max=200),
error_messages={"required": "Password confirmation is required"}
)

126
app/schemas/customer.py Normal file
View File

@@ -0,0 +1,126 @@
from marshmallow import Schema, fields, validate, EXCLUDE
class CreateCustomerSchema(Schema):
"""Validation schema for creating a new customer"""
class Meta:
unknown = EXCLUDE
customer_last_name = fields.Str(
required=True,
validate=validate.Length(min=1, max=250),
error_messages={"required": "Last name is required"}
)
customer_first_name = fields.Str(
required=True,
validate=validate.Length(min=1, max=250),
error_messages={"required": "First name is required"}
)
customer_town = fields.Str(
required=True,
validate=validate.Length(min=1, max=140),
error_messages={"required": "Town is required"}
)
customer_state = fields.Int(
required=True,
validate=validate.Range(min=0, max=50),
error_messages={"required": "State is required"}
)
customer_zip = fields.Str(
required=True,
validate=validate.Length(min=5, max=10),
error_messages={"required": "Zip code is required"}
)
customer_email = fields.Email(
allow_none=True,
load_default=None
)
customer_home_type = fields.Int(
required=True,
validate=validate.Range(min=0, max=10),
error_messages={"required": "Home type is required"}
)
customer_phone_number = fields.Str(
allow_none=True,
validate=validate.Length(max=25),
load_default=None
)
customer_address = fields.Str(
required=True,
validate=validate.Length(min=1, max=1000),
error_messages={"required": "Address is required"}
)
customer_apt = fields.Str(
allow_none=True,
validate=validate.Length(max=140),
load_default=None
)
customer_description = fields.Str(
allow_none=True,
validate=validate.Length(max=2000),
load_default=None
)
class UpdateCustomerSchema(Schema):
"""Validation schema for updating an existing customer"""
class Meta:
unknown = EXCLUDE
customer_last_name = fields.Str(
validate=validate.Length(min=1, max=250)
)
customer_first_name = fields.Str(
validate=validate.Length(min=1, max=250)
)
customer_town = fields.Str(
validate=validate.Length(min=1, max=140)
)
customer_state = fields.Int(
validate=validate.Range(min=0, max=50)
)
customer_zip = fields.Str(
validate=validate.Length(min=5, max=10)
)
customer_email = fields.Email(
allow_none=True
)
customer_home_type = fields.Int(
validate=validate.Range(min=0, max=10)
)
customer_phone_number = fields.Str(
allow_none=True,
validate=validate.Length(max=25)
)
customer_address = fields.Str(
validate=validate.Length(min=1, max=1000)
)
customer_apt = fields.Str(
allow_none=True,
validate=validate.Length(max=140)
)
customer_automatic = fields.Int(
validate=validate.Range(min=0, max=10)
)
customer_description = fields.Str(
allow_none=True,
validate=validate.Length(max=2000)
)
customer_fill_location = fields.Int(
allow_none=True,
validate=validate.Range(min=0, max=10)
)
class UpdateDescriptionSchema(Schema):
"""Validation schema for updating customer description"""
class Meta:
unknown = EXCLUDE
description = fields.Str(
allow_none=True,
validate=validate.Length(max=2000)
)
fill_location = fields.Int(
allow_none=True
)

56
app/schemas/utils.py Normal file
View File

@@ -0,0 +1,56 @@
from flask import jsonify, request
from functools import wraps
from marshmallow import ValidationError
def validate_request(schema_class):
"""
Decorator to validate incoming JSON request data against a marshmallow schema.
Usage:
@customer.route("/create", methods=["POST"])
@validate_request(CreateCustomerSchema)
def create_customer():
data = request.validated_data # Access validated data
...
"""
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
# Check if request has JSON data
if not request.is_json:
return jsonify({"error": "Request must be JSON"}), 400
json_data = request.get_json()
if json_data is None:
return jsonify({"error": "Invalid JSON data"}), 400
# Validate the data
schema = schema_class()
try:
validated_data = schema.load(json_data)
# Attach validated data to request object for easy access
request.validated_data = validated_data
except ValidationError as err:
return jsonify({"error": "Validation failed", "details": err.messages}), 400
return f(*args, **kwargs)
return decorated_function
return decorator
def validate_json(schema_class, data):
"""
Validate data against a schema and return (validated_data, errors).
Usage:
data, errors = validate_json(CreateCustomerSchema, request.get_json())
if errors:
return jsonify({"error": "Validation failed", "details": errors}), 400
"""
schema = schema_class()
try:
validated_data = schema.load(data or {})
return validated_data, None
except ValidationError as err:
return None, err.messages

View File

@@ -1,3 +1,4 @@
import logging
from flask import request, jsonify
from app.search import search
@@ -5,16 +6,27 @@ from app import db
from sqlalchemy import or_
from app.classes.customer import Customer_Customer, Customer_Customer_schema
from app.classes.delivery import Delivery_Delivery, Delivery_Delivery_schema
from flask_login import login_required
logger = logging.getLogger(__name__)
def escape_like(value: str) -> str:
"""Escape special LIKE characters to prevent LIKE injection."""
if value is None:
return ""
return value.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
@search.route("/customer", methods=["GET"])
@login_required
def search_customers():
"""
"""
keyword = request.args.get('q')
search = "%{}%".format(keyword)
logger.info(f"GET /search/customer - Searching customers with keyword: {keyword}")
search = "%{}%".format(escape_like(keyword))
search_type = (search[1])
search = search.replace("!", "")
search = search.replace("#", "")
@@ -66,12 +78,14 @@ def search_customers():
@search.route("/delivery", methods=["GET"])
@login_required
def search_delivery():
"""
pagination all customers
"""
keyword = request.args.get('q')
search = "%{}%".format(keyword)
logger.info(f"GET /search/delivery - Searching deliveries with keyword: {keyword}")
search = "%{}%".format(escape_like(keyword))
search_type = (search[1])
delivery_ticket = (db.session

View File

@@ -1,3 +1,4 @@
import logging
from flask import request, jsonify
from app.service import service
from app import db
@@ -8,9 +9,14 @@ from app.classes.service import (Service_Service,
Service_Plans, Service_Plans_schema
)
from app.classes.auto import Auto_Delivery
from flask_login import login_required
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 = {
@@ -49,18 +55,19 @@ def get_all_service_calls():
return jsonify(calendar_events), 200
except Exception as e:
# Add error logging to see what's happening
print(f"An error occurred in /service/all: {e}")
logger.error(f"Error in /service/all: {e}")
return jsonify(error=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
@@ -78,6 +85,7 @@ def get_upcoming_service_calls():
@service.route("/past", methods=["GET"])
@login_required
def get_past_service_calls():
"""
Fetches a list of all past service calls before today.
@@ -97,6 +105,7 @@ def get_past_service_calls():
@service.route("/today", methods=["GET"])
@login_required
def get_today_service_calls():
"""
Fetches a list of all service calls for today.
@@ -119,6 +128,7 @@ def get_today_service_calls():
@service.route("/upcoming/count", methods=["GET"])
@login_required
def get_upcoming_service_calls_count():
now = datetime.now()
try:
@@ -128,6 +138,7 @@ def get_upcoming_service_calls_count():
return jsonify({"error": str(e)}), 500
@service.route("/for-customer/<int:customer_id>", 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)
@@ -135,6 +146,7 @@ def get_service_calls_for_customer(customer_id):
return jsonify(result), 200
@service.route("/create", methods=["POST"])
@login_required
def create_service_call():
data = request.get_json()
if not data: return jsonify({"error": "No data provided"}), 400
@@ -155,6 +167,7 @@ def create_service_call():
return jsonify({ "ok": True, "id": new_service_call.id }), 201
@service.route("/update-cost/<int:id>", methods=["PUT"])
@login_required
def update_service_cost(id):
"""
Dedicated endpoint to update only the service cost for a service call.
@@ -196,10 +209,11 @@ def update_service_cost(id):
except Exception as e:
db.session.rollback()
print(f"Error updating service cost for service {id}: {str(e)}")
logger.error(f"Error updating service cost for service {id}: {e}")
return jsonify({"error": str(e)}), 500
@service.route("/update/<int:id>", methods=["PUT"])
@login_required
def update_service_call(id):
service_record = Service_Service.query.get_or_404(id)
data = request.get_json()
@@ -222,6 +236,7 @@ def update_service_call(id):
# 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)
@@ -245,6 +260,7 @@ def get_active_service_plans():
@service.route("/plans/customer/<int:customer_id>", methods=["GET"])
@login_required
def get_customer_service_plan(customer_id):
"""
Get service plan for a specific customer
@@ -261,6 +277,7 @@ def get_customer_service_plan(customer_id):
@service.route("/plans/create", methods=["POST"])
@login_required
def create_service_plan():
"""
Create a new service plan for a customer
@@ -287,6 +304,7 @@ def create_service_plan():
@service.route("/plans/update/<int:customer_id>", methods=["PUT"])
@login_required
def update_service_plan(customer_id):
"""
Update existing service plan for a customer
@@ -317,6 +335,7 @@ def update_service_plan(customer_id):
@service.route("/plans/delete/<int:customer_id>", methods=["DELETE"])
@login_required
def delete_service_plan(customer_id):
"""
Delete service plan for a customer
@@ -334,12 +353,14 @@ def delete_service_plan(customer_id):
return jsonify({"error": str(e)}), 500
@service.route("/<int:id>", 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 jsonify({"ok": True, "service": service_schema.dump(service_record)}), 200
@service.route("/delete/<int:id>", methods=["DELETE"])
@login_required
def delete_service_call(id):
service_record = Service_Service.query.get_or_404(id)
try:
@@ -351,6 +372,7 @@ def delete_service_call(id):
return jsonify({"error": str(e)}), 500
@service.route("/parts/customer/<int:customer_id>", methods=["GET"])
@login_required
def get_service_parts(customer_id):
parts = Service_Parts.query.filter_by(customer_id=customer_id).first()
if parts:
@@ -363,6 +385,7 @@ def get_service_parts(customer_id):
}), 200
@service.route("/parts/update/<int:customer_id>", methods=["POST"])
@login_required
def update_service_parts(customer_id):
try:
data = request.get_json()
@@ -397,6 +420,7 @@ def update_service_parts(customer_id):
@service.route("/payment/<int:service_id>/<int:payment_type>", 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:

View File

@@ -1,14 +1,20 @@
import logging
from flask import jsonify, request
import datetime
from app.social import social
from app import db
from app.classes.customer_social import (Customer_Customer_Social_schema,
from app.classes.customer_social import (Customer_Customer_Social_schema,
Customer_Customer_Social)
from flask_login import login_required
logger = logging.getLogger(__name__)
@social.route("/posts/<int:customer_id>/<int:page>", methods=["GET"])
@login_required
def get_customer_posts(customer_id, page):
logger.info(f"GET /social/posts/{customer_id}/{page} - Fetching customer posts page {page}")
per_page_amount = 50
if page is None:
offset_limit = 0
@@ -16,7 +22,7 @@ def get_customer_posts(customer_id, page):
offset_limit = 0
else:
offset_limit = (per_page_amount * page) - per_page_amount
customer_posts = (db.session
.query(Customer_Customer_Social)
.filter(Customer_Customer_Social.customer_id == customer_id)
@@ -28,8 +34,10 @@ def get_customer_posts(customer_id, page):
@social.route("/create/<int:customer_id>", methods=["POST"])
@login_required
def create_post(customer_id):
logger.info(f"POST /social/create/{customer_id} - Creating new social post")
comment = request.json["comment"]
poster_employee_id = request.json["poster_employee_id"]
@@ -47,7 +55,9 @@ def create_post(customer_id):
@social.route("/posts/<int:post_id>", methods=["PATCH"])
@login_required
def edit_post(post_id):
logger.info(f"PATCH /social/posts/{post_id} - Editing social post")
customer_post = (db.session
.query(Customer_Customer_Social)
@@ -55,7 +65,7 @@ def edit_post(post_id):
.first())
comment = request.json["comment"]
customer_post.comment = comment
db.session.add(customer_post)
db.session.commit()
@@ -64,7 +74,9 @@ def edit_post(post_id):
@social.route("/delete/<int:post_id>", methods=["DELETE"])
@login_required
def delete_post(post_id):
logger.info(f"DELETE /social/delete/{post_id} - Deleting social post")
customer_post = (db.session
.query(Customer_Customer_Social)

View File

@@ -1,3 +1,4 @@
import logging
from flask import jsonify
from datetime import date
from app.stats import stats
@@ -7,6 +8,8 @@ from app.classes.delivery import Delivery_Delivery
from app.classes.stats_company import Stats_Company, Stats_Company_schema
from app.classes.stats_customer import Stats_Customer, Stats_Customer_schema
logger = logging.getLogger(__name__)
def get_monday_date(date_object):
"""Gets the date of the Monday for the given date."""
@@ -27,6 +30,7 @@ def get_monday_date(date_object):
@stats.route("/calls/add", methods=["PUT"])
def total_calls_post():
logger.info("PUT /stats/calls/add - Incrementing call count")
total_calls_today = (db.session
.query(Stats_Company)
.filter(Stats_Company.expected_delivery_date == date.today())
@@ -38,17 +42,18 @@ def total_calls_post():
db.session.add(total_calls_today)
db.session.commit()
return jsonify({"ok": True,}), 200
@stats.route("/calls/count/today", methods=["GET"])
def total_calls_today():
logger.info("GET /stats/calls/count/today - Getting today's call count")
total_calls_today = (db.session
.query(Stats_Company)
.filter(Stats_Company.expected_delivery_date == date.today())
.count())
return jsonify({"ok": True,
'data': total_calls_today,
}), 200
@@ -56,17 +61,18 @@ def total_calls_today():
@stats.route("/gallons/total/<int:driver_id>", methods=["GET"])
def total_gallons_delivered_driver(driver_id):
logger.info(f"GET /stats/gallons/total/{driver_id} - Calculating total gallons for driver")
gallons_list = []
total_gallons = db.session\
.query(Delivery_Delivery)\
.filter(Delivery_Delivery.driver_employee_id == driver_id)\
.all()
for f in total_gallons:
gallons_list.append(f.gallons_delivered)
sum_of_gallons = (sum(gallons_list))
return jsonify({"ok": True,
'data': sum_of_gallons,
}), 200
@@ -74,6 +80,7 @@ def total_gallons_delivered_driver(driver_id):
@stats.route("/delivery/total/<int:driver_id>", methods=["GET"])
def total_deliveries_driver(driver_id):
logger.info(f"GET /stats/delivery/total/{driver_id} - Counting total deliveries for driver")
total_stops = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.driver_employee_id == driver_id)
@@ -85,12 +92,13 @@ def total_deliveries_driver(driver_id):
@stats.route("/primes/total/<int:driver_id>", methods=["GET"])
def total_primes_driver(driver_id):
logger.info(f"GET /stats/primes/total/{driver_id} - Counting prime deliveries for driver")
total_stops = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.driver_employee_id == driver_id)
.filter(Delivery_Delivery.prime == 1)
.count())
return jsonify({"ok": True,
'data': total_stops,
@@ -98,6 +106,7 @@ def total_primes_driver(driver_id):
@stats.route("/delivery/count/today", methods=["GET"])
def total_deliveries_today():
logger.info("GET /stats/delivery/count/today - Counting today's deliveries")
total_stops = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.expected_delivery_date == date.today())
@@ -109,12 +118,13 @@ def total_deliveries_today():
@stats.route("/delivery/count/delivered/today", methods=["GET"])
def total_deliveries_today_finished():
logger.info("GET /stats/delivery/count/delivered/today - Counting completed deliveries today")
total_stops = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.expected_delivery_date == date.today())
.filter((Delivery_Delivery.delivery_status == 10))
.count())
return jsonify({"ok": True,
'data': total_stops,
}), 200
@@ -125,6 +135,7 @@ def get_user_stats(user_id):
"""
gets stats of user
"""
logger.info(f"GET /stats/user/{user_id} - Fetching user statistics")
get_user = db.session \
.query(Stats_Customer) \
.filter(Stats_Customer.customer_id == user_id) \
@@ -157,6 +168,7 @@ def get_user_last_delivery(user_id):
"""
gets users last delivery. used on profile page
"""
logger.info(f"GET /stats/user/lastdelivery/{user_id} - Fetching user's last delivery date")
get_delivery= db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.customer_id == user_id) \
@@ -174,6 +186,7 @@ def get_user_last_delivery(user_id):
@stats.route("/gallons/week", methods=["GET"])
def total_gallons_delivered_this_week():
logger.info("GET /stats/gallons/week - Calculating weekly gallons delivered")
# Get today's date
total_gallons = 0
@@ -194,6 +207,7 @@ def total_gallons_delivered_this_week():
@stats.route("/gallons/check/total/<int:user_id>", methods=["GET"])
def calculate_gallons_user(user_id):
logger.info(f"GET /stats/gallons/check/total/{user_id} - Recalculating user total gallons")
# Get today's date
total_gallons = 0
@@ -215,4 +229,3 @@ def calculate_gallons_user(user_id):
db.session.commit()
return jsonify({"ok": True,
}), 200

View File

@@ -1,14 +1,16 @@
import logging
from flask import jsonify
from app.ticket import ticket
from app import db
from app.classes.delivery import Delivery_Delivery
logger = logging.getLogger(__name__)
@ticket.route("/<int:ticket_id>", methods=["GET"])
def get_ticket_printer_letter(ticket_id):
logger.info(f"GET /ticket/{ticket_id} - Generating ticket printer letter")
return jsonify({"ok": True,
}), 200