major claude changes
This commit is contained in:
@@ -6,6 +6,8 @@ ENV PYTHONUNBUFFERED=1
|
|||||||
|
|
||||||
ENV MODE="DEVELOPMENT"
|
ENV MODE="DEVELOPMENT"
|
||||||
|
|
||||||
|
ENV FLASK_APP=app.py
|
||||||
|
|
||||||
RUN mkdir -p /app
|
RUN mkdir -p /app
|
||||||
|
|
||||||
COPY requirements.txt /app
|
COPY requirements.txt /app
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ ENV TZ=America/New_York
|
|||||||
|
|
||||||
ENV MODE="LOCAL"
|
ENV MODE="LOCAL"
|
||||||
|
|
||||||
|
ENV FLASK_APP=app.py
|
||||||
|
|
||||||
RUN mkdir -p /app
|
RUN mkdir -p /app
|
||||||
|
|
||||||
COPY requirements.txt /app
|
COPY requirements.txt /app
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ COPY . .
|
|||||||
# Tell Docker that the container listens on port 80
|
# Tell Docker that the container listens on port 80
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
# Run the application using Gunicorn
|
# Set Flask app for CLI commands
|
||||||
# This command runs the Flask app. 'app:app' means "in the file named app.py, run the variable named app".
|
ENV FLASK_APP=app.py
|
||||||
# Adjust if your main file or Flask app variable is named differently.
|
|
||||||
CMD ["gunicorn", "--bind", "0.0.0.0:80", "app:app"]
|
# Run database migrations and then the application
|
||||||
|
CMD flask db upgrade && gunicorn --bind 0.0.0.0:80 app:app
|
||||||
|
|||||||
2
app.py
2
app.py
@@ -6,7 +6,7 @@ HOST = '0.0.0.0'
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(
|
app.run(
|
||||||
debug=True,
|
debug=app.config.get('DEBUG', False),
|
||||||
host=HOST,
|
host=HOST,
|
||||||
port=PORT,
|
port=PORT,
|
||||||
use_reloader=True
|
use_reloader=True
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
from flask import Flask, jsonify
|
from flask import Flask, jsonify
|
||||||
from flask_bcrypt import Bcrypt
|
from flask_bcrypt import Bcrypt
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
from flask_marshmallow import Marshmallow
|
from flask_marshmallow import Marshmallow
|
||||||
|
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from flask_migrate import Migrate
|
||||||
from flask_session import Session
|
from flask_session import Session
|
||||||
from flask_login import LoginManager
|
from flask_login import LoginManager
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
@@ -12,9 +15,42 @@ from werkzeug.routing import BaseConverter
|
|||||||
from flask_mail import Mail
|
from flask_mail import Mail
|
||||||
from config import load_config
|
from config import load_config
|
||||||
import re
|
import re
|
||||||
|
from sqlalchemy import text
|
||||||
|
|
||||||
ApplicationConfig = load_config()
|
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__,
|
app = Flask(__name__,
|
||||||
static_url_path='',
|
static_url_path='',
|
||||||
static_folder='static',
|
static_folder='static',
|
||||||
@@ -55,6 +91,7 @@ app.config['SECRET_KEY'] = ApplicationConfig.SECRET_KEY
|
|||||||
|
|
||||||
session.configure(bind=ApplicationConfig.SQLALCHEMY_DATABASE_URI)
|
session.configure(bind=ApplicationConfig.SQLALCHEMY_DATABASE_URI)
|
||||||
db = SQLAlchemy(app)
|
db = SQLAlchemy(app)
|
||||||
|
migrate = Migrate(app, db)
|
||||||
bcrypt = Bcrypt(app)
|
bcrypt = Bcrypt(app)
|
||||||
app.config['SESSION_SQLALCHEMY'] = db
|
app.config['SESSION_SQLALCHEMY'] = db
|
||||||
server_session = Session(app)
|
server_session = Session(app)
|
||||||
@@ -93,14 +130,7 @@ def load_user_from_request(request):
|
|||||||
# If no valid key is found in header or args, return None
|
# If no valid key is found in header or args, return None
|
||||||
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,
|
supports_credentials=True,
|
||||||
resources={r"/*": {"origins": ApplicationConfig.CORS_ALLOWED_ORIGINS}
|
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')
|
app.register_blueprint(service_blueprint, url_prefix='/service')
|
||||||
|
|
||||||
|
|
||||||
with app.app_context():
|
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.configure_mappers()
|
||||||
db.create_all()
|
|
||||||
db.session.commit()
|
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")
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
from flask_login import current_user, logout_user, login_user, login_required
|
from flask_login import current_user, logout_user, login_user, login_required
|
||||||
from app.admin import admin
|
from app.admin import admin
|
||||||
@@ -7,12 +8,17 @@ from app.classes.pricing import (
|
|||||||
Pricing_Oil_Oil,
|
Pricing_Oil_Oil,
|
||||||
Pricing_Oil_Oil_schema)
|
Pricing_Oil_Oil_schema)
|
||||||
from app.classes.admin import Admin_Company, Admin_Company_schema, Call
|
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.route("/oil/create", methods=["POST"])
|
||||||
|
@admin_required
|
||||||
def create_oil_price():
|
def create_oil_price():
|
||||||
"""
|
"""
|
||||||
Changes the price for oil deliveries
|
Changes the price for oil deliveries
|
||||||
"""
|
"""
|
||||||
|
logger.info("POST /admin/oil/create - Creating new oil price")
|
||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
price_from_supplier = request.json["price_from_supplier"]
|
price_from_supplier = request.json["price_from_supplier"]
|
||||||
price_for_customer = request.json["price_for_customer"]
|
price_for_customer = request.json["price_for_customer"]
|
||||||
@@ -50,10 +56,12 @@ def create_oil_price():
|
|||||||
|
|
||||||
|
|
||||||
@admin.route("/oil/get", methods=["GET"])
|
@admin.route("/oil/get", methods=["GET"])
|
||||||
|
@admin_required
|
||||||
def get_oil_price():
|
def get_oil_price():
|
||||||
"""
|
"""
|
||||||
gets oil prices
|
gets oil prices
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /admin/oil/get - Fetching current oil prices")
|
||||||
get_oil_prices = (db.session
|
get_oil_prices = (db.session
|
||||||
.query(Pricing_Oil_Oil)
|
.query(Pricing_Oil_Oil)
|
||||||
.order_by(Pricing_Oil_Oil.date.desc())
|
.order_by(Pricing_Oil_Oil.date.desc())
|
||||||
@@ -63,7 +71,9 @@ def get_oil_price():
|
|||||||
|
|
||||||
|
|
||||||
@admin.route("/company/<int:company_id>", methods=["GET"])
|
@admin.route("/company/<int:company_id>", methods=["GET"])
|
||||||
|
@admin_required
|
||||||
def get_company(company_id):
|
def get_company(company_id):
|
||||||
|
logger.info(f"GET /admin/company/{company_id} - Fetching company data")
|
||||||
get_data_company = (db.session
|
get_data_company = (db.session
|
||||||
.query(Admin_Company)
|
.query(Admin_Company)
|
||||||
.first())
|
.first())
|
||||||
@@ -72,11 +82,12 @@ def get_company(company_id):
|
|||||||
return jsonify(company_schema.dump(get_data_company))
|
return jsonify(company_schema.dump(get_data_company))
|
||||||
|
|
||||||
@admin.route("/voip_routing", methods=["GET"])
|
@admin.route("/voip_routing", methods=["GET"])
|
||||||
|
@admin_required
|
||||||
def get_voip_routing():
|
def get_voip_routing():
|
||||||
"""
|
"""
|
||||||
Gets the current VOIP routing (latest Call record's current_phone)
|
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
|
latest_call = (db.session
|
||||||
.query(Call)
|
.query(Call)
|
||||||
.order_by(Call.created_at.desc())
|
.order_by(Call.created_at.desc())
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
from flask_login import current_user, logout_user, login_required
|
from flask_login import current_user, logout_user, login_required
|
||||||
from app.auth import auth
|
from app.auth import auth
|
||||||
@@ -6,8 +7,11 @@ from datetime import datetime
|
|||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from app.classes.auth import Auth_User
|
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
|
import re
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@auth.route("/whoami", methods=["GET"])
|
@auth.route("/whoami", methods=["GET"])
|
||||||
def check_session():
|
def check_session():
|
||||||
"""
|
"""
|
||||||
@@ -25,7 +29,7 @@ def check_session():
|
|||||||
user = db.session.query(Auth_User).filter(Auth_User.api_key == api_key).first()
|
user = db.session.query(Auth_User).filter(Auth_User.api_key == api_key).first()
|
||||||
|
|
||||||
if not user:
|
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
|
return jsonify({"ok": False, "error": "Invalid token"}), 401
|
||||||
|
|
||||||
# Now, build the complete response with both user and employee data.
|
# Now, build the complete response with both user and employee data.
|
||||||
@@ -73,9 +77,11 @@ def logout():
|
|||||||
|
|
||||||
|
|
||||||
@auth.route("/login", methods=["POST"])
|
@auth.route("/login", methods=["POST"])
|
||||||
|
@validate_request(LoginSchema)
|
||||||
def login():
|
def login():
|
||||||
username = request.json["username"]
|
data = request.validated_data
|
||||||
password = request.json["password"]
|
username = data["username"]
|
||||||
|
password = data["password"]
|
||||||
|
|
||||||
user = db.session.query(Auth_User).filter_by(username=username).first()
|
user = db.session.query(Auth_User).filter_by(username=username).first()
|
||||||
|
|
||||||
@@ -103,15 +109,17 @@ def login():
|
|||||||
}), 200
|
}), 200
|
||||||
|
|
||||||
@auth.route("/register", methods=["POST"])
|
@auth.route("/register", methods=["POST"])
|
||||||
|
@validate_request(RegisterSchema)
|
||||||
def register_user():
|
def register_user():
|
||||||
"""
|
"""
|
||||||
Main post function to register a user
|
Main post function to register a user
|
||||||
"""
|
"""
|
||||||
|
data = request.validated_data
|
||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
|
|
||||||
username = request.json["username"]
|
username = data["username"]
|
||||||
email = request.json["email"]
|
email = data["email"]
|
||||||
password = request.json["password"]
|
password = data["password"]
|
||||||
|
|
||||||
part_one_code = uuid4().hex
|
part_one_code = uuid4().hex
|
||||||
part_two_code = uuid4().hex
|
part_two_code = uuid4().hex
|
||||||
@@ -172,6 +180,7 @@ def register_user():
|
|||||||
|
|
||||||
|
|
||||||
@auth.route('/change-password', methods=['POST'])
|
@auth.route('/change-password', methods=['POST'])
|
||||||
|
@validate_request(ChangePasswordSchema)
|
||||||
def change_password():
|
def change_password():
|
||||||
auth_header = request.headers.get('Authorization')
|
auth_header = request.headers.get('Authorization')
|
||||||
if not auth_header:
|
if not auth_header:
|
||||||
@@ -184,8 +193,9 @@ def change_password():
|
|||||||
if not user:
|
if not user:
|
||||||
return jsonify({"error": "Invalid token"}), 401
|
return jsonify({"error": "Invalid token"}), 401
|
||||||
|
|
||||||
new_password = request.json["new_password"]
|
data = request.validated_data
|
||||||
new_password_confirm = request.json["password_confirm"]
|
new_password = data["new_password"]
|
||||||
|
new_password_confirm = data["password_confirm"]
|
||||||
|
|
||||||
if str(new_password) != str(new_password_confirm):
|
if str(new_password) != str(new_password_confirm):
|
||||||
return jsonify({"error": "Error: Incorrect Passwords"}), 200
|
return jsonify({"error": "Error: Incorrect Passwords"}), 200
|
||||||
@@ -214,7 +224,7 @@ def admin_change_password():
|
|||||||
if not user:
|
if not user:
|
||||||
return jsonify({"error": "Invalid token"}), 401
|
return jsonify({"error": "Invalid token"}), 401
|
||||||
|
|
||||||
if user.admin_role != 0:
|
if user.admin_role == 0:
|
||||||
return jsonify({"error": "Admin access required"}), 403
|
return jsonify({"error": "Admin access required"}), 403
|
||||||
|
|
||||||
employee_id = request.json.get("employee_id")
|
employee_id = request.json.get("employee_id")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from flask import abort
|
from flask import abort, jsonify
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
@@ -14,3 +14,12 @@ def login_required(f):
|
|||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
return decorated_function
|
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
46
app/constants.py
Normal 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.
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
|
import logging
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
from flask_login import login_required
|
from flask_login import login_required
|
||||||
from geopy.geocoders import Nominatim
|
from geopy.geocoders import Nominatim
|
||||||
from app.customer import customer
|
from app.customer import customer
|
||||||
from app import db
|
from app import db
|
||||||
|
from app.common.decorators import login_required as common_login_required
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from app.classes.cards import Card_Card
|
from app.classes.cards import Card_Card
|
||||||
from app.classes.customer import \
|
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.admin import Admin_Company
|
||||||
from app.classes.auto import Auto_Delivery,Auto_Delivery_schema
|
from app.classes.auto import Auto_Delivery,Auto_Delivery_schema
|
||||||
from app.classes.stats_customer import Stats_Customer
|
from app.classes.stats_customer import Stats_Customer
|
||||||
|
from app.schemas import CreateCustomerSchema, UpdateCustomerSchema, validate_request
|
||||||
import string
|
import string
|
||||||
import random
|
import random
|
||||||
|
|
||||||
@@ -33,8 +38,9 @@ def generate_random_number_string(length):
|
|||||||
|
|
||||||
|
|
||||||
@customer.route("/all", methods=["GET"])
|
@customer.route("/all", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def all_customers_around():
|
def all_customers_around():
|
||||||
|
logger.info("GET /customer/all - Fetching all customers")
|
||||||
customer_list = db.session \
|
customer_list = db.session \
|
||||||
.query(Customer_Customer) \
|
.query(Customer_Customer) \
|
||||||
.all()
|
.all()
|
||||||
@@ -43,12 +49,12 @@ def all_customers_around():
|
|||||||
|
|
||||||
|
|
||||||
@customer.route("/all/<int:page>", methods=["GET"])
|
@customer.route("/all/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def all_customers(page):
|
def all_customers(page):
|
||||||
"""
|
"""
|
||||||
pagination all customers
|
pagination all customers
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /customer/all/{page} - Fetching customers page {page}")
|
||||||
per_page_amount = 100
|
per_page_amount = 100
|
||||||
if page is None:
|
if page is None:
|
||||||
offset_limit = 0
|
offset_limit = 0
|
||||||
@@ -67,9 +73,11 @@ def all_customers(page):
|
|||||||
|
|
||||||
|
|
||||||
@customer.route("/<int:customer_id>", methods=["GET"])
|
@customer.route("/<int:customer_id>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_a_customer(customer_id):
|
def get_a_customer(customer_id):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /customer/{customer_id} - Fetching customer")
|
||||||
get_customer = (db.session
|
get_customer = (db.session
|
||||||
.query(Customer_Customer)
|
.query(Customer_Customer)
|
||||||
.filter(Customer_Customer.id == customer_id)
|
.filter(Customer_Customer.id == customer_id)
|
||||||
@@ -79,10 +87,12 @@ def get_a_customer(customer_id):
|
|||||||
|
|
||||||
|
|
||||||
@customer.route("/description/<int:customer_id>", methods=["GET"])
|
@customer.route("/description/<int:customer_id>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_a_customer_description(customer_id):
|
def get_a_customer_description(customer_id):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /customer/description/{customer_id} - Fetching customer description")
|
||||||
get_customer_description = (db.session
|
get_customer_description = (db.session
|
||||||
.query(Customer_Description)
|
.query(Customer_Description)
|
||||||
.filter(Customer_Description.customer_id == customer_id)
|
.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"])
|
@customer.route("/tank/<int:customer_id>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_a_customer_tank(customer_id):
|
def get_a_customer_tank(customer_id):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /customer/tank/{customer_id} - Fetching customer tank info")
|
||||||
get_customer_tank = (db.session
|
get_customer_tank = (db.session
|
||||||
.query(Customer_Tank_Inspection)
|
.query(Customer_Tank_Inspection)
|
||||||
.filter(Customer_Tank_Inspection.customer_id == customer_id)
|
.filter(Customer_Tank_Inspection.customer_id == customer_id)
|
||||||
@@ -142,56 +154,50 @@ def get_a_customer_tank(customer_id):
|
|||||||
|
|
||||||
|
|
||||||
@customer.route("/create", methods=["POST"])
|
@customer.route("/create", methods=["POST"])
|
||||||
|
@validate_request(CreateCustomerSchema)
|
||||||
|
@common_login_required
|
||||||
def create_customer():
|
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()
|
now = datetime.utcnow()
|
||||||
get_company = (db.session
|
get_company = (db.session
|
||||||
.query(Admin_Company)
|
.query(Admin_Company)
|
||||||
.filter(Admin_Company.id == 1)
|
.filter(Admin_Company.id == 1)
|
||||||
.first())
|
.first())
|
||||||
|
|
||||||
get_company = (db.session
|
|
||||||
.query(Admin_Company)
|
|
||||||
.filter(Admin_Company.id == 1)
|
|
||||||
.first())
|
|
||||||
|
|
||||||
|
|
||||||
random_string = generate_random_number_string(6)
|
random_string = generate_random_number_string(6)
|
||||||
|
|
||||||
made_account_number = str(get_company.account_prefix) + '-' + str(random_string)
|
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())
|
see_if_exists = (db.session.query(Customer_Customer).filter(Customer_Customer.account_number == made_account_number).first())
|
||||||
|
|
||||||
if see_if_exists is not None:
|
if see_if_exists is not None:
|
||||||
|
|
||||||
random_string = generate_random_number_string(10)
|
random_string = generate_random_number_string(10)
|
||||||
|
|
||||||
made_account_number = str(get_company.account_prefix) + '-' + str(random_string)
|
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())
|
see_if_exists = (db.session.query(Customer_Customer).filter(Customer_Customer.account_number == made_account_number).first())
|
||||||
|
|
||||||
if see_if_exists is not None:
|
if see_if_exists is not None:
|
||||||
|
|
||||||
random_string = generate_random_number_string(10)
|
random_string = generate_random_number_string(10)
|
||||||
|
|
||||||
made_account_number = str(get_company.account_prefix) + '-' + str(random_string)
|
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)
|
int_customer_home_type = int(response_customer_home_type)
|
||||||
response_customer_zip = str(response_customer_zip)
|
|
||||||
response_customer_state = int(response_customer_state)
|
response_customer_state = int(response_customer_state)
|
||||||
|
|
||||||
|
|
||||||
@@ -204,40 +210,7 @@ def create_customer():
|
|||||||
else:
|
else:
|
||||||
the_state = 'MA'
|
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")
|
geolocator = Nominatim(user_agent="auburnoil")
|
||||||
@@ -247,7 +220,7 @@ def create_customer():
|
|||||||
user_lat = location.latitude
|
user_lat = location.latitude
|
||||||
user_long = location.longitude
|
user_long = location.longitude
|
||||||
cor_ad = True
|
cor_ad = True
|
||||||
except:
|
except Exception:
|
||||||
user_lat = None
|
user_lat = None
|
||||||
user_long = None
|
user_long = None
|
||||||
cor_ad = False
|
cor_ad = False
|
||||||
@@ -323,70 +296,95 @@ def create_customer():
|
|||||||
|
|
||||||
@customer.route("/edit/<int:customer_id>", methods=["PUT"])
|
@customer.route("/edit/<int:customer_id>", methods=["PUT"])
|
||||||
@login_required
|
@login_required
|
||||||
|
@validate_request(UpdateCustomerSchema)
|
||||||
def edit_customer(customer_id):
|
def edit_customer(customer_id):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"PUT /customer/edit/{customer_id} - Editing customer")
|
||||||
get_customer = (db.session
|
get_customer = (db.session
|
||||||
.query(Customer_Customer)
|
.query(Customer_Customer)
|
||||||
.filter(Customer_Customer.id == customer_id)
|
.filter(Customer_Customer.id == customer_id)
|
||||||
.first())
|
.first())
|
||||||
|
|
||||||
|
if not get_customer:
|
||||||
|
return jsonify({"error": "Customer not found"}), 404
|
||||||
|
|
||||||
get_customer_description = (db.session
|
get_customer_description = (db.session
|
||||||
.query(Customer_Description)
|
.query(Customer_Description)
|
||||||
.filter(Customer_Description.customer_id == customer_id)
|
.filter(Customer_Description.customer_id == customer_id)
|
||||||
.first())
|
.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:
|
if get_customer_description is not None:
|
||||||
|
if response_customer_description is not None:
|
||||||
get_customer_description.description = response_customer_description
|
get_customer_description.description = response_customer_description
|
||||||
|
if response_customer_fill_location is not None:
|
||||||
get_customer_description.fill_location = response_customer_fill_location
|
get_customer_description.fill_location = response_customer_fill_location
|
||||||
db.session.add(get_customer_description)
|
db.session.add(get_customer_description)
|
||||||
|
|
||||||
if response_customer_state == 0:
|
# 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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
state_code = response_customer_state if response_customer_state is not None else get_customer.customer_state
|
||||||
|
if state_code == 0:
|
||||||
the_state = 'MA'
|
the_state = 'MA'
|
||||||
elif response_customer_state == 1:
|
elif state_code == 1:
|
||||||
the_state = 'RI'
|
the_state = 'RI'
|
||||||
elif response_customer_state == 1:
|
elif state_code == 2:
|
||||||
the_state = 'NH'
|
the_state = 'NH'
|
||||||
else:
|
else:
|
||||||
the_state = 'MA'
|
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")
|
geolocator = Nominatim(user_agent="auburnoil")
|
||||||
address_string = response_customer_address + ' ' + response_customer_town+ ' ' + the_state
|
address_string = address + ' ' + town + ' ' + the_state
|
||||||
try:
|
try:
|
||||||
location = geolocator.geocode(address_string, timeout=10)
|
location = geolocator.geocode(address_string, timeout=10)
|
||||||
get_customer.customer_latitude = location.latitude
|
get_customer.customer_latitude = location.latitude
|
||||||
get_customer.customer_longitude = location.longitude
|
get_customer.customer_longitude = location.longitude
|
||||||
cor_ad = True
|
get_customer.correct_address = True
|
||||||
except:
|
except Exception:
|
||||||
get_customer.customer_latitude = None
|
get_customer.customer_latitude = None
|
||||||
get_customer.customer_longitude = None
|
get_customer.customer_longitude = None
|
||||||
cor_ad = False
|
get_customer.correct_address = False
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
db.session.add(get_customer)
|
db.session.add(get_customer)
|
||||||
@@ -407,6 +405,7 @@ def edit_customer(customer_id):
|
|||||||
def delete_customer(customer_id):
|
def delete_customer(customer_id):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"DELETE /customer/delete/{customer_id} - Deleting customer")
|
||||||
get_customer = (db.session
|
get_customer = (db.session
|
||||||
.query(Customer_Customer)
|
.query(Customer_Customer)
|
||||||
.filter(Customer_Customer.id == customer_id)
|
.filter(Customer_Customer.id == customer_id)
|
||||||
@@ -436,6 +435,7 @@ def delete_customer(customer_id):
|
|||||||
def customer_count():
|
def customer_count():
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /customer/count - Getting customer count")
|
||||||
get_customer = (db.session
|
get_customer = (db.session
|
||||||
.query(Customer_Customer)
|
.query(Customer_Customer)
|
||||||
.count())
|
.count())
|
||||||
@@ -451,6 +451,7 @@ def customer_count():
|
|||||||
def customer_automatic_status(customer_id):
|
def customer_automatic_status(customer_id):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /customer/automatic/status/{customer_id} - Checking auto delivery status")
|
||||||
get_customer = (db.session
|
get_customer = (db.session
|
||||||
.query(Customer_Customer)
|
.query(Customer_Customer)
|
||||||
.filter(Customer_Customer.id == customer_id)
|
.filter(Customer_Customer.id == customer_id)
|
||||||
@@ -475,7 +476,7 @@ def get_all_automatic_deliveries():
|
|||||||
"""
|
"""
|
||||||
Get all automatic deliveries for the table.
|
Get all automatic deliveries for the table.
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /customer/automatic/deliveries - Fetching all auto deliveries")
|
||||||
try:
|
try:
|
||||||
deliveries = Auto_Delivery.query.all()
|
deliveries = Auto_Delivery.query.all()
|
||||||
schema = Auto_Delivery_schema(many=True)
|
schema = Auto_Delivery_schema(many=True)
|
||||||
@@ -491,6 +492,7 @@ def get_all_automatic_deliveries():
|
|||||||
def customer_automatic_assignment(customer_id):
|
def customer_automatic_assignment(customer_id):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /customer/automatic/assign/{customer_id} - Toggling auto delivery assignment")
|
||||||
get_customer = (db.session
|
get_customer = (db.session
|
||||||
.query(Customer_Customer)
|
.query(Customer_Customer)
|
||||||
.filter(Customer_Customer.id == customer_id)
|
.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.
|
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()
|
get_customer = db.session.query(Customer_Customer).filter(Customer_Customer.id == customer_id).one_or_none()
|
||||||
if not get_customer:
|
if not get_customer:
|
||||||
return jsonify({"ok": False, "error": "Customer not found"}), 404
|
return jsonify({"ok": False, "error": "Customer not found"}), 404
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
import logging
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from app.delivery import delivery
|
from app.delivery import delivery
|
||||||
from app import db
|
from app import db
|
||||||
|
from app.common.decorators import login_required as common_login_required
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
from sqlalchemy import or_
|
from sqlalchemy import or_
|
||||||
from app.classes.customer import (Customer_Customer)
|
from app.classes.customer import (Customer_Customer)
|
||||||
from app.classes.delivery import (Delivery_Delivery,
|
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.
|
# This endpoint is fine, but I've added some comments for clarity.
|
||||||
@delivery.route("/updatestatus", methods=["GET"])
|
@delivery.route("/updatestatus", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def move_deliveries():
|
def move_deliveries():
|
||||||
"""
|
"""
|
||||||
Batch updates delivery statuses based on their expected delivery date relative to today.
|
Batch updates delivery statuses based on their expected delivery date relative to today.
|
||||||
@@ -28,6 +33,7 @@ def move_deliveries():
|
|||||||
- Future deliveries -> "Waiting" (0)
|
- Future deliveries -> "Waiting" (0)
|
||||||
- Past-due deliveries -> "Pending" (9)
|
- Past-due deliveries -> "Pending" (9)
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /delivery/updatestatus - Batch updating delivery statuses")
|
||||||
counter = 0
|
counter = 0
|
||||||
today = date.today()
|
today = date.today()
|
||||||
tomorrow = today + timedelta(days=1)
|
tomorrow = today + timedelta(days=1)
|
||||||
@@ -84,10 +90,12 @@ def move_deliveries():
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/<int:delivery_id>", methods=["GET"])
|
@delivery.route("/<int:delivery_id>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_a_delivery(delivery_id):
|
def get_a_delivery(delivery_id):
|
||||||
"""
|
"""
|
||||||
Get a single delivery's details.
|
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()
|
get_delivery = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.id == delivery_id).first()
|
||||||
if not get_delivery:
|
if not get_delivery:
|
||||||
return jsonify({"ok": False, "error": "Delivery not found"}), 404
|
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"])
|
@delivery.route("/past1/<int:customer_id>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_customer_past_delivery1(customer_id):
|
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
|
get_customer_past_delivery = (db.session
|
||||||
.query(Delivery_Delivery)
|
.query(Delivery_Delivery)
|
||||||
.filter(Delivery_Delivery.customer_id == customer_id)
|
.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"])
|
@delivery.route("/past2/<int:customer_id>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_customer_past_delivery2(customer_id):
|
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
|
get_customer_past_delivery = (db.session
|
||||||
.query(Delivery_Delivery)
|
.query(Delivery_Delivery)
|
||||||
.filter(Delivery_Delivery.customer_id == customer_id)
|
.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))
|
return jsonify(delivery_schema.dump(get_customer_past_delivery))
|
||||||
|
|
||||||
@delivery.route("/auto/<int:customer_id>", methods=["GET"])
|
@delivery.route("/auto/<int:customer_id>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_customer_auto_delivery(customer_id):
|
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
|
get_customer_past_delivery = (db.session
|
||||||
.query(Tickets_Auto_Delivery)
|
.query(Tickets_Auto_Delivery)
|
||||||
.filter(Tickets_Auto_Delivery.customer_id == customer_id)
|
.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"])
|
@delivery.route("/order/<int:delivery_id>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_a_specific_delivery(delivery_id):
|
def get_a_specific_delivery(delivery_id):
|
||||||
"""
|
"""
|
||||||
Get a single delivery by its 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"])
|
@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):
|
def update_a_delivery_payment(delivery_id, type_of_payment):
|
||||||
"""
|
"""
|
||||||
This update a delivery for example if user updates to a fill
|
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"])
|
@delivery.route("/all/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_all(page):
|
def get_deliveries_all(page):
|
||||||
"""
|
"""
|
||||||
This will get deliveries not done
|
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"])
|
@delivery.route("/customer/<int:customer_id>/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_from_customer(customer_id, page):
|
def get_deliveries_from_customer(customer_id, page):
|
||||||
"""
|
"""
|
||||||
This will get deliveries not done
|
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"])
|
@delivery.route("/all/order/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_not_delivered(page):
|
def get_deliveries_not_delivered(page):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -250,6 +267,7 @@ def get_deliveries_not_delivered(page):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/waiting/<int:page>", methods=["GET"])
|
@delivery.route("/waiting/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_waiting(page):
|
def get_deliveries_waiting(page):
|
||||||
"""
|
"""
|
||||||
This will get deliveries not done
|
This will get deliveries not done
|
||||||
@@ -278,6 +296,7 @@ def get_deliveries_waiting(page):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/pending/<int:page>", methods=["GET"])
|
@delivery.route("/pending/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_pending(page):
|
def get_deliveries_pending(page):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
@@ -299,6 +318,7 @@ def get_deliveries_pending(page):
|
|||||||
return jsonify(customer_schema.dump(deliveries))
|
return jsonify(customer_schema.dump(deliveries))
|
||||||
|
|
||||||
@delivery.route("/outfordelivery/<int:page>", methods=["GET"])
|
@delivery.route("/outfordelivery/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_outfordelivery(page):
|
def get_deliveries_outfordelivery(page):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
@@ -322,6 +342,7 @@ def get_deliveries_outfordelivery(page):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/tommorrow/<int:page>", methods=["GET"])
|
@delivery.route("/tommorrow/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_tommorrow(page):
|
def get_deliveries_tommorrow(page):
|
||||||
"""
|
"""
|
||||||
This will get deliveries not done
|
This will get deliveries not done
|
||||||
@@ -348,6 +369,7 @@ def get_deliveries_tommorrow(page):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/finalized/<int:page>", methods=["GET"])
|
@delivery.route("/finalized/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_finalized(page):
|
def get_deliveries_finalized(page):
|
||||||
"""
|
"""
|
||||||
This will get deliveries not done
|
This will get deliveries not done
|
||||||
@@ -372,6 +394,7 @@ def get_deliveries_finalized(page):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/cancelled/<int:page>", methods=["GET"])
|
@delivery.route("/cancelled/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_cancelled(page):
|
def get_deliveries_cancelled(page):
|
||||||
"""
|
"""
|
||||||
This will get deliveries not done
|
This will get deliveries not done
|
||||||
@@ -396,6 +419,7 @@ def get_deliveries_cancelled(page):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/partialdelivery/<int:page>", methods=["GET"])
|
@delivery.route("/partialdelivery/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_partial(page):
|
def get_deliveries_partial(page):
|
||||||
"""
|
"""
|
||||||
This will get deliveries not done
|
This will get deliveries not done
|
||||||
@@ -420,6 +444,7 @@ def get_deliveries_partial(page):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/issue/<int:page>", methods=["GET"])
|
@delivery.route("/issue/<int:page>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_issue(page):
|
def get_deliveries_issue(page):
|
||||||
"""
|
"""
|
||||||
This will get deliveries not done
|
This will get deliveries not done
|
||||||
@@ -444,6 +469,7 @@ def get_deliveries_issue(page):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/time/today", methods=["GET"])
|
@delivery.route("/time/today", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def get_deliveries_today():
|
def get_deliveries_today():
|
||||||
"""
|
"""
|
||||||
This will get today's deliveries
|
This will get today's deliveries
|
||||||
@@ -460,10 +486,12 @@ def get_deliveries_today():
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/edit/<int:delivery_id>", methods=["POST"])
|
@delivery.route("/edit/<int:delivery_id>", methods=["POST"])
|
||||||
|
@common_login_required
|
||||||
def edit_a_delivery(delivery_id):
|
def edit_a_delivery(delivery_id):
|
||||||
"""
|
"""
|
||||||
This will edit a delivery using a delivery id.
|
This will edit a delivery using a delivery id.
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"POST /delivery/edit/{delivery_id} - Editing delivery")
|
||||||
data = request.json
|
data = request.json
|
||||||
get_delivery = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.id == delivery_id).first()
|
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"])
|
@delivery.route("/create/<int:user_id>", methods=["POST"])
|
||||||
|
@common_login_required
|
||||||
def create_a_delivery(user_id):
|
def create_a_delivery(user_id):
|
||||||
"""
|
"""
|
||||||
This will create a delivery using a customer 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\
|
get_customer = db.session\
|
||||||
.query(Customer_Customer)\
|
.query(Customer_Customer)\
|
||||||
.filter(Customer_Customer.id == user_id)\
|
.filter(Customer_Customer.id == user_id)\
|
||||||
@@ -600,7 +630,7 @@ def create_a_delivery(user_id):
|
|||||||
promo_id = request.json["promo_id"]
|
promo_id = request.json["promo_id"]
|
||||||
else:
|
else:
|
||||||
promo_id = None
|
promo_id = None
|
||||||
except:
|
except (KeyError, TypeError):
|
||||||
promo_id = None
|
promo_id = None
|
||||||
if promo_id is not None:
|
if promo_id is not None:
|
||||||
get_promo_data = (db.session
|
get_promo_data = (db.session
|
||||||
@@ -651,7 +681,7 @@ def create_a_delivery(user_id):
|
|||||||
card_payment_id = request.json["credit_card_id"]
|
card_payment_id = request.json["credit_card_id"]
|
||||||
else:
|
else:
|
||||||
card_payment_id = None
|
card_payment_id = None
|
||||||
except:
|
except (KeyError, TypeError):
|
||||||
card_payment_id = None
|
card_payment_id = None
|
||||||
|
|
||||||
if card_payment_id is not 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"])
|
@delivery.route("/cancel/<int:delivery_id>", methods=["POST"])
|
||||||
|
@common_login_required
|
||||||
def cancel_a_delivery(delivery_id):
|
def cancel_a_delivery(delivery_id):
|
||||||
"""
|
"""
|
||||||
This will cancel a delivery
|
This will cancel a delivery
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"POST /delivery/cancel/{delivery_id} - Cancelling delivery")
|
||||||
get_delivery = db.session\
|
get_delivery = db.session\
|
||||||
.query(Delivery_Delivery)\
|
.query(Delivery_Delivery)\
|
||||||
.filter(Delivery_Delivery.id == delivery_id)\
|
.filter(Delivery_Delivery.id == delivery_id)\
|
||||||
@@ -794,10 +826,12 @@ def cancel_a_delivery(delivery_id):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/delivered/<int:delivery_id>", methods=["POST"])
|
@delivery.route("/delivered/<int:delivery_id>", methods=["POST"])
|
||||||
|
@common_login_required
|
||||||
def mark_as_delivered(delivery_id):
|
def mark_as_delivered(delivery_id):
|
||||||
"""
|
"""
|
||||||
This will mark the delivery as delivered
|
This will mark the delivery as delivered
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"POST /delivery/delivered/{delivery_id} - Marking delivery as delivered")
|
||||||
# how many gallons delivered
|
# how many gallons delivered
|
||||||
gallons_put_into_tank = request.json["gallons_put_into_tank"]
|
gallons_put_into_tank = request.json["gallons_put_into_tank"]
|
||||||
# was the tank full or not
|
# was the tank full or not
|
||||||
@@ -819,6 +853,7 @@ def mark_as_delivered(delivery_id):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/partial/<int:delivery_id>", methods=["POST"])
|
@delivery.route("/partial/<int:delivery_id>", methods=["POST"])
|
||||||
|
@common_login_required
|
||||||
def partial_delivery(delivery_id):
|
def partial_delivery(delivery_id):
|
||||||
"""
|
"""
|
||||||
This will mark the delivery as delivered
|
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"])
|
@delivery.route("/note/technician/<int:delivery_id>", methods=["PUT"])
|
||||||
|
@common_login_required
|
||||||
def delivery_note_driver(delivery_id):
|
def delivery_note_driver(delivery_id):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -876,10 +912,12 @@ def delivery_note_driver(delivery_id):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/delete/<int:delivery_id>", methods=["DELETE"])
|
@delivery.route("/delete/<int:delivery_id>", methods=["DELETE"])
|
||||||
|
@common_login_required
|
||||||
def delete_call(delivery_id):
|
def delete_call(delivery_id):
|
||||||
"""
|
"""
|
||||||
delete a delivery call
|
delete a delivery call
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"DELETE /delivery/delete/{delivery_id} - Deleting delivery")
|
||||||
get_call_to_delete = (db.session
|
get_call_to_delete = (db.session
|
||||||
.query(Delivery_Delivery)
|
.query(Delivery_Delivery)
|
||||||
.filter(Delivery_Delivery.id == delivery_id)
|
.filter(Delivery_Delivery.id == delivery_id)
|
||||||
@@ -893,6 +931,7 @@ def delete_call(delivery_id):
|
|||||||
|
|
||||||
|
|
||||||
@delivery.route("/total/<int:delivery_id>", methods=["GET"])
|
@delivery.route("/total/<int:delivery_id>", methods=["GET"])
|
||||||
|
@common_login_required
|
||||||
def calculate_total(delivery_id):
|
def calculate_total(delivery_id):
|
||||||
"""
|
"""
|
||||||
This will get deliveries not done
|
This will get deliveries not done
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from decimal import Decimal
|
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.auto import Auto_Delivery
|
||||||
from app.classes.stats_customer import Stats_Customer
|
from app.classes.stats_customer import Stats_Customer
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@delivery_data.route("/finalize/<int:delivery_id>", methods=["PUT"])
|
@delivery_data.route("/finalize/<int:delivery_id>", methods=["PUT"])
|
||||||
def office_finalize_delivery(delivery_id):
|
def office_finalize_delivery(delivery_id):
|
||||||
"""
|
"""
|
||||||
@@ -20,6 +23,7 @@ def office_finalize_delivery(delivery_id):
|
|||||||
"""
|
"""
|
||||||
Finalizes a delivery from office
|
Finalizes a delivery from office
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"PUT /deliverydata/finalize/{delivery_id} - Finalizing delivery from office")
|
||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
get_delivery = db.session \
|
get_delivery = db.session \
|
||||||
.query(Delivery_Delivery) \
|
.query(Delivery_Delivery) \
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
from datetime import date, timedelta
|
from datetime import date, timedelta
|
||||||
from app.delivery_status import deliverystatus
|
from app.delivery_status import deliverystatus
|
||||||
@@ -13,6 +14,8 @@ from app.classes.transactions import Transaction
|
|||||||
from datetime import date, timedelta, datetime
|
from datetime import date, timedelta, datetime
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# --- NEW EFFICIENT ENDPOINT ---
|
# --- NEW EFFICIENT ENDPOINT ---
|
||||||
@deliverystatus.route("/stats/sidebar-counts", methods=["GET"])
|
@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.
|
Efficiently gets all counts needed for the navigation sidebar in a single request.
|
||||||
This combines logic from all the individual /count/* endpoints.
|
This combines logic from all the individual /count/* endpoints.
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /deliverystatus/stats/sidebar-counts - Fetching sidebar counts")
|
||||||
try:
|
try:
|
||||||
eastern = ZoneInfo("America/New_York")
|
eastern = ZoneInfo("America/New_York")
|
||||||
now_local = datetime.now(eastern).replace(tzinfo=None) # naive local time
|
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.
|
Get total gallons by town for tomorrow's deliveries, including grand total.
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /deliverystatus/tomorrow-totals - Fetching tomorrow delivery totals")
|
||||||
try:
|
try:
|
||||||
deliveries = db.session.query(
|
deliveries = db.session.query(
|
||||||
Delivery_Delivery.customer_town,
|
Delivery_Delivery.customer_town,
|
||||||
@@ -101,6 +106,7 @@ def get_today_totals():
|
|||||||
"""
|
"""
|
||||||
Get total gallons by town for today's deliveries, including grand total.
|
Get total gallons by town for today's deliveries, including grand total.
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /deliverystatus/today-totals - Fetching today delivery totals")
|
||||||
try:
|
try:
|
||||||
deliveries = db.session.query(
|
deliveries = db.session.query(
|
||||||
Delivery_Delivery.customer_town,
|
Delivery_Delivery.customer_town,
|
||||||
@@ -129,6 +135,7 @@ def get_waiting_totals():
|
|||||||
"""
|
"""
|
||||||
Get total gallons by town for waiting deliveries, including grand total.
|
Get total gallons by town for waiting deliveries, including grand total.
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /deliverystatus/waiting-totals - Fetching waiting delivery totals")
|
||||||
try:
|
try:
|
||||||
deliveries = db.session.query(
|
deliveries = db.session.query(
|
||||||
Delivery_Delivery.customer_town,
|
Delivery_Delivery.customer_town,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
|
|
||||||
from sqlalchemy import or_
|
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.auth import Auth_User
|
||||||
from app.classes.stats_employee import Stats_Employee_Oil, Stats_Employee_Office
|
from app.classes.stats_employee import Stats_Employee_Oil, Stats_Employee_Office
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@employees.route("/<int:userid>", methods=["GET"])
|
@employees.route("/<int:userid>", methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def get_specific_employee(userid):
|
def get_specific_employee(userid):
|
||||||
|
logger.info(f"GET /employees/{userid} - Fetching employee by user ID")
|
||||||
employee = db.session \
|
employee = db.session \
|
||||||
.query(Employee_Employee) \
|
.query(Employee_Employee) \
|
||||||
.filter(Employee_Employee.user_id == userid) \
|
.filter(Employee_Employee.user_id == userid) \
|
||||||
@@ -31,6 +35,7 @@ def get_specific_employee(userid):
|
|||||||
@employees.route("/byid/<int:employee_id>", methods=["GET"])
|
@employees.route("/byid/<int:employee_id>", methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def get_employee_by_id(employee_id):
|
def get_employee_by_id(employee_id):
|
||||||
|
logger.info(f"GET /employees/byid/{employee_id} - Fetching employee by ID")
|
||||||
employee = db.session \
|
employee = db.session \
|
||||||
.query(Employee_Employee) \
|
.query(Employee_Employee) \
|
||||||
.filter(Employee_Employee.id == employee_id) \
|
.filter(Employee_Employee.id == employee_id) \
|
||||||
@@ -42,6 +47,7 @@ def get_employee_by_id(employee_id):
|
|||||||
@employees.route("/userid/<int:userid>", methods=["GET"])
|
@employees.route("/userid/<int:userid>", methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def get_specific_employee_user_id(userid):
|
def get_specific_employee_user_id(userid):
|
||||||
|
logger.info(f"GET /employees/userid/{userid} - Fetching employee by user ID")
|
||||||
employee = db.session \
|
employee = db.session \
|
||||||
.query(Employee_Employee) \
|
.query(Employee_Employee) \
|
||||||
.filter(Employee_Employee.user_id == userid) \
|
.filter(Employee_Employee.user_id == userid) \
|
||||||
@@ -56,6 +62,7 @@ def all_employees_paginated(page):
|
|||||||
"""
|
"""
|
||||||
pagination all employees
|
pagination all employees
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /employees/all/{page} - Fetching employees page {page}")
|
||||||
per_page_amount = 50
|
per_page_amount = 50
|
||||||
if page is None:
|
if page is None:
|
||||||
offset_limit = 0
|
offset_limit = 0
|
||||||
@@ -75,6 +82,7 @@ def all_employees_paginated(page):
|
|||||||
@employees.route("/all", methods=["GET"])
|
@employees.route("/all", methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def all_employees():
|
def all_employees():
|
||||||
|
logger.info("GET /employees/all - Fetching all employees")
|
||||||
employee_list = db.session \
|
employee_list = db.session \
|
||||||
.query(Employee_Employee) \
|
.query(Employee_Employee) \
|
||||||
.all()
|
.all()
|
||||||
@@ -85,6 +93,7 @@ def all_employees():
|
|||||||
@employees.route("/drivers", methods=["GET"])
|
@employees.route("/drivers", methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def all_employees_drivers():
|
def all_employees_drivers():
|
||||||
|
logger.info("GET /employees/drivers - Fetching all drivers")
|
||||||
employee_list = db.session \
|
employee_list = db.session \
|
||||||
.query(Employee_Employee) \
|
.query(Employee_Employee) \
|
||||||
.filter(or_(Employee_Employee.employee_type == 4,
|
.filter(or_(Employee_Employee.employee_type == 4,
|
||||||
@@ -98,6 +107,7 @@ def all_employees_drivers():
|
|||||||
@employees.route("/techs", methods=["GET"])
|
@employees.route("/techs", methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def all_employees_techs():
|
def all_employees_techs():
|
||||||
|
logger.info("GET /employees/techs - Fetching all technicians")
|
||||||
employee_list = db.session \
|
employee_list = db.session \
|
||||||
.query(Employee_Employee) \
|
.query(Employee_Employee) \
|
||||||
.filter(or_(Employee_Employee.employee_type == 0,
|
.filter(or_(Employee_Employee.employee_type == 0,
|
||||||
@@ -116,6 +126,7 @@ def employee_create():
|
|||||||
"""
|
"""
|
||||||
This will create an employee
|
This will create an employee
|
||||||
"""
|
"""
|
||||||
|
logger.info("POST /employees/create - Creating new employee")
|
||||||
e_last_name = request.json["employee_last_name"]
|
e_last_name = request.json["employee_last_name"]
|
||||||
e_first_name = request.json["employee_first_name"]
|
e_first_name = request.json["employee_first_name"]
|
||||||
e_town = request.json["employee_town"]
|
e_town = request.json["employee_town"]
|
||||||
@@ -180,6 +191,7 @@ def employee_edit(employee_id):
|
|||||||
"""
|
"""
|
||||||
This will update an employee
|
This will update an employee
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"POST /employees/edit/{employee_id} - Editing employee")
|
||||||
e_last_name = request.json["employee_last_name"]
|
e_last_name = request.json["employee_last_name"]
|
||||||
e_first_name = request.json["employee_first_name"]
|
e_first_name = request.json["employee_first_name"]
|
||||||
e_town = request.json["employee_town"]
|
e_town = request.json["employee_town"]
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from app.info import info
|
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.admin import Admin_Company
|
||||||
from app.classes.delivery import Delivery_Delivery
|
from app.classes.delivery import Delivery_Delivery
|
||||||
from app.classes.service import Service_Service
|
from app.classes.service import Service_Service
|
||||||
|
from flask_login import login_required
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@info.route("/price/oil/tiers", methods=["GET"])
|
@info.route("/price/oil/tiers", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_pricing_tiers():
|
def get_pricing_tiers():
|
||||||
|
logger.info("GET /info/price/oil/tiers - Fetching oil pricing tiers")
|
||||||
get_price_query = (db.session
|
get_price_query = (db.session
|
||||||
.query(Pricing_Oil_Oil)
|
.query(Pricing_Oil_Oil)
|
||||||
.order_by(Pricing_Oil_Oil.date.desc())
|
.order_by(Pricing_Oil_Oil.date.desc())
|
||||||
@@ -34,7 +40,9 @@ def get_pricing_tiers():
|
|||||||
return jsonify(pricing_totals)
|
return jsonify(pricing_totals)
|
||||||
|
|
||||||
@info.route("/price/oil", methods=["GET"])
|
@info.route("/price/oil", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_oil_price_today():
|
def get_oil_price_today():
|
||||||
|
logger.info("GET /info/price/oil - Fetching current oil prices")
|
||||||
get_price_query = (db.session
|
get_price_query = (db.session
|
||||||
.query(Pricing_Oil_Oil)
|
.query(Pricing_Oil_Oil)
|
||||||
.order_by(Pricing_Oil_Oil.date.desc())
|
.order_by(Pricing_Oil_Oil.date.desc())
|
||||||
@@ -50,7 +58,9 @@ def get_oil_price_today():
|
|||||||
|
|
||||||
|
|
||||||
@info.route("/price/oil/table", methods=["GET"])
|
@info.route("/price/oil/table", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_pricing():
|
def get_pricing():
|
||||||
|
logger.info("GET /info/price/oil/table - Fetching oil pricing table")
|
||||||
get_price_query = (db.session
|
get_price_query = (db.session
|
||||||
.query(Pricing_Oil_Oil)
|
.query(Pricing_Oil_Oil)
|
||||||
.order_by(Pricing_Oil_Oil.date.desc())
|
.order_by(Pricing_Oil_Oil.date.desc())
|
||||||
@@ -63,7 +73,9 @@ def get_pricing():
|
|||||||
|
|
||||||
|
|
||||||
@info.route("/company", methods=["GET"])
|
@info.route("/company", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_company():
|
def get_company():
|
||||||
|
logger.info("GET /info/company - Fetching company information")
|
||||||
get_data_company = (db.session
|
get_data_company = (db.session
|
||||||
.query(Admin_Company)
|
.query(Admin_Company)
|
||||||
.first())
|
.first())
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
|
import logging
|
||||||
from flask import jsonify, Response, url_for
|
from flask import jsonify, Response, url_for
|
||||||
from app import app
|
from app import app
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@app.route("/favicon.ico")
|
@app.route("/favicon.ico")
|
||||||
def favicon():
|
def favicon():
|
||||||
|
logger.info("GET /favicon.ico - Serving favicon")
|
||||||
return url_for('static', filename='data:,')
|
return url_for('static', filename='data:,')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/robots.txt')
|
@app.route('/robots.txt')
|
||||||
@app.route('/sitemap.xml')
|
@app.route('/sitemap.xml')
|
||||||
def static_from_root():
|
def static_from_root():
|
||||||
|
logger.info("GET /robots.txt or /sitemap.xml - Serving robots/sitemap")
|
||||||
def disallow(string): return 'Disallow: {0}'.format(string)
|
def disallow(string): return 'Disallow: {0}'.format(string)
|
||||||
return Response("User-agent: *\n{0}\n".format("\n".join([
|
return Response("User-agent: *\n{0}\n".format("\n".join([
|
||||||
disallow('/bin/*'),
|
disallow('/bin/*'),
|
||||||
@@ -19,5 +24,5 @@ def static_from_root():
|
|||||||
@app.route('/index', methods=['GET'])
|
@app.route('/index', methods=['GET'])
|
||||||
@app.route('/', methods=['GET'])
|
@app.route('/', methods=['GET'])
|
||||||
def index():
|
def index():
|
||||||
|
logger.info("GET / or /index - API health check")
|
||||||
return jsonify({"success": "Api is online"}), 200
|
return jsonify({"success": "Api is online"}), 200
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
from app.money import money
|
from app.money import money
|
||||||
from app import db
|
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.money import Money_delivery, Money_delivery_schema
|
||||||
from app.classes.delivery import Delivery_Delivery, Delivery_Delivery_schema
|
from app.classes.delivery import Delivery_Delivery, Delivery_Delivery_schema
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def get_monday_date(date_object):
|
def get_monday_date(date_object):
|
||||||
"""Gets the date of the Monday for the given date."""
|
"""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"])
|
@money.route("/profit/week", methods=["GET"])
|
||||||
def total_profit_week():
|
def total_profit_week():
|
||||||
|
logger.info("GET /money/profit/week - Calculating weekly profit")
|
||||||
# Get today's date
|
# Get today's date
|
||||||
total_profit = 0
|
total_profit = 0
|
||||||
total_deliveries = 0
|
total_deliveries = 0
|
||||||
@@ -52,6 +56,7 @@ def total_profit_week():
|
|||||||
|
|
||||||
@money.route("/profit/year", methods=["GET"])
|
@money.route("/profit/year", methods=["GET"])
|
||||||
def total_profit_year():
|
def total_profit_year():
|
||||||
|
logger.info("GET /money/profit/year - Calculating yearly profit")
|
||||||
# Get today's date
|
# Get today's date
|
||||||
total_profit = 0
|
total_profit = 0
|
||||||
|
|
||||||
@@ -74,6 +79,7 @@ def total_profit_year():
|
|||||||
def get_money_delivery(delivery_id):
|
def get_money_delivery(delivery_id):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /money/{delivery_id} - Fetching delivery profit data")
|
||||||
profit = (db.session
|
profit = (db.session
|
||||||
.query(Money_delivery)
|
.query(Money_delivery)
|
||||||
.filter(Money_delivery.delivery_id == delivery_id)
|
.filter(Money_delivery.delivery_id == delivery_id)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import jsonify, request
|
from flask import jsonify, request
|
||||||
from app.payment import payment
|
from app.payment import payment
|
||||||
from app import db
|
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.transactions import Transaction
|
||||||
from app.classes.delivery import Delivery_Delivery
|
from app.classes.delivery import Delivery_Delivery
|
||||||
from app.classes.service import Service_Service, Service_Service_schema
|
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"])
|
@payment.route("/cards/<int:user_id>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_user_cards(user_id):
|
def get_user_cards(user_id):
|
||||||
"""
|
"""
|
||||||
gets all cards of a user
|
gets all cards of a user
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /payment/cards/{user_id} - Fetching user cards")
|
||||||
get_u_cards = (db.session
|
get_u_cards = (db.session
|
||||||
.query(Card_Card)
|
.query(Card_Card)
|
||||||
.filter(Card_Card.user_id == user_id)
|
.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"])
|
@payment.route("/cards/onfile/<int:user_id>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_user_cards_count(user_id):
|
def get_user_cards_count(user_id):
|
||||||
"""
|
"""
|
||||||
gets all cards of a user
|
gets all cards of a user
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /payment/cards/onfile/{user_id} - Getting card count")
|
||||||
get_u_cards = (db.session
|
get_u_cards = (db.session
|
||||||
.query(Card_Card)
|
.query(Card_Card)
|
||||||
.filter(Card_Card.user_id == user_id)
|
.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"])
|
@payment.route("/card/<int:card_id>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_user_specific_card(card_id):
|
def get_user_specific_card(card_id):
|
||||||
"""
|
"""
|
||||||
gets a specific card of a user
|
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"])
|
@payment.route("/card/main/<int:card_id>/<int:user_id>", methods=["PUT"])
|
||||||
|
@login_required
|
||||||
def set_main_card(user_id, card_id):
|
def set_main_card(user_id, card_id):
|
||||||
"""
|
"""
|
||||||
updates a card of a user
|
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"])
|
@payment.route("/card/remove/<int:card_id>", methods=["DELETE"])
|
||||||
|
@login_required
|
||||||
def remove_user_card(card_id):
|
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
|
get_card = (db.session
|
||||||
.query(Card_Card)
|
.query(Card_Card)
|
||||||
.filter(Card_Card.id == card_id)
|
.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) ...
|
# ... (your existing imports: jsonify, request, db, Customer_Customer, Card_Card) ...
|
||||||
|
|
||||||
@payment.route("/card/create/<int:user_id>", methods=["POST"])
|
@payment.route("/card/create/<int:user_id>", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def create_user_card(user_id):
|
def create_user_card(user_id):
|
||||||
"""
|
"""
|
||||||
Adds a card for a user to the local database. This is its only job.
|
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)
|
set_card_main(user_id=get_customer.id, card_id=create_new_card.id)
|
||||||
|
|
||||||
db.session.commit()
|
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:
|
except Exception as e:
|
||||||
db.session.rollback()
|
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 jsonify({"ok": False, "error": "Failed to save card information."}), 500
|
||||||
|
|
||||||
# Return a success response with the card_id
|
# Return a success response with the card_id
|
||||||
return jsonify({"ok": True, "card_id": create_new_card.id}), 200
|
return jsonify({"ok": True, "card_id": create_new_card.id}), 200
|
||||||
|
|
||||||
@payment.route("/card/update_payment_profile/<int:card_id>", methods=["PUT"])
|
@payment.route("/card/update_payment_profile/<int:card_id>", methods=["PUT"])
|
||||||
|
@login_required
|
||||||
def update_card_payment_profile(card_id):
|
def update_card_payment_profile(card_id):
|
||||||
"""
|
"""
|
||||||
Updates the auth_net_payment_profile_id for a card
|
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"])
|
@payment.route("/card/edit/<int:card_id>", methods=["PUT"])
|
||||||
|
@login_required
|
||||||
def update_user_card(card_id):
|
def update_user_card(card_id):
|
||||||
"""
|
"""
|
||||||
edits a card
|
edits a card
|
||||||
@@ -277,6 +290,7 @@ def update_user_card(card_id):
|
|||||||
|
|
||||||
|
|
||||||
@payment.route("/transactions/authorize/<int:page>", methods=["GET"])
|
@payment.route("/transactions/authorize/<int:page>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_authorize_transactions(page):
|
def get_authorize_transactions(page):
|
||||||
"""
|
"""
|
||||||
Gets transactions with transaction_type = 0 (charge), for the authorize 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"])
|
@payment.route("/authorize/cleanup/<int:customer_id>", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def cleanup_authorize_profile(customer_id):
|
def cleanup_authorize_profile(customer_id):
|
||||||
"""
|
"""
|
||||||
Clean up Authorize.Net profile data in local database when API check fails.
|
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"])
|
@payment.route("/authorize/<int:delivery_id>", methods=["PUT"])
|
||||||
|
@login_required
|
||||||
def update_delivery_payment_authorize(delivery_id):
|
def update_delivery_payment_authorize(delivery_id):
|
||||||
"""
|
"""
|
||||||
Update a delivery's payment_type to 11 (CC - Authorize API) after successful preauthorization
|
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"])
|
@payment.route("/transaction/delivery/<int:delivery_id>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_transaction_by_delivery(delivery_id):
|
def get_transaction_by_delivery(delivery_id):
|
||||||
"""
|
"""
|
||||||
Get a single transaction by delivery_id for Authorize.net payments
|
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"])
|
@payment.route("/transactions/customer/<int:customer_id>/<int:page>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_customer_transactions(customer_id, page):
|
def get_customer_transactions(customer_id, page):
|
||||||
"""
|
"""
|
||||||
Gets transactions for a specific customer
|
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"])
|
@payment.route("/service/payment/<int:service_id>/<int:payment_type>", methods=["PUT"])
|
||||||
|
@login_required
|
||||||
def process_service_payment_tiger(service_id, payment_type):
|
def process_service_payment_tiger(service_id, payment_type):
|
||||||
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
|
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
|
||||||
if not service:
|
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"])
|
@payment.route("/authorize/service/<int:service_id>", methods=["PUT"])
|
||||||
|
@login_required
|
||||||
def update_service_payment_authorize(service_id):
|
def update_service_payment_authorize(service_id):
|
||||||
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
|
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
|
||||||
if not service:
|
if not service:
|
||||||
@@ -487,6 +507,7 @@ def update_service_payment_authorize(service_id):
|
|||||||
|
|
||||||
|
|
||||||
@payment.route("/capture/service/<int:service_id>", methods=["PUT"])
|
@payment.route("/capture/service/<int:service_id>", methods=["PUT"])
|
||||||
|
@login_required
|
||||||
def update_service_payment_capture(service_id):
|
def update_service_payment_capture(service_id):
|
||||||
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
|
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
|
||||||
if not service:
|
if not service:
|
||||||
@@ -511,6 +532,7 @@ def update_service_payment_capture(service_id):
|
|||||||
|
|
||||||
|
|
||||||
@payment.route("/transactions/service/<int:service_id>", methods=["GET"])
|
@payment.route("/transactions/service/<int:service_id>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_service_transactions(service_id):
|
def get_service_transactions(service_id):
|
||||||
"""
|
"""
|
||||||
Gets all transactions for a specific 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
|
return jsonify(transactions_data), 200
|
||||||
|
|
||||||
except Exception as e:
|
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
|
return jsonify({"ok": False, "error": str(e)}), 500
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
import decimal
|
import decimal
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -11,6 +12,8 @@ from app.classes.delivery import (Delivery_Delivery,
|
|||||||
Delivery_Notes_Driver,
|
Delivery_Notes_Driver,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def convert_to_decimal(text):
|
def convert_to_decimal(text):
|
||||||
try:
|
try:
|
||||||
number = float(text)
|
number = float(text)
|
||||||
@@ -23,6 +26,7 @@ def convert_to_decimal(text):
|
|||||||
def get_promo(promo_id):
|
def get_promo(promo_id):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /promo/{promo_id} - Fetching promo")
|
||||||
get_promo_data = (db.session
|
get_promo_data = (db.session
|
||||||
.query(Promo_Promo)
|
.query(Promo_Promo)
|
||||||
.filter(Promo_Promo.id == promo_id)
|
.filter(Promo_Promo.id == promo_id)
|
||||||
@@ -35,6 +39,7 @@ def get_promo(promo_id):
|
|||||||
def get_promo_price(delivery_id):
|
def get_promo_price(delivery_id):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /promo/promoprice/{delivery_id} - Calculating promo price")
|
||||||
get_delivery = (db.session
|
get_delivery = (db.session
|
||||||
.query(Delivery_Delivery)
|
.query(Delivery_Delivery)
|
||||||
.filter(Delivery_Delivery.id == delivery_id)
|
.filter(Delivery_Delivery.id == delivery_id)
|
||||||
@@ -53,6 +58,7 @@ def get_promo_price(delivery_id):
|
|||||||
def get_all_promo():
|
def get_all_promo():
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /promo/all - Fetching all promos")
|
||||||
get_promo_data = (db.session
|
get_promo_data = (db.session
|
||||||
.query(Promo_Promo)
|
.query(Promo_Promo)
|
||||||
.all())
|
.all())
|
||||||
@@ -64,6 +70,7 @@ def get_all_promo():
|
|||||||
def delete_a_promo(promo_id):
|
def delete_a_promo(promo_id):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"DELETE /promo/delete/{promo_id} - Deleting promo")
|
||||||
get_promo_data = (db.session
|
get_promo_data = (db.session
|
||||||
.query(Promo_Promo)
|
.query(Promo_Promo)
|
||||||
.filter(Promo_Promo.id == promo_id)
|
.filter(Promo_Promo.id == promo_id)
|
||||||
@@ -81,6 +88,7 @@ def delete_a_promo(promo_id):
|
|||||||
def create_promo():
|
def create_promo():
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
logger.info("POST /promo/create - Creating new promo")
|
||||||
date_created = datetime.utcnow()
|
date_created = datetime.utcnow()
|
||||||
name_of_promotion = request.json["name_of_promotion"]
|
name_of_promotion = request.json["name_of_promotion"]
|
||||||
money_off_delivery = request.json["money_off_delivery"]
|
money_off_delivery = request.json["money_off_delivery"]
|
||||||
@@ -112,6 +120,7 @@ def edit_promo(promo_id):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"PUT /promo/edit/{promo_id} - Editing promo")
|
||||||
get_promo_data = (db.session
|
get_promo_data = (db.session
|
||||||
.query(Promo_Promo)
|
.query(Promo_Promo)
|
||||||
.filter(Promo_Promo.id == promo_id)
|
.filter(Promo_Promo.id == promo_id)
|
||||||
@@ -144,6 +153,7 @@ def turn_on_promo(promo_id):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"PATCH /promo/on/{promo_id} - Activating promo")
|
||||||
get_promo_data = (db.session
|
get_promo_data = (db.session
|
||||||
.query(Promo_Promo)
|
.query(Promo_Promo)
|
||||||
.filter(Promo_Promo.id == promo_id)
|
.filter(Promo_Promo.id == promo_id)
|
||||||
@@ -165,6 +175,7 @@ def turn_off_promo(promo_id):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"PATCH /promo/off/{promo_id} - Deactivating promo")
|
||||||
get_promo_data = (db.session
|
get_promo_data = (db.session
|
||||||
.query(Promo_Promo)
|
.query(Promo_Promo)
|
||||||
.filter(Promo_Promo.id == promo_id)
|
.filter(Promo_Promo.id == promo_id)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
from app.query import query
|
from app.query import query
|
||||||
from app import db
|
from app import db
|
||||||
@@ -10,12 +11,17 @@ from app.classes.query import (Query_StateList,
|
|||||||
Query_CustomerTypeList_Schema,
|
Query_CustomerTypeList_Schema,
|
||||||
Query_EmployeeTypeList,
|
Query_EmployeeTypeList,
|
||||||
Query_EmployeeTypeList_Schema)
|
Query_EmployeeTypeList_Schema)
|
||||||
|
from flask_login import login_required
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@query.route("/company/<int:company_id>", methods=["GET"])
|
@query.route("/company/<int:company_id>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_company(company_id):
|
def get_company(company_id):
|
||||||
"""
|
"""
|
||||||
This will get the company from env variable
|
This will get the company from env variable
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /query/company/{company_id} - Fetching company data")
|
||||||
|
|
||||||
query_data = (db.session
|
query_data = (db.session
|
||||||
.query(Admin_Company)
|
.query(Admin_Company)
|
||||||
@@ -25,10 +31,12 @@ def get_company(company_id):
|
|||||||
return jsonify(delivery_schema.dump(query_data))
|
return jsonify(delivery_schema.dump(query_data))
|
||||||
|
|
||||||
@query.route("/states", methods=["GET"])
|
@query.route("/states", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_state_list():
|
def get_state_list():
|
||||||
"""
|
"""
|
||||||
This will get states
|
This will get states
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /query/states - Fetching state list")
|
||||||
|
|
||||||
query_data = db.session \
|
query_data = db.session \
|
||||||
.query(Query_StateList) \
|
.query(Query_StateList) \
|
||||||
@@ -39,10 +47,12 @@ def get_state_list():
|
|||||||
|
|
||||||
|
|
||||||
@query.route("/customertype", methods=["GET"])
|
@query.route("/customertype", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_customer_type_list():
|
def get_customer_type_list():
|
||||||
"""
|
"""
|
||||||
This will get types of customers
|
This will get types of customers
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /query/customertype - Fetching customer type list")
|
||||||
|
|
||||||
query_data = db.session \
|
query_data = db.session \
|
||||||
.query(Query_CustomerTypeList) \
|
.query(Query_CustomerTypeList) \
|
||||||
@@ -54,10 +64,12 @@ def get_customer_type_list():
|
|||||||
|
|
||||||
|
|
||||||
@query.route("/employeetype", methods=["GET"])
|
@query.route("/employeetype", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_employee_type_list():
|
def get_employee_type_list():
|
||||||
"""
|
"""
|
||||||
This will get types of service
|
This will get types of service
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /query/employeetype - Fetching employee type list")
|
||||||
|
|
||||||
query_data = db.session \
|
query_data = db.session \
|
||||||
.query(Query_EmployeeTypeList) \
|
.query(Query_EmployeeTypeList) \
|
||||||
@@ -67,16 +79,15 @@ def get_employee_type_list():
|
|||||||
|
|
||||||
|
|
||||||
@query.route("/deliverystatus", methods=["GET"])
|
@query.route("/deliverystatus", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_delivery_status_list():
|
def get_delivery_status_list():
|
||||||
"""
|
"""
|
||||||
This will get delivery status
|
This will get delivery status
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /query/deliverystatus - Fetching delivery status list")
|
||||||
|
|
||||||
query_data = db.session \
|
query_data = db.session \
|
||||||
.query(Query_DeliveryStatusList) \
|
.query(Query_DeliveryStatusList) \
|
||||||
.all()
|
.all()
|
||||||
delivery_schema = Query_DeliveryStatusList_Schema(many=True)
|
delivery_schema = Query_DeliveryStatusList_Schema(many=True)
|
||||||
return jsonify(delivery_schema.dump(query_data))
|
return jsonify(delivery_schema.dump(query_data))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
from app.reports import reports
|
from app.reports import reports
|
||||||
@@ -7,9 +8,12 @@ from app.classes.customer import Customer_Customer
|
|||||||
|
|
||||||
from app.classes.delivery import Delivery_Delivery
|
from app.classes.delivery import Delivery_Delivery
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@reports.route("/oil/total", methods=["GET"])
|
@reports.route("/oil/total", methods=["GET"])
|
||||||
def oil_total_gallons():
|
def oil_total_gallons():
|
||||||
|
logger.info("GET /reports/oil/total - Calculating total oil delivered")
|
||||||
total_oil = db.session\
|
total_oil = db.session\
|
||||||
.query(func.sum(Delivery_Delivery.gallons_delivered))\
|
.query(func.sum(Delivery_Delivery.gallons_delivered))\
|
||||||
.group_by(Delivery_Delivery.id)\
|
.group_by(Delivery_Delivery.id)\
|
||||||
@@ -24,6 +28,7 @@ def customer_list():
|
|||||||
Returns account number, first name, last name, address, town, and phone number.
|
Returns account number, first name, last name, address, town, and phone number.
|
||||||
Ordered by last name from A to Z.
|
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()
|
customers = db.session.query(Customer_Customer).order_by(Customer_Customer.customer_last_name.asc()).all()
|
||||||
customer_data = [
|
customer_data = [
|
||||||
|
|||||||
4
app/schemas/__init__.py
Normal file
4
app/schemas/__init__.py
Normal 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
56
app/schemas/auth.py
Normal 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
126
app/schemas/customer.py
Normal 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
56
app/schemas/utils.py
Normal 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
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
|
|
||||||
from app.search import search
|
from app.search import search
|
||||||
@@ -5,16 +6,27 @@ from app import db
|
|||||||
from sqlalchemy import or_
|
from sqlalchemy import or_
|
||||||
from app.classes.customer import Customer_Customer, Customer_Customer_schema
|
from app.classes.customer import Customer_Customer, Customer_Customer_schema
|
||||||
from app.classes.delivery import Delivery_Delivery, Delivery_Delivery_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"])
|
@search.route("/customer", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def search_customers():
|
def search_customers():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
keyword = request.args.get('q')
|
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_type = (search[1])
|
||||||
search = search.replace("!", "")
|
search = search.replace("!", "")
|
||||||
search = search.replace("#", "")
|
search = search.replace("#", "")
|
||||||
@@ -66,12 +78,14 @@ def search_customers():
|
|||||||
|
|
||||||
|
|
||||||
@search.route("/delivery", methods=["GET"])
|
@search.route("/delivery", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def search_delivery():
|
def search_delivery():
|
||||||
"""
|
"""
|
||||||
pagination all customers
|
pagination all customers
|
||||||
"""
|
"""
|
||||||
keyword = request.args.get('q')
|
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])
|
search_type = (search[1])
|
||||||
|
|
||||||
delivery_ticket = (db.session
|
delivery_ticket = (db.session
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
from app.service import service
|
from app.service import service
|
||||||
from app import db
|
from app import db
|
||||||
@@ -8,9 +9,14 @@ from app.classes.service import (Service_Service,
|
|||||||
Service_Plans, Service_Plans_schema
|
Service_Plans, Service_Plans_schema
|
||||||
)
|
)
|
||||||
from app.classes.auto import Auto_Delivery
|
from app.classes.auto import Auto_Delivery
|
||||||
|
from flask_login import login_required
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@service.route("/all", methods=["GET"])
|
@service.route("/all", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_all_service_calls():
|
def get_all_service_calls():
|
||||||
|
logger.info("GET /service/all - Fetching all service calls for calendar")
|
||||||
try:
|
try:
|
||||||
all_services = Service_Service.query.all()
|
all_services = Service_Service.query.all()
|
||||||
color_map = {
|
color_map = {
|
||||||
@@ -49,18 +55,19 @@ def get_all_service_calls():
|
|||||||
|
|
||||||
return jsonify(calendar_events), 200
|
return jsonify(calendar_events), 200
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Add error logging to see what's happening
|
logger.error(f"Error in /service/all: {e}")
|
||||||
print(f"An error occurred in /service/all: {e}")
|
|
||||||
return jsonify(error=str(e)), 500
|
return jsonify(error=str(e)), 500
|
||||||
|
|
||||||
|
|
||||||
# --- THIS IS THE FIX ---
|
# --- THIS IS THE FIX ---
|
||||||
# The logic from /all has been copied here to ensure a consistent data structure.
|
# The logic from /all has been copied here to ensure a consistent data structure.
|
||||||
@service.route("/upcoming", methods=["GET"])
|
@service.route("/upcoming", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_upcoming_service_calls():
|
def get_upcoming_service_calls():
|
||||||
"""
|
"""
|
||||||
Fetches a list of all future service calls from today onwards.
|
Fetches a list of all future service calls from today onwards.
|
||||||
"""
|
"""
|
||||||
|
logger.info("GET /service/upcoming - Fetching upcoming service calls")
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
upcoming_services = (
|
upcoming_services = (
|
||||||
Service_Service.query
|
Service_Service.query
|
||||||
@@ -78,6 +85,7 @@ def get_upcoming_service_calls():
|
|||||||
|
|
||||||
|
|
||||||
@service.route("/past", methods=["GET"])
|
@service.route("/past", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_past_service_calls():
|
def get_past_service_calls():
|
||||||
"""
|
"""
|
||||||
Fetches a list of all past service calls before today.
|
Fetches a list of all past service calls before today.
|
||||||
@@ -97,6 +105,7 @@ def get_past_service_calls():
|
|||||||
|
|
||||||
|
|
||||||
@service.route("/today", methods=["GET"])
|
@service.route("/today", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_today_service_calls():
|
def get_today_service_calls():
|
||||||
"""
|
"""
|
||||||
Fetches a list of all service calls for today.
|
Fetches a list of all service calls for today.
|
||||||
@@ -119,6 +128,7 @@ def get_today_service_calls():
|
|||||||
|
|
||||||
|
|
||||||
@service.route("/upcoming/count", methods=["GET"])
|
@service.route("/upcoming/count", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_upcoming_service_calls_count():
|
def get_upcoming_service_calls_count():
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
try:
|
try:
|
||||||
@@ -128,6 +138,7 @@ def get_upcoming_service_calls_count():
|
|||||||
return jsonify({"error": str(e)}), 500
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
@service.route("/for-customer/<int:customer_id>", methods=["GET"])
|
@service.route("/for-customer/<int:customer_id>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_service_calls_for_customer(customer_id):
|
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_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)
|
service_schema = Service_Service_schema(many=True)
|
||||||
@@ -135,6 +146,7 @@ def get_service_calls_for_customer(customer_id):
|
|||||||
return jsonify(result), 200
|
return jsonify(result), 200
|
||||||
|
|
||||||
@service.route("/create", methods=["POST"])
|
@service.route("/create", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def create_service_call():
|
def create_service_call():
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
if not data: return jsonify({"error": "No data provided"}), 400
|
if not data: return jsonify({"error": "No data provided"}), 400
|
||||||
@@ -155,6 +167,7 @@ def create_service_call():
|
|||||||
return jsonify({ "ok": True, "id": new_service_call.id }), 201
|
return jsonify({ "ok": True, "id": new_service_call.id }), 201
|
||||||
|
|
||||||
@service.route("/update-cost/<int:id>", methods=["PUT"])
|
@service.route("/update-cost/<int:id>", methods=["PUT"])
|
||||||
|
@login_required
|
||||||
def update_service_cost(id):
|
def update_service_cost(id):
|
||||||
"""
|
"""
|
||||||
Dedicated endpoint to update only the service cost for a service call.
|
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:
|
except Exception as e:
|
||||||
db.session.rollback()
|
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
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
@service.route("/update/<int:id>", methods=["PUT"])
|
@service.route("/update/<int:id>", methods=["PUT"])
|
||||||
|
@login_required
|
||||||
def update_service_call(id):
|
def update_service_call(id):
|
||||||
service_record = Service_Service.query.get_or_404(id)
|
service_record = Service_Service.query.get_or_404(id)
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
@@ -222,6 +236,7 @@ def update_service_call(id):
|
|||||||
|
|
||||||
# Service Plans CRUD endpoints
|
# Service Plans CRUD endpoints
|
||||||
@service.route("/plans/active", methods=["GET"])
|
@service.route("/plans/active", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_active_service_plans():
|
def get_active_service_plans():
|
||||||
"""
|
"""
|
||||||
Get all active service plans (contract_plan > 0)
|
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"])
|
@service.route("/plans/customer/<int:customer_id>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_customer_service_plan(customer_id):
|
def get_customer_service_plan(customer_id):
|
||||||
"""
|
"""
|
||||||
Get service plan for a specific customer
|
Get service plan for a specific customer
|
||||||
@@ -261,6 +277,7 @@ def get_customer_service_plan(customer_id):
|
|||||||
|
|
||||||
|
|
||||||
@service.route("/plans/create", methods=["POST"])
|
@service.route("/plans/create", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def create_service_plan():
|
def create_service_plan():
|
||||||
"""
|
"""
|
||||||
Create a new service plan for a customer
|
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"])
|
@service.route("/plans/update/<int:customer_id>", methods=["PUT"])
|
||||||
|
@login_required
|
||||||
def update_service_plan(customer_id):
|
def update_service_plan(customer_id):
|
||||||
"""
|
"""
|
||||||
Update existing service plan for a customer
|
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"])
|
@service.route("/plans/delete/<int:customer_id>", methods=["DELETE"])
|
||||||
|
@login_required
|
||||||
def delete_service_plan(customer_id):
|
def delete_service_plan(customer_id):
|
||||||
"""
|
"""
|
||||||
Delete service plan for a customer
|
Delete service plan for a customer
|
||||||
@@ -334,12 +353,14 @@ def delete_service_plan(customer_id):
|
|||||||
return jsonify({"error": str(e)}), 500
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
@service.route("/<int:id>", methods=["GET"])
|
@service.route("/<int:id>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_service_by_id(id):
|
def get_service_by_id(id):
|
||||||
service_record = Service_Service.query.get_or_404(id)
|
service_record = Service_Service.query.get_or_404(id)
|
||||||
service_schema = Service_Service_schema()
|
service_schema = Service_Service_schema()
|
||||||
return jsonify({"ok": True, "service": service_schema.dump(service_record)}), 200
|
return jsonify({"ok": True, "service": service_schema.dump(service_record)}), 200
|
||||||
|
|
||||||
@service.route("/delete/<int:id>", methods=["DELETE"])
|
@service.route("/delete/<int:id>", methods=["DELETE"])
|
||||||
|
@login_required
|
||||||
def delete_service_call(id):
|
def delete_service_call(id):
|
||||||
service_record = Service_Service.query.get_or_404(id)
|
service_record = Service_Service.query.get_or_404(id)
|
||||||
try:
|
try:
|
||||||
@@ -351,6 +372,7 @@ def delete_service_call(id):
|
|||||||
return jsonify({"error": str(e)}), 500
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
@service.route("/parts/customer/<int:customer_id>", methods=["GET"])
|
@service.route("/parts/customer/<int:customer_id>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_service_parts(customer_id):
|
def get_service_parts(customer_id):
|
||||||
parts = Service_Parts.query.filter_by(customer_id=customer_id).first()
|
parts = Service_Parts.query.filter_by(customer_id=customer_id).first()
|
||||||
if parts:
|
if parts:
|
||||||
@@ -363,6 +385,7 @@ def get_service_parts(customer_id):
|
|||||||
}), 200
|
}), 200
|
||||||
|
|
||||||
@service.route("/parts/update/<int:customer_id>", methods=["POST"])
|
@service.route("/parts/update/<int:customer_id>", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def update_service_parts(customer_id):
|
def update_service_parts(customer_id):
|
||||||
try:
|
try:
|
||||||
data = request.get_json()
|
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"])
|
@service.route("/payment/<int:service_id>/<int:payment_type>", methods=["PUT"])
|
||||||
|
@login_required
|
||||||
def process_service_payment(service_id, payment_type):
|
def process_service_payment(service_id, payment_type):
|
||||||
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
|
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
|
||||||
if not service:
|
if not service:
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import jsonify, request
|
from flask import jsonify, request
|
||||||
import datetime
|
import datetime
|
||||||
from app.social import social
|
from app.social import social
|
||||||
@@ -5,10 +6,15 @@ 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)
|
Customer_Customer_Social)
|
||||||
|
from flask_login import login_required
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@social.route("/posts/<int:customer_id>/<int:page>", methods=["GET"])
|
@social.route("/posts/<int:customer_id>/<int:page>", methods=["GET"])
|
||||||
|
@login_required
|
||||||
def get_customer_posts(customer_id, page):
|
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
|
per_page_amount = 50
|
||||||
if page is None:
|
if page is None:
|
||||||
offset_limit = 0
|
offset_limit = 0
|
||||||
@@ -28,7 +34,9 @@ def get_customer_posts(customer_id, page):
|
|||||||
|
|
||||||
|
|
||||||
@social.route("/create/<int:customer_id>", methods=["POST"])
|
@social.route("/create/<int:customer_id>", methods=["POST"])
|
||||||
|
@login_required
|
||||||
def create_post(customer_id):
|
def create_post(customer_id):
|
||||||
|
logger.info(f"POST /social/create/{customer_id} - Creating new social post")
|
||||||
|
|
||||||
comment = request.json["comment"]
|
comment = request.json["comment"]
|
||||||
poster_employee_id = request.json["poster_employee_id"]
|
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"])
|
@social.route("/posts/<int:post_id>", methods=["PATCH"])
|
||||||
|
@login_required
|
||||||
def edit_post(post_id):
|
def edit_post(post_id):
|
||||||
|
logger.info(f"PATCH /social/posts/{post_id} - Editing social post")
|
||||||
|
|
||||||
customer_post = (db.session
|
customer_post = (db.session
|
||||||
.query(Customer_Customer_Social)
|
.query(Customer_Customer_Social)
|
||||||
@@ -64,7 +74,9 @@ def edit_post(post_id):
|
|||||||
|
|
||||||
|
|
||||||
@social.route("/delete/<int:post_id>", methods=["DELETE"])
|
@social.route("/delete/<int:post_id>", methods=["DELETE"])
|
||||||
|
@login_required
|
||||||
def delete_post(post_id):
|
def delete_post(post_id):
|
||||||
|
logger.info(f"DELETE /social/delete/{post_id} - Deleting social post")
|
||||||
|
|
||||||
customer_post = (db.session
|
customer_post = (db.session
|
||||||
.query(Customer_Customer_Social)
|
.query(Customer_Customer_Social)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from app.stats import stats
|
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_company import Stats_Company, Stats_Company_schema
|
||||||
from app.classes.stats_customer import Stats_Customer, Stats_Customer_schema
|
from app.classes.stats_customer import Stats_Customer, Stats_Customer_schema
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_monday_date(date_object):
|
def get_monday_date(date_object):
|
||||||
"""Gets the date of the Monday for the given date."""
|
"""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"])
|
@stats.route("/calls/add", methods=["PUT"])
|
||||||
def total_calls_post():
|
def total_calls_post():
|
||||||
|
logger.info("PUT /stats/calls/add - Incrementing call count")
|
||||||
total_calls_today = (db.session
|
total_calls_today = (db.session
|
||||||
.query(Stats_Company)
|
.query(Stats_Company)
|
||||||
.filter(Stats_Company.expected_delivery_date == date.today())
|
.filter(Stats_Company.expected_delivery_date == date.today())
|
||||||
@@ -44,6 +48,7 @@ def total_calls_post():
|
|||||||
|
|
||||||
@stats.route("/calls/count/today", methods=["GET"])
|
@stats.route("/calls/count/today", methods=["GET"])
|
||||||
def total_calls_today():
|
def total_calls_today():
|
||||||
|
logger.info("GET /stats/calls/count/today - Getting today's call count")
|
||||||
total_calls_today = (db.session
|
total_calls_today = (db.session
|
||||||
.query(Stats_Company)
|
.query(Stats_Company)
|
||||||
.filter(Stats_Company.expected_delivery_date == date.today())
|
.filter(Stats_Company.expected_delivery_date == date.today())
|
||||||
@@ -56,6 +61,7 @@ def total_calls_today():
|
|||||||
|
|
||||||
@stats.route("/gallons/total/<int:driver_id>", methods=["GET"])
|
@stats.route("/gallons/total/<int:driver_id>", methods=["GET"])
|
||||||
def total_gallons_delivered_driver(driver_id):
|
def total_gallons_delivered_driver(driver_id):
|
||||||
|
logger.info(f"GET /stats/gallons/total/{driver_id} - Calculating total gallons for driver")
|
||||||
gallons_list = []
|
gallons_list = []
|
||||||
|
|
||||||
total_gallons = db.session\
|
total_gallons = db.session\
|
||||||
@@ -74,6 +80,7 @@ def total_gallons_delivered_driver(driver_id):
|
|||||||
|
|
||||||
@stats.route("/delivery/total/<int:driver_id>", methods=["GET"])
|
@stats.route("/delivery/total/<int:driver_id>", methods=["GET"])
|
||||||
def total_deliveries_driver(driver_id):
|
def total_deliveries_driver(driver_id):
|
||||||
|
logger.info(f"GET /stats/delivery/total/{driver_id} - Counting total deliveries for driver")
|
||||||
total_stops = (db.session
|
total_stops = (db.session
|
||||||
.query(Delivery_Delivery)
|
.query(Delivery_Delivery)
|
||||||
.filter(Delivery_Delivery.driver_employee_id == driver_id)
|
.filter(Delivery_Delivery.driver_employee_id == driver_id)
|
||||||
@@ -85,6 +92,7 @@ def total_deliveries_driver(driver_id):
|
|||||||
|
|
||||||
@stats.route("/primes/total/<int:driver_id>", methods=["GET"])
|
@stats.route("/primes/total/<int:driver_id>", methods=["GET"])
|
||||||
def total_primes_driver(driver_id):
|
def total_primes_driver(driver_id):
|
||||||
|
logger.info(f"GET /stats/primes/total/{driver_id} - Counting prime deliveries for driver")
|
||||||
total_stops = (db.session
|
total_stops = (db.session
|
||||||
.query(Delivery_Delivery)
|
.query(Delivery_Delivery)
|
||||||
.filter(Delivery_Delivery.driver_employee_id == driver_id)
|
.filter(Delivery_Delivery.driver_employee_id == driver_id)
|
||||||
@@ -98,6 +106,7 @@ def total_primes_driver(driver_id):
|
|||||||
|
|
||||||
@stats.route("/delivery/count/today", methods=["GET"])
|
@stats.route("/delivery/count/today", methods=["GET"])
|
||||||
def total_deliveries_today():
|
def total_deliveries_today():
|
||||||
|
logger.info("GET /stats/delivery/count/today - Counting today's deliveries")
|
||||||
total_stops = (db.session
|
total_stops = (db.session
|
||||||
.query(Delivery_Delivery)
|
.query(Delivery_Delivery)
|
||||||
.filter(Delivery_Delivery.expected_delivery_date == date.today())
|
.filter(Delivery_Delivery.expected_delivery_date == date.today())
|
||||||
@@ -109,6 +118,7 @@ def total_deliveries_today():
|
|||||||
|
|
||||||
@stats.route("/delivery/count/delivered/today", methods=["GET"])
|
@stats.route("/delivery/count/delivered/today", methods=["GET"])
|
||||||
def total_deliveries_today_finished():
|
def total_deliveries_today_finished():
|
||||||
|
logger.info("GET /stats/delivery/count/delivered/today - Counting completed deliveries today")
|
||||||
total_stops = (db.session
|
total_stops = (db.session
|
||||||
.query(Delivery_Delivery)
|
.query(Delivery_Delivery)
|
||||||
.filter(Delivery_Delivery.expected_delivery_date == date.today())
|
.filter(Delivery_Delivery.expected_delivery_date == date.today())
|
||||||
@@ -125,6 +135,7 @@ def get_user_stats(user_id):
|
|||||||
"""
|
"""
|
||||||
gets stats of user
|
gets stats of user
|
||||||
"""
|
"""
|
||||||
|
logger.info(f"GET /stats/user/{user_id} - Fetching user statistics")
|
||||||
get_user = db.session \
|
get_user = db.session \
|
||||||
.query(Stats_Customer) \
|
.query(Stats_Customer) \
|
||||||
.filter(Stats_Customer.customer_id == user_id) \
|
.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
|
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 \
|
get_delivery= db.session \
|
||||||
.query(Delivery_Delivery) \
|
.query(Delivery_Delivery) \
|
||||||
.filter(Delivery_Delivery.customer_id == user_id) \
|
.filter(Delivery_Delivery.customer_id == user_id) \
|
||||||
@@ -174,6 +186,7 @@ def get_user_last_delivery(user_id):
|
|||||||
|
|
||||||
@stats.route("/gallons/week", methods=["GET"])
|
@stats.route("/gallons/week", methods=["GET"])
|
||||||
def total_gallons_delivered_this_week():
|
def total_gallons_delivered_this_week():
|
||||||
|
logger.info("GET /stats/gallons/week - Calculating weekly gallons delivered")
|
||||||
# Get today's date
|
# Get today's date
|
||||||
total_gallons = 0
|
total_gallons = 0
|
||||||
|
|
||||||
@@ -194,6 +207,7 @@ def total_gallons_delivered_this_week():
|
|||||||
|
|
||||||
@stats.route("/gallons/check/total/<int:user_id>", methods=["GET"])
|
@stats.route("/gallons/check/total/<int:user_id>", methods=["GET"])
|
||||||
def calculate_gallons_user(user_id):
|
def calculate_gallons_user(user_id):
|
||||||
|
logger.info(f"GET /stats/gallons/check/total/{user_id} - Recalculating user total gallons")
|
||||||
# Get today's date
|
# Get today's date
|
||||||
total_gallons = 0
|
total_gallons = 0
|
||||||
|
|
||||||
@@ -215,4 +229,3 @@ def calculate_gallons_user(user_id):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
return jsonify({"ok": True,
|
return jsonify({"ok": True,
|
||||||
}), 200
|
}), 200
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
|
import logging
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
from app.ticket import ticket
|
from app.ticket import ticket
|
||||||
from app import db
|
from app import db
|
||||||
from app.classes.delivery import Delivery_Delivery
|
from app.classes.delivery import Delivery_Delivery
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ticket.route("/<int:ticket_id>", methods=["GET"])
|
@ticket.route("/<int:ticket_id>", methods=["GET"])
|
||||||
def get_ticket_printer_letter(ticket_id):
|
def get_ticket_printer_letter(ticket_id):
|
||||||
|
logger.info(f"GET /ticket/{ticket_id} - Generating ticket printer letter")
|
||||||
|
|
||||||
|
|
||||||
return jsonify({"ok": True,
|
return jsonify({"ok": True,
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import os
|
|||||||
def load_config(mode=os.environ.get('MODE')):
|
def load_config(mode=os.environ.get('MODE')):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print(f"mode is {mode}")
|
|
||||||
if mode == 'PRODUCTION':
|
if mode == 'PRODUCTION':
|
||||||
from settings_prod import ApplicationConfig
|
from settings_prod import ApplicationConfig
|
||||||
return ApplicationConfig
|
return ApplicationConfig
|
||||||
|
|||||||
1
migrations/README
Normal file
1
migrations/README
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Single-database configuration for Flask.
|
||||||
50
migrations/alembic.ini
Normal file
50
migrations/alembic.ini
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# A generic, single database configuration.
|
||||||
|
|
||||||
|
[alembic]
|
||||||
|
# template used to generate migration files
|
||||||
|
# file_template = %%(rev)s_%%(slug)s
|
||||||
|
|
||||||
|
# set to 'true' to run the environment during
|
||||||
|
# the 'revision' command, regardless of autogenerate
|
||||||
|
# revision_environment = false
|
||||||
|
|
||||||
|
|
||||||
|
# Logging configuration
|
||||||
|
[loggers]
|
||||||
|
keys = root,sqlalchemy,alembic,flask_migrate
|
||||||
|
|
||||||
|
[handlers]
|
||||||
|
keys = console
|
||||||
|
|
||||||
|
[formatters]
|
||||||
|
keys = generic
|
||||||
|
|
||||||
|
[logger_root]
|
||||||
|
level = WARN
|
||||||
|
handlers = console
|
||||||
|
qualname =
|
||||||
|
|
||||||
|
[logger_sqlalchemy]
|
||||||
|
level = WARN
|
||||||
|
handlers =
|
||||||
|
qualname = sqlalchemy.engine
|
||||||
|
|
||||||
|
[logger_alembic]
|
||||||
|
level = INFO
|
||||||
|
handlers =
|
||||||
|
qualname = alembic
|
||||||
|
|
||||||
|
[logger_flask_migrate]
|
||||||
|
level = INFO
|
||||||
|
handlers =
|
||||||
|
qualname = flask_migrate
|
||||||
|
|
||||||
|
[handler_console]
|
||||||
|
class = StreamHandler
|
||||||
|
args = (sys.stderr,)
|
||||||
|
level = NOTSET
|
||||||
|
formatter = generic
|
||||||
|
|
||||||
|
[formatter_generic]
|
||||||
|
format = %(levelname)-5.5s [%(name)s] %(message)s
|
||||||
|
datefmt = %H:%M:%S
|
||||||
113
migrations/env.py
Normal file
113
migrations/env.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import logging
|
||||||
|
from logging.config import fileConfig
|
||||||
|
|
||||||
|
from flask import current_app
|
||||||
|
|
||||||
|
from alembic import context
|
||||||
|
|
||||||
|
# this is the Alembic Config object, which provides
|
||||||
|
# access to the values within the .ini file in use.
|
||||||
|
config = context.config
|
||||||
|
|
||||||
|
# Interpret the config file for Python logging.
|
||||||
|
# This line sets up loggers basically.
|
||||||
|
fileConfig(config.config_file_name)
|
||||||
|
logger = logging.getLogger('alembic.env')
|
||||||
|
|
||||||
|
|
||||||
|
def get_engine():
|
||||||
|
try:
|
||||||
|
# this works with Flask-SQLAlchemy<3 and Alchemical
|
||||||
|
return current_app.extensions['migrate'].db.get_engine()
|
||||||
|
except (TypeError, AttributeError):
|
||||||
|
# this works with Flask-SQLAlchemy>=3
|
||||||
|
return current_app.extensions['migrate'].db.engine
|
||||||
|
|
||||||
|
|
||||||
|
def get_engine_url():
|
||||||
|
try:
|
||||||
|
return get_engine().url.render_as_string(hide_password=False).replace(
|
||||||
|
'%', '%%')
|
||||||
|
except AttributeError:
|
||||||
|
return str(get_engine().url).replace('%', '%%')
|
||||||
|
|
||||||
|
|
||||||
|
# add your model's MetaData object here
|
||||||
|
# for 'autogenerate' support
|
||||||
|
# from myapp import mymodel
|
||||||
|
# target_metadata = mymodel.Base.metadata
|
||||||
|
config.set_main_option('sqlalchemy.url', get_engine_url())
|
||||||
|
target_db = current_app.extensions['migrate'].db
|
||||||
|
|
||||||
|
# other values from the config, defined by the needs of env.py,
|
||||||
|
# can be acquired:
|
||||||
|
# my_important_option = config.get_main_option("my_important_option")
|
||||||
|
# ... etc.
|
||||||
|
|
||||||
|
|
||||||
|
def get_metadata():
|
||||||
|
if hasattr(target_db, 'metadatas'):
|
||||||
|
return target_db.metadatas[None]
|
||||||
|
return target_db.metadata
|
||||||
|
|
||||||
|
|
||||||
|
def run_migrations_offline():
|
||||||
|
"""Run migrations in 'offline' mode.
|
||||||
|
|
||||||
|
This configures the context with just a URL
|
||||||
|
and not an Engine, though an Engine is acceptable
|
||||||
|
here as well. By skipping the Engine creation
|
||||||
|
we don't even need a DBAPI to be available.
|
||||||
|
|
||||||
|
Calls to context.execute() here emit the given string to the
|
||||||
|
script output.
|
||||||
|
|
||||||
|
"""
|
||||||
|
url = config.get_main_option("sqlalchemy.url")
|
||||||
|
context.configure(
|
||||||
|
url=url, target_metadata=get_metadata(), literal_binds=True
|
||||||
|
)
|
||||||
|
|
||||||
|
with context.begin_transaction():
|
||||||
|
context.run_migrations()
|
||||||
|
|
||||||
|
|
||||||
|
def run_migrations_online():
|
||||||
|
"""Run migrations in 'online' mode.
|
||||||
|
|
||||||
|
In this scenario we need to create an Engine
|
||||||
|
and associate a connection with the context.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# this callback is used to prevent an auto-migration from being generated
|
||||||
|
# when there are no changes to the schema
|
||||||
|
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
|
||||||
|
def process_revision_directives(context, revision, directives):
|
||||||
|
if getattr(config.cmd_opts, 'autogenerate', False):
|
||||||
|
script = directives[0]
|
||||||
|
if script.upgrade_ops.is_empty():
|
||||||
|
directives[:] = []
|
||||||
|
logger.info('No changes in schema detected.')
|
||||||
|
|
||||||
|
conf_args = current_app.extensions['migrate'].configure_args
|
||||||
|
if conf_args.get("process_revision_directives") is None:
|
||||||
|
conf_args["process_revision_directives"] = process_revision_directives
|
||||||
|
|
||||||
|
connectable = get_engine()
|
||||||
|
|
||||||
|
with connectable.connect() as connection:
|
||||||
|
context.configure(
|
||||||
|
connection=connection,
|
||||||
|
target_metadata=get_metadata(),
|
||||||
|
**conf_args
|
||||||
|
)
|
||||||
|
|
||||||
|
with context.begin_transaction():
|
||||||
|
context.run_migrations()
|
||||||
|
|
||||||
|
|
||||||
|
if context.is_offline_mode():
|
||||||
|
run_migrations_offline()
|
||||||
|
else:
|
||||||
|
run_migrations_online()
|
||||||
24
migrations/script.py.mako
Normal file
24
migrations/script.py.mako
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
"""${message}
|
||||||
|
|
||||||
|
Revision ID: ${up_revision}
|
||||||
|
Revises: ${down_revision | comma,n}
|
||||||
|
Create Date: ${create_date}
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
${imports if imports else ""}
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = ${repr(up_revision)}
|
||||||
|
down_revision = ${repr(down_revision)}
|
||||||
|
branch_labels = ${repr(branch_labels)}
|
||||||
|
depends_on = ${repr(depends_on)}
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
${upgrades if upgrades else "pass"}
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
${downgrades if downgrades else "pass"}
|
||||||
185
migrations/versions/b43a39b1cf25_initial_baseline.py
Normal file
185
migrations/versions/b43a39b1cf25_initial_baseline.py
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
"""Initial baseline
|
||||||
|
|
||||||
|
Revision ID: b43a39b1cf25
|
||||||
|
Revises:
|
||||||
|
Create Date: 2026-01-21 02:25:55.179218
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'b43a39b1cf25'
|
||||||
|
down_revision = None
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('printer_jobs')
|
||||||
|
op.drop_table('query_town_ist')
|
||||||
|
op.drop_table('taxes_pricing')
|
||||||
|
op.drop_table('pricing_service_general')
|
||||||
|
op.drop_table('portal_user')
|
||||||
|
op.drop_table('delivery_payment')
|
||||||
|
with op.batch_alter_table('street_reference', schema=None) as batch_op:
|
||||||
|
batch_op.drop_index(batch_op.f('ix_public_street_reference_osm_id'))
|
||||||
|
batch_op.drop_index(batch_op.f('ix_public_street_reference_street_name_normalized'))
|
||||||
|
batch_op.drop_index(batch_op.f('ix_street_ref_name_town'))
|
||||||
|
batch_op.drop_index(batch_op.f('ix_street_ref_town_state'))
|
||||||
|
|
||||||
|
op.drop_table('street_reference')
|
||||||
|
with op.batch_alter_table('auth_users', schema=None) as batch_op:
|
||||||
|
batch_op.create_unique_constraint(None, ['id'])
|
||||||
|
|
||||||
|
with op.batch_alter_table('auto_delivery', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('estimated_gallons_left',
|
||||||
|
existing_type=sa.INTEGER(),
|
||||||
|
type_=sa.DECIMAL(precision=6, scale=2),
|
||||||
|
existing_nullable=True)
|
||||||
|
batch_op.alter_column('estimated_gallons_left_prev_day',
|
||||||
|
existing_type=sa.INTEGER(),
|
||||||
|
type_=sa.DECIMAL(precision=6, scale=2),
|
||||||
|
existing_nullable=True)
|
||||||
|
|
||||||
|
with op.batch_alter_table('customer_customer', schema=None) as batch_op:
|
||||||
|
batch_op.create_index(batch_op.f('ix_public_customer_customer_auth_net_profile_id'), ['auth_net_profile_id'], unique=True)
|
||||||
|
batch_op.drop_column('verified_at')
|
||||||
|
|
||||||
|
with op.batch_alter_table('service_service', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('when_ordered',
|
||||||
|
existing_type=sa.DATE(),
|
||||||
|
type_=sa.DATETIME(),
|
||||||
|
existing_nullable=True)
|
||||||
|
batch_op.alter_column('scheduled_date',
|
||||||
|
existing_type=postgresql.DOMAIN('time_stamp', TIMESTAMP()),
|
||||||
|
type_=sa.DATETIME(),
|
||||||
|
existing_nullable=True,
|
||||||
|
existing_server_default=sa.text('CURRENT_TIMESTAMP(2)'))
|
||||||
|
batch_op.alter_column('service_cost',
|
||||||
|
existing_type=sa.NUMERIC(precision=10, scale=2),
|
||||||
|
nullable=False)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('service_service', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('service_cost',
|
||||||
|
existing_type=sa.NUMERIC(precision=10, scale=2),
|
||||||
|
nullable=True)
|
||||||
|
batch_op.alter_column('scheduled_date',
|
||||||
|
existing_type=sa.DATETIME(),
|
||||||
|
type_=postgresql.DOMAIN('time_stamp', TIMESTAMP()),
|
||||||
|
existing_nullable=True,
|
||||||
|
existing_server_default=sa.text('CURRENT_TIMESTAMP(2)'))
|
||||||
|
batch_op.alter_column('when_ordered',
|
||||||
|
existing_type=sa.DATETIME(),
|
||||||
|
type_=sa.DATE(),
|
||||||
|
existing_nullable=True)
|
||||||
|
|
||||||
|
with op.batch_alter_table('customer_customer', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('verified_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=True))
|
||||||
|
batch_op.drop_index(batch_op.f('ix_public_customer_customer_auth_net_profile_id'))
|
||||||
|
|
||||||
|
with op.batch_alter_table('auto_delivery', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('estimated_gallons_left_prev_day',
|
||||||
|
existing_type=sa.DECIMAL(precision=6, scale=2),
|
||||||
|
type_=sa.INTEGER(),
|
||||||
|
existing_nullable=True)
|
||||||
|
batch_op.alter_column('estimated_gallons_left',
|
||||||
|
existing_type=sa.DECIMAL(precision=6, scale=2),
|
||||||
|
type_=sa.INTEGER(),
|
||||||
|
existing_nullable=True)
|
||||||
|
|
||||||
|
with op.batch_alter_table('auth_users', schema=None) as batch_op:
|
||||||
|
batch_op.drop_constraint(None, type_='unique')
|
||||||
|
|
||||||
|
op.create_table('street_reference',
|
||||||
|
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column('street_name', sa.VARCHAR(length=500), autoincrement=False, nullable=False),
|
||||||
|
sa.Column('street_name_normalized', sa.VARCHAR(length=500), autoincrement=False, nullable=False),
|
||||||
|
sa.Column('street_number_low', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('street_number_high', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('town', sa.VARCHAR(length=140), autoincrement=False, nullable=False),
|
||||||
|
sa.Column('town_normalized', sa.VARCHAR(length=140), autoincrement=False, nullable=False),
|
||||||
|
sa.Column('state', sa.VARCHAR(length=2), autoincrement=False, nullable=False),
|
||||||
|
sa.Column('zip_codes', sa.VARCHAR(length=100), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('osm_id', sa.VARCHAR(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('created_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('id', name=op.f('street_reference_pkey'))
|
||||||
|
)
|
||||||
|
with op.batch_alter_table('street_reference', schema=None) as batch_op:
|
||||||
|
batch_op.create_index(batch_op.f('ix_street_ref_town_state'), ['town_normalized', 'state'], unique=False)
|
||||||
|
batch_op.create_index(batch_op.f('ix_street_ref_name_town'), ['street_name_normalized', 'town_normalized'], unique=False)
|
||||||
|
batch_op.create_index(batch_op.f('ix_public_street_reference_street_name_normalized'), ['street_name_normalized'], unique=False)
|
||||||
|
batch_op.create_index(batch_op.f('ix_public_street_reference_osm_id'), ['osm_id'], unique=False)
|
||||||
|
|
||||||
|
op.create_table('delivery_payment',
|
||||||
|
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column('delivery_id', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('time_added', postgresql.TIMESTAMP(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('total_amount_oil', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('total_amount_emergency', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('total_amount_prime', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('total_amount_fee', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('total_amount', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id', name=op.f('delivery_payment_pkey'))
|
||||||
|
)
|
||||||
|
op.create_table('portal_user',
|
||||||
|
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column('username', sa.VARCHAR(length=50), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('account_number', sa.VARCHAR(length=32), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('house_number', sa.VARCHAR(length=32), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('email', sa.VARCHAR(length=350), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('password_hash', sa.TEXT(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('member_since', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('last_seen', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('admin', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('admin_role', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('confirmed', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('active', sa.INTEGER(), server_default=sa.text('1'), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('password_reset_expires', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('password_reset_token', sa.TEXT(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('user_id', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('confirmation_token', sa.TEXT(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('confirmation_sent_at', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('confirmed_at', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id', name=op.f('portal_user_pkey'))
|
||||||
|
)
|
||||||
|
op.create_table('pricing_service_general',
|
||||||
|
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column('price_service_hour', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('price_emergency_service_hour', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('price_emergency_call', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('price_out_of_oil', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('price_prime', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('price_cleaning', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('date', postgresql.TIMESTAMP(), autoincrement=False, nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id', name=op.f('pricing_service_general_pkey'))
|
||||||
|
)
|
||||||
|
op.create_table('taxes_pricing',
|
||||||
|
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column('state_id', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('taxes_oil', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('taxes_other', sa.NUMERIC(precision=50, scale=2), autoincrement=False, nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id', name=op.f('taxes_pricing_pkey'))
|
||||||
|
)
|
||||||
|
op.create_table('query_town_ist',
|
||||||
|
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column('value', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('text', sa.VARCHAR(length=240), autoincrement=False, nullable=True)
|
||||||
|
)
|
||||||
|
op.create_table('printer_jobs',
|
||||||
|
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column('delivery_id', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('date_added', sa.DATE(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('date_completed', sa.DATE(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('employee_id', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.Column('status', sa.INTEGER(), autoincrement=False, nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id', name=op.f('printer_jobs_pkey'))
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
@@ -7,6 +7,7 @@ Flask-Bcrypt==1.0.1
|
|||||||
flask-cors==5.0.1
|
flask-cors==5.0.1
|
||||||
Flask-Login==0.6.3
|
Flask-Login==0.6.3
|
||||||
Flask-Mail==0.10.0
|
Flask-Mail==0.10.0
|
||||||
|
Flask-Migrate==4.0.7
|
||||||
flask-marshmallow==1.3.0
|
flask-marshmallow==1.3.0
|
||||||
Flask-Moment==1.0.6
|
Flask-Moment==1.0.6
|
||||||
Flask-Paranoid==0.3.0
|
Flask-Paranoid==0.3.0
|
||||||
|
|||||||
@@ -1,38 +1,42 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
class ApplicationConfig:
|
class ApplicationConfig:
|
||||||
"""
|
"""
|
||||||
Basic Configuration for a generic User
|
Development Configuration
|
||||||
"""
|
"""
|
||||||
CURRENT_SETTINGS = 'LOCAL'
|
CURRENT_SETTINGS = 'DEVELOPMENT'
|
||||||
# databases info
|
|
||||||
POSTGRES_USERNAME = 'postgres'
|
# Database credentials (defaults for local dev)
|
||||||
POSTGRES_PW = 'password'
|
POSTGRES_USERNAME = os.environ.get('POSTGRES_USERNAME', 'postgres')
|
||||||
POSTGRES_SERVER = '192.168.1.204:5432'
|
POSTGRES_PW = os.environ.get('POSTGRES_PW', 'password')
|
||||||
POSTGRES_DBNAME00 = 'eamco'
|
POSTGRES_SERVER = os.environ.get('POSTGRES_SERVER', '192.168.1.204:5432')
|
||||||
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(POSTGRES_USERNAME,
|
POSTGRES_DBNAME00 = os.environ.get('POSTGRES_DBNAME', 'eamco')
|
||||||
|
|
||||||
|
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(
|
||||||
|
POSTGRES_USERNAME,
|
||||||
POSTGRES_PW,
|
POSTGRES_PW,
|
||||||
POSTGRES_SERVER,
|
POSTGRES_SERVER,
|
||||||
POSTGRES_DBNAME00
|
POSTGRES_DBNAME00
|
||||||
)
|
)
|
||||||
SQLALCHEMY_BINDS = {'eamco': SQLALCHEMY_DATABASE_URI}
|
SQLALCHEMY_BINDS = {'eamco': SQLALCHEMY_DATABASE_URI}
|
||||||
# sqlalchemy config
|
|
||||||
|
# SQLAlchemy config
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
TRAP_HTTP_EXCEPTIONS = True
|
TRAP_HTTP_EXCEPTIONS = True
|
||||||
PROPAGATE_EXCEPTIONS = True
|
PROPAGATE_EXCEPTIONS = True
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
UPLOADED_FILES_DEST_ITEM = '/data/item'
|
UPLOADED_FILES_DEST_ITEM = '/data/item'
|
||||||
|
|
||||||
# file uploads
|
# File uploads
|
||||||
UPLOADED_FILES_ALLOW = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
UPLOADED_FILES_ALLOW = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
||||||
MAX_CONTENT_LENGTH = 5 * 2500 * 2500
|
MAX_CONTENT_LENGTH = 5 * 2500 * 2500
|
||||||
ALLOWED_EXTENSIONS = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
ALLOWED_EXTENSIONS = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
||||||
|
|
||||||
# secret keys
|
# Secret key (default for local dev only)
|
||||||
SECRET_KEY = "youwillneverguessthiskeycia"
|
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-secret-key-not-for-production')
|
||||||
|
|
||||||
# sessions
|
# Sessions
|
||||||
# Available SESSION_TYPE options: 'redis', 'sqlalchemy', 'mongodb', 'filesystem', 'memcached'
|
|
||||||
SESSION_TYPE = "sqlalchemy"
|
SESSION_TYPE = "sqlalchemy"
|
||||||
SESSION_COOKIE_NAME = "eamco_session"
|
SESSION_COOKIE_NAME = "eamco_session"
|
||||||
SESSION_COOKIE_SECURE = False
|
SESSION_COOKIE_SECURE = False
|
||||||
@@ -43,13 +47,8 @@ class ApplicationConfig:
|
|||||||
SESSION_USE_SIGNER = True
|
SESSION_USE_SIGNER = True
|
||||||
|
|
||||||
# CORS
|
# CORS
|
||||||
|
CORS_ALLOWED_ORIGINS = ["*"]
|
||||||
CORS_ALLOWED_ORIGINS = [
|
|
||||||
"*"
|
|
||||||
]
|
|
||||||
CORS_SEND_WILDCARD = False
|
CORS_SEND_WILDCARD = False
|
||||||
CORS_SUPPORT_CREDENTIALS = True
|
CORS_SUPPORT_CREDENTIALS = True
|
||||||
CORS_EXPOSE_HEADERS = None
|
CORS_EXPOSE_HEADERS = None
|
||||||
CORS_ALLOW_HEADERS = "*"
|
CORS_ALLOW_HEADERS = "*"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +1,42 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
class ApplicationConfig:
|
class ApplicationConfig:
|
||||||
"""
|
"""
|
||||||
Basic Configuration for a generic User
|
Local Configuration (LAN deployment)
|
||||||
"""
|
"""
|
||||||
CURRENT_SETTINGS = 'LOCAL'
|
CURRENT_SETTINGS = 'LOCAL'
|
||||||
# databases info
|
|
||||||
POSTGRES_USERNAME = 'postgres'
|
# Database credentials from environment variables
|
||||||
POSTGRES_PW = 'password'
|
POSTGRES_USERNAME = os.environ.get('POSTGRES_USERNAME', 'postgres')
|
||||||
POSTGRES_SERVER = '192.168.1.204:5432'
|
POSTGRES_PW = os.environ.get('POSTGRES_PW')
|
||||||
POSTGRES_DBNAME00 = 'auburnoil'
|
POSTGRES_SERVER = os.environ.get('POSTGRES_SERVER', '192.168.1.204:5432')
|
||||||
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(POSTGRES_USERNAME,
|
POSTGRES_DBNAME00 = os.environ.get('POSTGRES_DBNAME', 'auburnoil')
|
||||||
|
|
||||||
|
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(
|
||||||
|
POSTGRES_USERNAME,
|
||||||
POSTGRES_PW,
|
POSTGRES_PW,
|
||||||
POSTGRES_SERVER,
|
POSTGRES_SERVER,
|
||||||
POSTGRES_DBNAME00
|
POSTGRES_DBNAME00
|
||||||
)
|
)
|
||||||
SQLALCHEMY_BINDS = {'auburnoil': SQLALCHEMY_DATABASE_URI}
|
SQLALCHEMY_BINDS = {'auburnoil': SQLALCHEMY_DATABASE_URI}
|
||||||
# sqlalchemy config
|
|
||||||
|
# SQLAlchemy config
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
TRAP_HTTP_EXCEPTIONS = True
|
TRAP_HTTP_EXCEPTIONS = True
|
||||||
PROPAGATE_EXCEPTIONS = True
|
PROPAGATE_EXCEPTIONS = True
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
UPLOADED_FILES_DEST_ITEM = '/data/item'
|
UPLOADED_FILES_DEST_ITEM = '/data/item'
|
||||||
|
|
||||||
# file uploads
|
# File uploads
|
||||||
UPLOADED_FILES_ALLOW = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
UPLOADED_FILES_ALLOW = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
||||||
MAX_CONTENT_LENGTH = 5 * 2500 * 2500
|
MAX_CONTENT_LENGTH = 5 * 2500 * 2500
|
||||||
ALLOWED_EXTENSIONS = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
ALLOWED_EXTENSIONS = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
||||||
|
|
||||||
# secret keys
|
# Secret key from environment variable
|
||||||
SECRET_KEY = "youwillneverguessthiskeycia"
|
SECRET_KEY = os.environ.get('SECRET_KEY')
|
||||||
|
|
||||||
# sessions
|
# Sessions
|
||||||
# Available SESSION_TYPE options: 'redis', 'sqlalchemy', 'mongodb', 'filesystem', 'memcached'
|
|
||||||
SESSION_TYPE = "sqlalchemy"
|
SESSION_TYPE = "sqlalchemy"
|
||||||
SESSION_COOKIE_NAME = "eamco_session"
|
SESSION_COOKIE_NAME = "eamco_session"
|
||||||
SESSION_COOKIE_SECURE = False
|
SESSION_COOKIE_SECURE = False
|
||||||
@@ -43,7 +47,6 @@ class ApplicationConfig:
|
|||||||
SESSION_USE_SIGNER = True
|
SESSION_USE_SIGNER = True
|
||||||
|
|
||||||
# CORS
|
# CORS
|
||||||
|
|
||||||
CORS_SEND_WILDCARD = False
|
CORS_SEND_WILDCARD = False
|
||||||
CORS_SUPPORT_CREDENTIALS = True
|
CORS_SUPPORT_CREDENTIALS = True
|
||||||
CORS_EXPOSE_HEADERS = None
|
CORS_EXPOSE_HEADERS = None
|
||||||
@@ -54,5 +57,4 @@ class ApplicationConfig:
|
|||||||
'http://192.168.1.204:9612',
|
'http://192.168.1.204:9612',
|
||||||
'http://192.168.1.204:9613',
|
'http://192.168.1.204:9613',
|
||||||
'http://192.168.1.204:9614',
|
'http://192.168.1.204:9614',
|
||||||
|
|
||||||
]
|
]
|
||||||
@@ -1,38 +1,42 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
class ApplicationConfig:
|
class ApplicationConfig:
|
||||||
"""
|
"""
|
||||||
Basic Configuration for a generic User
|
Production Configuration
|
||||||
"""
|
"""
|
||||||
CURRENT_SETTINGS = 'PRODUCTION'
|
CURRENT_SETTINGS = 'PRODUCTION'
|
||||||
# databases info
|
|
||||||
POSTGRES_USERNAME = 'postgres'
|
|
||||||
POSTGRES_PW = 'password'
|
|
||||||
POSTGRES_SERVER = '192.168.1.204:5432'
|
|
||||||
|
|
||||||
POSTGRES_DBNAME00 = 'auburnoil'
|
# Database credentials from environment variables
|
||||||
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(POSTGRES_USERNAME,
|
POSTGRES_USERNAME = os.environ.get('POSTGRES_USERNAME', 'postgres')
|
||||||
|
POSTGRES_PW = os.environ.get('POSTGRES_PW')
|
||||||
|
POSTGRES_SERVER = os.environ.get('POSTGRES_SERVER', '192.168.1.204:5432')
|
||||||
|
POSTGRES_DBNAME00 = os.environ.get('POSTGRES_DBNAME', 'auburnoil')
|
||||||
|
|
||||||
|
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(
|
||||||
|
POSTGRES_USERNAME,
|
||||||
POSTGRES_PW,
|
POSTGRES_PW,
|
||||||
POSTGRES_SERVER,
|
POSTGRES_SERVER,
|
||||||
POSTGRES_DBNAME00
|
POSTGRES_DBNAME00
|
||||||
)
|
)
|
||||||
SQLALCHEMY_BINDS = {'auburnoil': SQLALCHEMY_DATABASE_URI}
|
SQLALCHEMY_BINDS = {'auburnoil': SQLALCHEMY_DATABASE_URI}
|
||||||
# sqlalchemy config
|
|
||||||
|
# SQLAlchemy config
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
TRAP_HTTP_EXCEPTIONS = True
|
TRAP_HTTP_EXCEPTIONS = True
|
||||||
PROPAGATE_EXCEPTIONS = True
|
PROPAGATE_EXCEPTIONS = True
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
UPLOADED_FILES_DEST_ITEM = '/data/item'
|
UPLOADED_FILES_DEST_ITEM = '/data/item'
|
||||||
|
|
||||||
# file uploads
|
# File uploads
|
||||||
UPLOADED_FILES_ALLOW = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
UPLOADED_FILES_ALLOW = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
||||||
MAX_CONTENT_LENGTH = 5 * 2500 * 2500
|
MAX_CONTENT_LENGTH = 5 * 2500 * 2500
|
||||||
ALLOWED_EXTENSIONS = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
ALLOWED_EXTENSIONS = ['png', 'jpeg', 'jpg', 'png', 'gif']
|
||||||
|
|
||||||
# secret keys
|
# Secret key from environment variable
|
||||||
SECRET_KEY = "34dsfkjh43123cxzfvqwer23432dsf233214efdasf2134321"
|
SECRET_KEY = os.environ.get('SECRET_KEY')
|
||||||
|
|
||||||
# sessions
|
# Sessions
|
||||||
SESSION_TYPE = "sqlalchemy"
|
SESSION_TYPE = "sqlalchemy"
|
||||||
SESSION_COOKIE_NAME = "eamco_session"
|
SESSION_COOKIE_NAME = "eamco_session"
|
||||||
SESSION_COOKIE_SECURE = False
|
SESSION_COOKIE_SECURE = False
|
||||||
@@ -43,9 +47,6 @@ class ApplicationConfig:
|
|||||||
SESSION_USE_SIGNER = True
|
SESSION_USE_SIGNER = True
|
||||||
|
|
||||||
# CORS
|
# CORS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CORS_SEND_WILDCARD = False
|
CORS_SEND_WILDCARD = False
|
||||||
CORS_SUPPORT_CREDENTIALS = True
|
CORS_SUPPORT_CREDENTIALS = True
|
||||||
CORS_EXPOSE_HEADERS = None
|
CORS_EXPOSE_HEADERS = None
|
||||||
|
|||||||
Reference in New Issue
Block a user