Compare commits

..

64 Commits

Author SHA1 Message Date
47c3e98dbf fixed bug api 2025-10-21 22:07:46 -04:00
6a1cd0eab5 updated search 2025-10-12 12:11:20 -04:00
701d9a9cc0 added hot water 2025-10-06 21:14:01 -04:00
2cca684908 config issues prod 2025-09-27 14:25:20 -04:00
d8e5d6eedc reverted search 2025-09-27 11:50:44 -04:00
19f5c70735 fixed service calls 2025-09-27 09:44:21 -04:00
10d82cf81a working auto 2025-09-27 00:13:20 -04:00
deaf2f111a working auto 2025-09-26 20:30:30 -04:00
c9464b1605 Added search 2025-09-24 16:39:16 -04:00
1404a0432a Added call 2025-09-24 16:38:47 -04:00
5d96031992 Updated models 2025-09-23 22:38:25 -04:00
2209145e74 Working API CHARGING! 2025-09-20 15:33:36 -04:00
cfbc12da3b added cleanup 2025-09-19 19:08:25 -04:00
fd906a574b Working payment accopunts 2025-09-19 17:27:44 -04:00
628eb8eaa6 small calc change 2025-09-18 19:31:36 -04:00
8c146d24f6 Good progression 2025-09-18 13:02:14 -04:00
908100514f Working flow authorize 2025-09-16 12:45:32 -04:00
8d9ecf6935 Adding authnet not tested 2025-09-15 15:30:16 -04:00
f0544779bb Updated forms and search 2025-09-14 11:59:53 -04:00
382e12671b Updated charge close to working 2025-09-09 18:26:08 -04:00
14abc3c2b4 work 2025-09-07 18:29:54 -04:00
8753e3e103 Working authorize needs work 2025-09-07 17:53:13 -04:00
a280194079 Added service plan. Password change 2025-09-06 12:28:37 -04:00
cd3f4471cc Fixed edit delivery 2025-09-06 09:44:13 -04:00
66f00aa7b5 Updated time 2025-09-05 11:39:49 -04:00
ca6e7ad778 added text data 2025-09-04 11:22:45 -04:00
20f9a4485e Working log in/route guard 2025-09-04 08:05:01 -04:00
d250e136c3 Major Refactor 2025-09-01 16:42:59 -04:00
9a2f9a6564 Added price for service 2025-08-26 17:19:52 -04:00
067c9055d2 Updated auto desc 2025-08-25 18:28:44 -04:00
652947b30a tons fixes 2025-08-25 17:59:00 -04:00
c526284d98 working calender 2025-08-22 14:48:42 -04:00
51f2e986a9 Working time 2025-08-22 12:58:29 -04:00
3e259a530c Added calender 2025-08-21 17:53:25 -04:00
79aa32e8e4 website online working 2025-08-16 21:51:14 -04:00
b97d729ef1 updated page amount 2025-07-28 12:05:14 -04:00
09fafa59d4 Updated packages. Added new session type 2025-05-09 14:53:07 -04:00
86d6d2dadd added auto info to ticket 2025-02-04 18:22:00 -05:00
98a2c94083 bug fixes. added auto table 2024-12-28 15:54:08 -05:00
e6f85ff014 small fixes 2024-12-23 18:10:18 -05:00
86ec25a499 added maps 2024-11-20 18:01:14 -05:00
5e5b9274e1 added pending waiting 2024-10-30 17:04:58 -04:00
b3f0e85574 updated forms 2024-10-24 11:51:14 -04:00
5649294be0 major update 2024-10-17 17:01:24 -04:00
8cee9dc5bf small bug deciding payment status 2024-10-08 08:25:49 -04:00
d0641950f9 dynamic database 2024-10-07 22:58:17 -04:00
d91460fa82 added promo 2024-10-07 17:35:22 -04:00
fec638a5c8 added checks emergency fixed bugs 2024-09-27 14:13:44 -04:00
0e827053de added checks and finalize ticket 2024-09-26 20:01:13 -04:00
c456ef301c added emergency price 2024-09-26 08:48:37 -04:00
d7c809af82 added description 2024-09-18 12:48:12 -04:00
d77c4e2478 Stats working 2024-08-06 11:08:29 -04:00
93fc535eaf small coding fixes 2024-07-29 13:46:07 -04:00
bc1e38c327 Added automatic stuff 2024-07-24 17:24:00 -04:00
ebeecccd63 updated dynamic auto 2024-07-17 18:05:11 -04:00
12d973d785 Updated 2024-07-16 10:29:54 -04:00
9672b804e6 added config file 2024-07-15 18:29:41 -04:00
2a266eea23 Updated auto 2024-07-02 16:56:18 -04:00
ca3ebf9f9b Updated auto 2024-06-25 17:57:53 -04:00
2433dbb447 Updated 2024-05-16 14:36:14 -04:00
2a4804ecb2 Fixed errors 2024-04-04 16:37:57 -04:00
6fab39bf86 working money and delivery dates 2024-03-29 19:56:59 -04:00
666d0895e4 unsure 2024-03-28 10:36:00 -04:00
52172812cb Changes 2024-03-14 14:11:09 -04:00
78 changed files with 3717 additions and 1433 deletions

6
.gitignore vendored
View File

@@ -120,13 +120,11 @@ app/static/bootstrap
/app/static/css/
/app/static/js/
/app/static/javascriptaddons/
.idea
/config.py
instance/config.py
.idea/
/passwords.py
config.py
crons.txt
getnewitems.py
helperfunctions/
test.py

View File

@@ -1,9 +1,11 @@
FROM python:3.12-bullseye
FROM python:3.13.3-bullseye
ENV PYTHONFAULTHANDLER=1
ENV PYTHONUNBUFFERED=1
ENV MODE="DEVELOPMENT"
RUN mkdir -p /app
COPY requirements.txt /app

37
Dockerfile.local Normal file
View File

@@ -0,0 +1,37 @@
FROM python:3.13.3-bullseye
ENV PYTHONFAULTHANDLER=1
ENV PYTHONUNBUFFERED=1
ENV TZ=America/New_York
ENV MODE="LOCAL"
RUN mkdir -p /app
COPY requirements.txt /app
WORKDIR /app
RUN pip3 install -r requirements.txt
RUN pip3 install gunicorn
# Install Nginx
RUN apt-get update && apt-get install -y nginx && rm -rf /var/lib/apt/lists/*
COPY . /app
# Copy Nginx configuration
COPY nginx.conf /etc/nginx/sites-available/default
# Enable the Nginx site
RUN ln -sf /etc/nginx/sites-available/default /etc/nginx/sites-enabled/
# Copy start script
COPY start.sh /app/start.sh
RUN chmod +x /app/start.sh
EXPOSE 80
CMD ["/app/start.sh"]

23
Dockerfile.prod Normal file
View File

@@ -0,0 +1,23 @@
# Use an official Python runtime as a parent image
FROM python:3.11-slim-bullseye
# Set environment variables
ENV PYTHONUNBUFFERED=1
ENV APP_HOME=/app
WORKDIR $APP_HOME
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install gunicorn
# Copy the rest of the application code
COPY . .
# Tell Docker that the container listens on port 80
EXPOSE 80
# Run the application using Gunicorn
# This command runs the Flask app. 'app:app' means "in the file named app.py, run the variable named app".
# Adjust if your main file or Flask app variable is named differently.
CMD ["gunicorn", "--bind", "0.0.0.0:80", "app:app"]

107
app/__init__.py Normal file → Executable file
View File

@@ -10,12 +10,10 @@ from flask_login import LoginManager
from sqlalchemy.orm import sessionmaker
from werkzeug.routing import BaseConverter
from flask_mail import Mail
from config import load_config
import re
try:
from local_settings import ApplicationConfig
except Exception as e:
from settings import ApplicationConfig
ApplicationConfig = load_config()
app = Flask(__name__,
static_url_path='',
@@ -27,8 +25,7 @@ app.config.from_object(ApplicationConfig)
session = sessionmaker()
check_enviroment = ApplicationConfig.CURRENT_SETTINGS
print(f"starting server with {check_enviroment} settings")
class RegexConverter(BaseConverter):
@@ -42,10 +39,8 @@ app.jinja_env.autoescape = True
# configuration
UPLOADED_FILES_DEST_ITEM = ApplicationConfig.UPLOADED_FILES_DEST_ITEM
UPLOADED_FILES_ALLOW = ApplicationConfig.UPLOADED_FILES_ALLOW
CURRENT_SETTINGS = ApplicationConfig.CURRENT_SETTINGS
app.config['CORS_ALLOWED_ORIGINS'] = ApplicationConfig.CORS_ALLOWED_ORIGINS
app.config['UPLOADED_FILES_DEST_ITEM'] = ApplicationConfig.UPLOADED_FILES_DEST_ITEM
app.config['UPLOADED_FILES_ALLOW'] = ApplicationConfig.UPLOADED_FILES_ALLOW
app.config['MAX_CONTENT_LENGTH'] = ApplicationConfig.MAX_CONTENT_LENGTH
@@ -55,13 +50,13 @@ app.config['SESSION_COOKIE_HTTPONLY'] = ApplicationConfig.SESSION_COOKIE_HTTPONL
app.config['SESSION_COOKIE_SAMESITE'] = ApplicationConfig.SESSION_COOKIE_SAMESITE
app.config['SESSION_PERMANENT'] = ApplicationConfig.SESSION_PERMANENT
app.config['SESSION_USE_SIGNER'] = ApplicationConfig.SESSION_USE_SIGNER
app.config['ORIGIN_URL'] = ApplicationConfig.ORIGIN_URL
app.config['CURRENT_SETTINGS'] = ApplicationConfig.CURRENT_SETTINGS
app.config['SECRET_KEY'] = ApplicationConfig.SECRET_KEY
session.configure(bind=ApplicationConfig.SQLALCHEMY_DATABASE_URI)
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
app.config['SESSION_SQLALCHEMY'] = db
server_session = Session(app)
ma = Marshmallow(app)
mail = Mail(app)
@@ -75,39 +70,41 @@ login_manager.anonymous_user = "Guest"
@login_manager.request_loader
def load_user_from_request(request):
from app.classes.auth import Auth_User
# first, try to log in using the api_key url arg
api_key = request.args.get('api_key')
# Check for Authorization header first, as it's the standard
auth_header = request.headers.get('Authorization')
if auth_header:
# --- THIS IS THE FIX ---
# Use a case-insensitive regular expression to strip "bearer "
api_key = re.sub(r'^bearer\s+', '', auth_header, flags=re.IGNORECASE).strip('"')
if api_key:
user = db.session\
.query(Auth_User)\
.filter_by(api_key=api_key)\
.first()
user = db.session.query(Auth_User).filter_by(api_key=api_key).first()
if user:
return user
# next, try to log in using Basic Auth
api_key_auth = request.headers.get('Authorization')
if api_key_auth:
api_key = api_key_auth.replace('bearer ', '', 1)
if api_key.startswith('"') and api_key.endswith('"'):
api_key = api_key[1:-1]
user = db.session\
.query(Auth_User)\
.filter_by(api_key=api_key)\
.first()
# As a fallback, check for api_key in URL args (less secure, but keeps existing logic)
api_key_arg = request.args.get('api_key')
if api_key_arg:
user = db.session.query(Auth_User).filter_by(api_key=api_key_arg).first()
if user:
return user
# If no valid key is found in header or args, return None
return None
api_main = {
"origins": [ApplicationConfig.ORIGIN_URL],
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"],
"allow_headers": ['Authorization', 'application/json', 'authorization', 'Content-Type',
'Access-Control-Allow-Headers', 'Origin,Accept',
'X-Requested-With', 'Content-Type', 'Access-Control-Request-Method',
'Access-Control-Request-Headers']
}
cors = CORS(app, supports_credentials=True, resources={r'/*': api_main})
# 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,
supports_credentials=True,
resources={r"/*": {"origins": ApplicationConfig.CORS_ALLOWED_ORIGINS}
})
# bind a function after each request, even if an exception is encountered.
@@ -122,42 +119,42 @@ def teardown_appcontext(error):
@app.errorhandler(500)
def internal_error500():
def internal_error500(error):
return jsonify({"error": "Internal Error 500"}), 500
@app.errorhandler(502)
def internal_error502():
def internal_error502(error):
return jsonify({"error": "Internal Error 502"}), 502
@app.errorhandler(404)
def internal_error404():
def internal_error404(error):
return jsonify({"error": "Internal Error 400"}), 400
@app.errorhandler(401)
def internal_error404():
def internal_error401(error):
return jsonify({"error": "Internal Error 401"}), 401
@app.errorhandler(400)
def internal_error400():
def internal_error400(error):
return jsonify({"error": "Internal Error 400"}), 400
@app.errorhandler(413)
def to_large_file():
def to_large_file(error):
return jsonify({"error": "File is too large. Use a smaller image/file."}), 413
@app.errorhandler(403)
def internal_error403():
def internal_error403(error):
return jsonify({"error": "Internal Error 403"}), 403
@app.errorhandler(405)
def internal_error():
def internal_error(error):
return jsonify({"error": "Internal Error 405"}), 405
@@ -171,9 +168,6 @@ app.register_blueprint(main_blueprint, url_prefix='/main')
from .customer import customer as customer_blueprint
app.register_blueprint(customer_blueprint, url_prefix='/customer')
from .service import service as service_blueprint
app.register_blueprint(service_blueprint, url_prefix='/service')
from .delivery import delivery as delivery_blueprint
app.register_blueprint(delivery_blueprint, url_prefix='/delivery')
@@ -195,6 +189,9 @@ app.register_blueprint(query_blueprint, url_prefix='/query')
from .payment import payment as payment_blueprint
app.register_blueprint(payment_blueprint, url_prefix='/payment')
from .money import money as money_blueprint
app.register_blueprint(money_blueprint, url_prefix='/money')
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix='/auth')
@@ -207,7 +204,21 @@ app.register_blueprint(info_blueprint, url_prefix='/info')
from .stats import stats as stats_blueprint
app.register_blueprint(stats_blueprint, url_prefix='/stats')
from .ticket import ticket as ticket_blueprint
app.register_blueprint(ticket_blueprint, url_prefix='/ticket')
from .promo import promo as promo_blueprint
app.register_blueprint(promo_blueprint, url_prefix='/promo')
from .social import social as social_blueprint
app.register_blueprint(social_blueprint, url_prefix='/social')
from .service import service as service_blueprint
app.register_blueprint(service_blueprint, url_prefix='/service')
with app.app_context():
db.configure_mappers()
db.create_all()
db.session.commit()

0
app/admin/__init__.py Normal file → Executable file
View File

89
app/admin/views.py Normal file → Executable file
View File

@@ -3,11 +3,10 @@ from flask_login import current_user, logout_user, login_user, login_required
from app.admin import admin
from app import db
from datetime import datetime
from app.classes.pricing import (Pricing_Service_General,
from app.classes.pricing import (
Pricing_Oil_Oil,
Pricing_Service_General_schema,
Pricing_Oil_Oil_schema)
from app.classes.admin import Admin_Company, Admin_Company_schema, Call
@admin.route("/oil/create", methods=["POST"])
def create_oil_price():
@@ -19,14 +18,26 @@ def create_oil_price():
price_for_customer = request.json["price_for_customer"]
price_for_employee = request.json["price_for_employee"]
price_same_day = request.json["price_same_day"]
price_prime = request.json["price_prime"]
price_emergency= request.json["price_emergency"]
new_admin_oil_price = Pricing_Oil_Oil(
price_from_supplier=price_from_supplier,
price_for_customer=price_for_customer,
price_for_employee=price_for_employee,
price_same_day=price_same_day,
price_prime=price_prime,
price_emergency=price_emergency,
date=now,
)
# new_admin_oil_price = Pricing_Oil_Oil(
# price_from_supplier=price_from_supplier,
# price_for_customer=price_for_customer,
# price_for_employee=price_for_employee,
# price_same_day=price_same_day,
# price_prime=price_prime,
# date=now,
# )
db.session.add(new_admin_oil_price)
db.session.commit()
@@ -37,53 +48,6 @@ def create_oil_price():
}), 200
@admin.route("/service/create", methods=["POST"])
def create_service_price():
"""
Changes general labor rates prices
"""
now = datetime.utcnow()
price_service_hour = request.json["price_service_hour"]
price_emergency_service_hourly_rate = request.json["price_emergency_service_hour"]
price_emergency_call = request.json["price_emergency_call"]
price_out_of_oil = request.json["price_out_of_oil"]
price_prime = request.json["price_prime"]
price_cleaning = request.json["price_cleaning"]
price_service = Pricing_Service_General(
price_service_hour=price_service_hour,
price_out_of_oil=price_out_of_oil,
price_emergency_service_hour=price_emergency_service_hourly_rate,
price_prime=price_prime,
price_emergency_call=price_emergency_call,
price_cleaning=price_cleaning,
date=now,
)
db.session.add(price_service)
db.session.commit()
return jsonify({
"ok": True,
'price': price_service.id,
}), 200
@admin.route("/service/get", methods=["GET"])
def get_service_price():
"""
gets service prices
"""
get_service_prices = (db.session
.query(Pricing_Service_General)
.order_by(Pricing_Service_General.date.desc())
.first())
price_schema = Pricing_Service_General_schema(many=False)
return jsonify(price_schema.dump(get_service_prices))
@admin.route("/oil/get", methods=["GET"])
def get_oil_price():
@@ -96,3 +60,28 @@ def get_oil_price():
.first())
price_schema = Pricing_Oil_Oil_schema(many=False)
return jsonify(price_schema.dump(get_oil_prices))
@admin.route("/company/<int:company_id>", methods=["GET"])
def get_company(company_id):
get_data_company = (db.session
.query(Admin_Company)
.first())
company_schema = Admin_Company_schema(many=False)
return jsonify(company_schema.dump(get_data_company))
@admin.route("/voip_routing", methods=["GET"])
def get_voip_routing():
"""
Gets the current VOIP routing (latest Call record's current_phone)
"""
latest_call = (db.session
.query(Call)
.order_by(Call.created_at.desc())
.first())
if latest_call:
return jsonify({"current_phone": latest_call.current_phone})
else:
return jsonify({"current_phone": None}), 404

0
app/auth/__init__.py Normal file → Executable file
View File

133
app/auth/views.py Normal file → Executable file
View File

@@ -1,35 +1,34 @@
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_required
from app.auth import auth
from app import db, bcrypt
from datetime import datetime
from uuid import uuid4
from app.classes.auth import Auth_User
from app.classes.employee import Employee_Employee
import re
@auth.route("/whoami", methods=["GET"])
def check_session():
"""
Checks auth token to ensure user is authenticated
Checks auth token and returns user and associated employee data.
"""
auth_header = request.headers.get('Authorization')
if not auth_header:
return jsonify({"ok": False, "error": "Authorization header missing"}), 401
api_key = request.headers.get('Authorization')
if not api_key:
return jsonify({"error": "True"}), 200
else:
api_key = api_key.replace('bearer ', '', 1)
api_key = api_key.replace('"', '')
user_exists = (db.session
.query(Auth_User)
.filter(Auth_User.api_key == api_key)
.first())
if not user_exists:
return jsonify({"error": True}), 200
else:
user = db.session\
.query(Auth_User)\
.filter(Auth_User.api_key == api_key)\
.first()
# --- THIS IS THE FIX ---
# Use a case-insensitive regular expression to remove "bearer "
# This handles "Bearer ", "bearer ", "BEARER ", etc.
api_key = re.sub(r'^bearer\s+', '', auth_header, flags=re.IGNORECASE).strip('"')
user = db.session.query(Auth_User).filter(Auth_User.api_key == api_key).first()
if not user:
print("no user found with that api key")
return jsonify({"ok": False, "error": "Invalid token"}), 401
# Now, build the complete response with both user and employee data.
return jsonify({
"ok": True,
'user': {
@@ -40,7 +39,6 @@ def check_session():
'token': user.api_key,
'confirmed': user.confirmed
},
'token': user.api_key
}), 200
@@ -76,37 +74,30 @@ def logout():
@auth.route("/login", methods=["POST"])
def login():
"""
Main post function to a user
"""
username = request.json["username"]
password = request.json["password"]
user = db.session\
.query(Auth_User)\
.filter_by(username=username)\
.first() is not None
user = db.session.query(Auth_User).filter_by(username=username).first()
# Important checks!
if not user:
return jsonify({"error": True}), 200
user = db.session\
.query(Auth_User)\
.filter_by(username=username)\
.first()
return jsonify({"error": "User not found"}), 401 # Use a more descriptive error and status code
if not bcrypt.check_password_hash(user.password_hash, password):
return jsonify({"error": True}), 200
db.session.add(user)
db.session.commit()
return jsonify({"error": "Invalid password"}), 401 # Use a more descriptive error and status code
# Check if user is active
if user.active != 1:
return jsonify({"error": "Please contact a manager. Login rejected"}), 401
# If login is successful, return the correct structure
return jsonify({
"ok": True,
'user': {'user_id': user.uuid,
'user': {
'user_name': user.username,
'user_id': user.id,
'user_email': user.email,
'admin_role': user.admin_role,
'token': user.api_key
},
'token': user.api_key
}), 200
@@ -181,17 +172,21 @@ def register_user():
@auth.route('/change-password', methods=['POST'])
@login_required
def change_password():
auth_header = request.headers.get('Authorization')
if not auth_header:
return jsonify({"error": "Authorization header missing"}), 401
api_key = re.sub(r'^bearer\s+', '', auth_header, flags=re.IGNORECASE).strip('"')
user = db.session.query(Auth_User).filter(Auth_User.api_key == api_key).first()
if not user:
return jsonify({"error": "Invalid token"}), 401
new_password = request.json["new_password"]
new_password_confirm = request.json["password_confirm"]
user = db.session\
.query(Auth_User) \
.filter(Auth_User.id == current_user.id) \
.first()
if str(new_password) != str(new_password_confirm):
return jsonify({"error": "Error: Incorrect Passwords"}), 200
@@ -203,5 +198,49 @@ def change_password():
db.session.add(user)
db.session.commit()
return jsonify({"ok": "success"}), 200
return jsonify({"ok": True}), 200
@auth.route('/admin-change-password', methods=['POST'])
def admin_change_password():
auth_header = request.headers.get('Authorization')
if not auth_header:
return jsonify({"error": "Authorization header missing"}), 401
api_key = re.sub(r'^bearer\s+', '', auth_header, flags=re.IGNORECASE).strip('"')
user = db.session.query(Auth_User).filter(Auth_User.api_key == api_key).first()
if not user:
return jsonify({"error": "Invalid token"}), 401
if user.admin_role != 0:
return jsonify({"error": "Admin access required"}), 403
employee_id = request.json.get("employee_id")
new_password = request.json.get("new_password")
new_password_confirm = request.json.get("password_confirm")
if not employee_id or not new_password or not new_password_confirm:
return jsonify({"error": "Missing required fields"}), 400
if str(new_password) != str(new_password_confirm):
return jsonify({"error": "Passwords do not match"}), 400
from app.classes.employee import Employee_Employee
employee = db.session.query(Employee_Employee).filter(Employee_Employee.id == employee_id).first()
if not employee:
return jsonify({"error": "Employee not found"}), 404
target_user = db.session.query(Auth_User).filter(Auth_User.id == employee.user_id).first()
if not target_user:
return jsonify({"error": "User not found"}), 404
hashed_password = bcrypt.generate_password_hash(new_password).decode('utf-8')
target_user.password_hash = hashed_password
target_user.passwordpinallowed = 0
db.session.add(target_user)
db.session.commit()
return jsonify({"ok": True}), 200

0
app/classes/__init__.py Normal file → Executable file
View File

9
app/classes/admin.py Normal file → Executable file
View File

@@ -4,7 +4,6 @@ from datetime import datetime
class Admin_Company(db.Model):
__tablename__ = 'admin_company'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -24,3 +23,11 @@ class Admin_Company_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Admin_Company
# --- ADD THIS ENTIRE NEW MODEL ---
class Call(db.Model):
__tablename__ = "call_call"
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer, primary_key=True, index=True)
current_phone = db.Column(db.String(500))
created_at = db.Column(db.DateTime, default=datetime.utcnow)

4
app/classes/auth.py Normal file → Executable file
View File

@@ -10,7 +10,6 @@ def get_uuid():
class Auth_User(UserMixin, db.Model):
__tablename__ = 'auth_users'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -27,6 +26,7 @@ class Auth_User(UserMixin, db.Model):
admin = db.Column(db.INTEGER)
admin_role = db.Column(db.INTEGER)
confirmed = db.Column(db.INTEGER)
active = db.Column(db.INTEGER, default=1)
def __init__(self,
username,
@@ -38,6 +38,7 @@ class Auth_User(UserMixin, db.Model):
admin,
admin_role,
confirmed,
active=1,
):
self.username = username
self.api_key = api_key
@@ -48,6 +49,7 @@ class Auth_User(UserMixin, db.Model):
self.admin = admin
self.admin_role = admin_role
self.confirmed = confirmed
self.active = active
def is_authenticated(self):
return True

82
app/classes/auto.py Normal file → Executable file
View File

@@ -2,21 +2,31 @@
from app import db, ma
from datetime import datetime
class Auto_Update(db.Model):
__tablename__ = 'auto_update'
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
last_updated = db.Column(db.DATE())
class Auto_Temp(db.Model):
__tablename__ = 'auto_temp'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
todays_date = db.Column(db.TIMESTAMP(), default=datetime.utcnow())
temp = db.Column(db.DECIMAL(50, 2))
temp_max = db.Column(db.DECIMAL(50, 2))
temp_min = db.Column(db.DECIMAL(50, 2))
temp_avg = db.Column(db.DECIMAL(50, 2))
todays_date = db.Column(db.DATE())
temp = db.Column(db.DECIMAL(6, 2))
temp_max = db.Column(db.DECIMAL(6, 2))
temp_min = db.Column(db.DECIMAL(6, 2))
temp_avg = db.Column(db.DECIMAL(6, 2))
degree_day = db.Column(db.INTEGER())
class Auto_Temp_schema(ma.SQLAlchemyAutoSchema):
@@ -27,7 +37,6 @@ class Auto_Temp_schema(ma.SQLAlchemyAutoSchema):
class Auto_Delivery(db.Model):
__tablename__ = 'auto_delivery'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -35,15 +44,62 @@ class Auto_Delivery(db.Model):
autoincrement=True,
unique=False)
customer_id = db.Column(db.INTEGER())
customer_full_name = db.Column(db.DECIMAL(50, 2))
last_fill = db.Column(db.TIMESTAMP())
last_updated = db.Column(db.TIMESTAMP())
estimated_gallons_left = db.Column(db.INTEGER())
estimated_gallons_left_prev_day = db.Column(db.INTEGER())
account_number = db.Column(db.VARCHAR(25))
customer_town = db.Column(db.VARCHAR(140))
customer_state = db.Column(db.Integer)
customer_address = db.Column(db.VARCHAR(1000))
customer_zip = db.Column(db.VARCHAR(25))
customer_full_name = db.Column(db.VARCHAR(250))
last_fill = db.Column(db.DATE())
days_since_last_fill = db.Column(db.Integer)
last_updated = db.Column(db.DATE())
estimated_gallons_left = db.Column(db.DECIMAL(6, 2))
estimated_gallons_left_prev_day = db.Column(db.DECIMAL(6, 2))
tank_height = db.Column(db.VARCHAR(25))
tank_size = db.Column(db.VARCHAR(25))
k_factor = db.Column(db.DECIMAL(50, 2))
house_factor = db.Column(db.DECIMAL(5, 2))
hot_water_summer = db.Column(db.Integer)
#0 = waiting
#1 = waiting for delivery
auto_status = db.Column(db.INTEGER())
open_ticket_id = db.Column(db.Integer)
class Auto_Delivery_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Auto_Delivery
class Tickets_Auto_Delivery(db.Model):
__tablename__ = 'auto_tickets'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
customer_id = db.Column(db.INTEGER())
account_number = db.Column(db.VARCHAR(25))
customer_town = db.Column(db.VARCHAR(140))
customer_state = db.Column(db.Integer)
customer_address = db.Column(db.VARCHAR(1000))
customer_zip = db.Column(db.VARCHAR(25))
customer_full_name = db.Column(db.VARCHAR(250))
fill_date = db.Column(db.DATE())
oil_prices_id = db.Column(db.INTEGER())
gallons_delivered = db.Column(db.DECIMAL(6, 2))
price_per_gallon = db.Column(db.DECIMAL(6, 2))
total_amount_customer = db.Column(db.DECIMAL(6, 2))
payment_type = db.Column(db.INTEGER, nullable=True)
payment_card_id = db.Column(db.INTEGER, nullable=True)
payment_status = db.Column(db.INTEGER, nullable=True)
class Tickets_Auto_Delivery_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Tickets_Auto_Delivery

9
app/classes/cards.py Normal file → Executable file
View File

@@ -5,7 +5,6 @@ from datetime import datetime
class Card_Card(db.Model):
__tablename__ = 'card_card'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -17,12 +16,14 @@ class Card_Card(db.Model):
card_number = db.Column(db.VARCHAR(50))
last_four_digits = db.Column(db.INTEGER())
name_on_card = db.Column(db.VARCHAR(500))
expiration_month = db.Column(db.INTEGER())
expiration_year = db.Column(db.INTEGER())
expiration_month = db.Column(db.VARCHAR(20))
expiration_year = db.Column(db.VARCHAR(20))
type_of_card = db.Column(db.VARCHAR(500))
security_number = db.Column(db.INTEGER())
security_number = db.Column(db.VARCHAR(10))
accepted_or_declined = db.Column(db.INTEGER())
main_card = db.Column(db.BOOLEAN())
zip_code = db.Column(db.VARCHAR(20))
auth_net_payment_profile_id = db.Column(db.String, nullable=True)
class Card_Card_schema(ma.SQLAlchemyAutoSchema):
class Meta:

5
app/classes/company.py Normal file → Executable file
View File

@@ -4,7 +4,6 @@ from app import db, ma
class Company_Company(db.Model):
__tablename__ = 'company_company'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -15,8 +14,8 @@ class Company_Company(db.Model):
company_dba_name = db.Column(db.VARCHAR(250))
company_llc_name = db.Column(db.VARCHAR(250))
company_town = db.Column(db.VARCHAR(140))
company_state = db.Column(db.VARCHAR(140))
company_zip = db.Column(db.INTEGER)
company_state = db.Column(db.INTEGER)
company_zip = db.Column(db.VARCHAR(25))
class Company_Company_schema(ma.SQLAlchemyAutoSchema):

66
app/classes/customer.py Normal file → Executable file
View File

@@ -1,31 +1,34 @@
#
from app import db, ma
from app import db, ma, login_manager
from datetime import datetime
class Customer_Customer(db.Model):
__tablename__ = 'customer_customer'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
auth_net_profile_id = db.Column(db.String, unique=True, index=True, nullable=True)
account_number = db.Column(db.VARCHAR(25))
customer_last_name = db.Column(db.VARCHAR(250))
customer_first_name = db.Column(db.VARCHAR(250))
customer_town = db.Column(db.VARCHAR(140))
customer_state = db.Column(db.INTEGER)
customer_zip = db.Column(db.VARCHAR(25))
customer_first_call = db.Column(db.TIMESTAMP(), default=datetime.utcnow())
customer_first_call = db.Column(db.TIMESTAMP())
customer_email = db.Column(db.VARCHAR(500))
customer_automatic = db.Column(db.INTEGER)
customer_phone_number = db.Column(db.VARCHAR(25))
customer_home_type = db.Column(db.INTEGER)
customer_apt = db.Column(db.VARCHAR(140))
customer_address = db.Column(db.VARCHAR(1000))
company_id = db.Column(db.INTEGER)
customer_latitude = db.Column(db.VARCHAR(250))
customer_longitude = db.Column(db.VARCHAR(250))
correct_address = db.Column(db.BOOLEAN)
class Customer_Customer_schema(ma.SQLAlchemyAutoSchema):
class Meta:
@@ -34,7 +37,6 @@ class Customer_Customer_schema(ma.SQLAlchemyAutoSchema):
class Customer_Property(db.Model):
__tablename__ = 'customer_property'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -60,7 +62,6 @@ class Customer_Property_schema(ma.SQLAlchemyAutoSchema):
class Customer_Payment_Credit(db.Model):
__tablename__ = 'customer_payment'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -74,9 +75,58 @@ class Customer_Payment_Credit(db.Model):
credit_card_name = db.Column(db.VARCHAR(240))
credit_card_number = db.Column(db.VARCHAR(140))
credit_card_security = db.Column(db.VARCHAR(140))
customer_card_expiration = db.Column(db.TIMESTAMP(), default=datetime.utcnow())
customer_card_expiration = db.Column(db.TIMESTAMP())
class Customer_Payment_Credit_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Customer_Payment_Credit
class Customer_Description(db.Model):
__tablename__ = 'customer_description'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
customer_id = db.Column(db.INTEGER)
account_number = db.Column(db.VARCHAR(25))
company_id = db.Column(db.INTEGER)
fill_location = db.Column(db.INTEGER)
description = db.Column(db.VARCHAR(2000))
class Customer_Description_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Customer_Description
class Customer_Property_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Customer_Property
class Customer_Tank_Inspection(db.Model):
__tablename__ = 'customer_tank'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
customer_id = db.Column(db.INTEGER)
last_tank_inspection = db.Column(db.DATE())
tank_status = db.Column(db.BOOLEAN)
outside_or_inside = db.Column(db.BOOLEAN)
tank_size = db.Column(db.INTEGER)
class Customer_Tank_Inspection_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Customer_Tank_Inspection

View File

@@ -0,0 +1,25 @@
#
from app import db, ma
class Customer_Customer_Social(db.Model):
__tablename__ = 'customer_customer_social'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
created = db.Column(db.DATE())
customer_id = db.Column(db.INTEGER)
poster_employee_id = db.Column(db.INTEGER)
comment = db.Column(db.VARCHAR(1000))
class Customer_Customer_Social_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Customer_Customer_Social

68
app/classes/delivery.py Normal file → Executable file
View File

@@ -1,10 +1,10 @@
from app import db, ma
from datetime import datetime
class Delivery_Delivery(db.Model):
__tablename__ = 'delivery_delivery'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -23,81 +23,73 @@ class Delivery_Delivery(db.Model):
# if customer asked for a fill
customer_asked_for_fill = db.Column(db.INTEGER)
# integer value if delivered, waiting, cancelled etc
gallons_delivered =db.Column(db.DECIMAL(50, 2))
gallons_delivered =db.Column(db.DECIMAL(6, 2))
# if customer has a full tank
customer_filled = db.Column(db.INTEGER)
# integer value if delivered, waiting, cancelled etc
# waiting = 0
# delivered = 1
# cancelled = 1
# out for delivery = 2
# cancelled = 3
# partial delivery = 4
# tommorrow = 3
# issue = 5
# finalized = 10
delivery_status = db.Column(db.INTEGER)
# when the call to order took place
when_ordered = db.Column(db.TIMESTAMP(), default=datetime.utcnow())
when_ordered = db.Column(db.DATE(), default=None)
# when the delivery date happened
when_delivered = db.Column(db.TIMESTAMP(), default=None)
when_delivered = db.Column(db.DATE(), default=None)
# when the delivery is expected ie what day
expected_delivery_date = db.Column(db.DATE(), default=None)
# automatic delivery
automatic = db.Column(db.INTEGER)
automatic_id = db.Column(db.INTEGER)
# OIL info and id from table
oil_id = db.Column(db.INTEGER)
supplier_price = db.Column(db.DECIMAL(50, 2))
customer_price = db.Column(db.DECIMAL(50, 2))
supplier_price = db.Column(db.DECIMAL(6, 2))
customer_price = db.Column(db.DECIMAL(6, 2))
# weather
customer_temperature = db.Column(db.DECIMAL(50, 2))
# services
customer_temperature = db.Column(db.DECIMAL(6, 2))
dispatcher_notes = db.Column(db.TEXT())
prime = db.Column(db.INTEGER)
same_day = db.Column(db.INTEGER)
emergency = db.Column(db.INTEGER)
# cash = 0
# credit = 1
# credit/cash = 2
# check = 3
# other = 4
payment_type = db.Column(db.INTEGER)
payment_card_id = db.Column(db.INTEGER)
cash_recieved = db.Column(db.DECIMAL(6, 2))
driver_employee_id = db.Column(db.INTEGER)
driver_first_name = db.Column(db.VARCHAR(140))
driver_last_name = db.Column(db.VARCHAR(140))
pre_charge_amount = db.Column(db.DECIMAL(50, 2))
total_price = db.Column(db.DECIMAL(50, 2))
final_price = db.Column(db.DECIMAL(50, 2))
pre_charge_amount = db.Column(db.DECIMAL(6, 2))
total_price = db.Column(db.DECIMAL(6, 2))
final_price = db.Column(db.DECIMAL(6, 2))
check_number = db.Column(db.VARCHAR(20))
promo_id = db.Column(db.INTEGER)
promo_money_discount = db.Column(db.DECIMAL(6, 2))
class Delivery_Delivery_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Delivery_Delivery
class Delivery_Payment(db.Model):
__tablename__ = 'delivery_payment'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
delivery_id = db.Column(db.INTEGER)
time_added = db.Column(db.TIMESTAMP(), default=datetime.utcnow())
total_amount_oil = db.Column(db.DECIMAL(50, 2))
total_amount_emergency = db.Column(db.DECIMAL(50, 2))
total_amount_prime = db.Column(db.DECIMAL(50, 2))
total_amount_fee = db.Column(db.DECIMAL(50, 2))
total_amount = db.Column(db.DECIMAL(50, 2))
class Delivery_Payment_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Delivery_Payment
class Delivery_Notes_Driver(db.Model):
__tablename__ = 'delivery_notes'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,

5
app/classes/employee.py Normal file → Executable file
View File

@@ -4,7 +4,6 @@ from datetime import datetime
class Employee_Employee(db.Model):
__tablename__ = 'employee_employee'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -34,7 +33,6 @@ class Employee_Employee_schema(ma.SQLAlchemyAutoSchema):
class Employee_Credentials(db.Model):
__tablename__ = 'employee_credentials'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -54,7 +52,6 @@ class Employee_Credentials_schema(ma.SQLAlchemyAutoSchema):
class Employee_Vacation(db.Model):
__tablename__ = 'employee_vacation'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -64,7 +61,7 @@ class Employee_Vacation(db.Model):
employee_id = db.Column(db.INTEGER)
employee_name = db.Column(db.VARCHAR(140))
employee_total_days_off = db.Column(db.INTEGER)
employee_days_off_multiplier = db.Column(db.DECIMAL(50, 2))
employee_days_off_multiplier = db.Column(db.DECIMAL(6, 2))
employee_days_off_per_year = db.Column(db.INTEGER)

46
app/classes/money.py Normal file
View File

@@ -0,0 +1,46 @@
from app import db, ma
class Money_delivery(db.Model):
__tablename__ = 'money_delivery'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
delivery_id = db.Column(db.Integer)
time_added = db.Column(db.DATE())
gallons_delivered = db.Column(db.DECIMAL(6, 2))
supplier_price = db.Column(db.DECIMAL(6, 2))
customer_price = db.Column(db.DECIMAL(6, 2))
total_amount_oil = db.Column(db.DECIMAL(6, 2))
total_amount_prime = db.Column(db.DECIMAL(6, 2))
total_amount_same_day = db.Column(db.DECIMAL(6, 2))
total_amount_fee = db.Column(db.DECIMAL(6, 2))
total_amount = db.Column(db.DECIMAL(6, 2))
total_discount_amount = db.Column(db.DECIMAL(6, 2))
total_discount_total = db.Column(db.DECIMAL(6, 2))
taxes_paid = db.Column(db.DECIMAL(6, 2))
total_profit = db.Column(db.DECIMAL(6, 2))
total_profit_oil = db.Column(db.DECIMAL(6, 2))
auto = db.Column(db.BOOLEAN)
class Money_delivery_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Money_delivery
class Pricing_Taxes(db.Model):
__tablename__ = 'pricing_taxes'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
state_id = db.Column(db.Integer)
taxes_oil = db.Column(db.DECIMAL(6, 2))
taxes_other = db.Column(db.DECIMAL(6, 2))

33
app/classes/pricing.py Normal file → Executable file
View File

@@ -2,33 +2,11 @@ from app import db, ma, login_manager
from datetime import datetime
class Pricing_Service_General(db.Model):
__tablename__ = 'pricing_service_general'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
price_service_hour = db.Column(db.DECIMAL(50, 2))
price_emergency_service_hour = db.Column(db.DECIMAL(50, 2))
price_emergency_call = db.Column(db.DECIMAL(50, 2))
price_out_of_oil = db.Column(db.DECIMAL(50, 2))
price_prime = db.Column(db.DECIMAL(50, 2))
price_cleaning = db.Column(db.DECIMAL(50, 2))
date = db.Column(db.TIMESTAMP(), default=datetime.utcnow())
class Pricing_Service_General_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Pricing_Service_General
class Pricing_Oil_Oil(db.Model):
__tablename__ = 'pricing_oil_oil'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -36,11 +14,12 @@ class Pricing_Oil_Oil(db.Model):
autoincrement=True,
unique=False)
price_from_supplier = db.Column(db.DECIMAL(50, 2))
price_for_customer = db.Column(db.DECIMAL(50, 2))
price_for_employee = db.Column(db.DECIMAL(50, 2))
price_same_day = db.Column(db.DECIMAL(50, 2))
price_prime = db.Column(db.DECIMAL(50, 2))
price_from_supplier = db.Column(db.DECIMAL(6, 2))
price_for_customer = db.Column(db.DECIMAL(6, 2))
price_for_employee = db.Column(db.DECIMAL(6, 2))
price_same_day = db.Column(db.DECIMAL(6, 2))
price_prime = db.Column(db.DECIMAL(6, 2))
price_emergency = db.Column(db.DECIMAL(6, 2))
date = db.Column(db.TIMESTAMP(), default=datetime.utcnow())

26
app/classes/promo.py Normal file
View File

@@ -0,0 +1,26 @@
from app import db, ma
class Promo_Promo(db.Model):
__tablename__ = 'promo_Promo'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
active = db.Column(db.BOOLEAN())
name_of_promotion = db.Column(db.VARCHAR(1000))
money_off_delivery = db.Column(db.DECIMAL(6, 2))
description = db.Column(db.VARCHAR(1000))
text_on_ticket = db.Column(db.VARCHAR(100))
date_created = db.Column(db.DATE())
class Promo_Promo_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Promo_Promo

23
app/classes/query.py Normal file → Executable file
View File

@@ -4,7 +4,6 @@ from app import db, ma
class Query_EmployeeTypeList(db.Model):
__tablename__ = 'query_employee_type_list'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
value = db.Column(db.INTEGER)
@@ -20,13 +19,14 @@ class Query_EmployeeTypeList_Schema(ma.SQLAlchemyAutoSchema):
class Query_StateList(db.Model):
__tablename__ = 'query_state_list'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
value = db.Column(db.INTEGER)
text = db.Column(db.VARCHAR(140))
class Query_StateList_Schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Query_StateList
@@ -35,9 +35,24 @@ class Query_StateList_Schema(ma.SQLAlchemyAutoSchema):
value = ma.auto_field()
class Query_TownList(db.Model):
__tablename__ = 'query_town_list'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
value = db.Column(db.INTEGER)
text = db.Column(db.VARCHAR(140))
class Query_TownList_Schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Query_TownList
id = ma.auto_field()
text = ma.auto_field()
value = ma.auto_field()
class Query_CustomerTypeList(db.Model):
__tablename__ = 'query_customer_type_list'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
value = db.Column(db.INTEGER)
@@ -55,7 +70,6 @@ class Query_CustomerTypeList_Schema(ma.SQLAlchemyAutoSchema):
class Query_ServiceTypeList(db.Model):
__tablename__ = 'query_service_type_list'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
value = db.Column(db.INTEGER)
@@ -73,7 +87,6 @@ class Query_ServiceTypeList_Schema(ma.SQLAlchemyAutoSchema):
class Query_DeliveryStatusList(db.Model):
__tablename__ = 'query_delivery_type_list'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
value = db.Column(db.INTEGER)

View File

@@ -3,9 +3,8 @@ from app import db, ma
from datetime import datetime
class Service_Call(db.Model):
__tablename__ = 'service_call'
__bind_key__ = 'eamco'
class Service_Service(db.Model):
__tablename__ = 'service_service'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -14,52 +13,38 @@ class Service_Call(db.Model):
unique=False)
customer_id = db.Column(db.INTEGER)
customer_last_name = db.Column(db.VARCHAR(250))
customer_first_name = db.Column(db.VARCHAR(250))
customer_town = db.Column(db.VARCHAR(140))
customer_state = db.Column(db.INTEGER)
customer_zip = db.Column(db.VARCHAR(25))
customer_apt = db.Column(db.VARCHAR(140))
customer_name = db.Column(db.VARCHAR(1000))
customer_address = db.Column(db.VARCHAR(1000))
customer_town = db.Column(db.VARCHAR(140))
customer_state = db.Column(db.VARCHAR(140))
customer_zip = db.Column(db.VARCHAR(10))
# tune-up = 0
# no heat = 1
# fix = 2
# tank = 3
# other = 4
type_service_call = db.Column(db.INTEGER)
when_ordered = db.Column(db.DATETIME())
scheduled_date = db.Column(db.DATETIME())
description = db.Column(db.TEXT())
#0 = closed
#1 = open
status = db.Column(db.INTEGER)
service_cost = db.Column(db.Numeric(10, 2), nullable=False)
# 0 = unknown
# 1 = cleaning / tuneup
# 2 = problem
# 3 = install
# 3 = callback
service_type = db.Column(db.INTEGER)
# when the call to service took place
when_called = db.Column(db.DATE(), default=datetime.utcnow())
# what day the call will take place
scheduled_date = db.Column(db.DATE(), default=datetime.utcnow())
# what day the call will take place
scheduled_time = db.Column(db.INTEGER)
# when the service took place
when_serviced = db.Column(db.DATE(), default=datetime.utcnow())
# is the call finished or not
# 0 = open
#1 = finished
completed = db.Column(db.INTEGER)
tech_id = db.Column(db.INTEGER)
tech_first_name = db.Column(db.VARCHAR(300))
tech_last_name = db.Column(db.VARCHAR(300))
payment_type = db.Column(db.INTEGER)
payment_card_id = db.Column(db.INTEGER)
payment_type = db.Column(db.INTEGER, nullable=True)
payment_card_id = db.Column(db.INTEGER, nullable=True)
payment_status = db.Column(db.INTEGER, nullable=True)
class Service_Call_schema(ma.SQLAlchemyAutoSchema):
class Service_Service_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Service_Call
model = Service_Service
scheduled_date = ma.DateTime(format='%Y-%m-%dT%H:%M:%S')
when_ordered = ma.DateTime(format='%Y-%m-%dT%H:%M:%S')
class Service_Call_Money(db.Model):
__tablename__ = 'service_money'
__bind_key__ = 'eamco'
class Service_Parts(db.Model):
__tablename__ = 'service_parts'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -67,20 +52,24 @@ class Service_Call_Money(db.Model):
autoincrement=True,
unique=False)
service_call_id = db.Column(db.INTEGER)
hours = db.Column(db.DECIMAL(50, 2))
cost_per_hour = db.Column(db.DECIMAL(50, 2))
parts_cost = db.Column(db.DECIMAL(50, 2))
customer_id = db.Column(db.INTEGER)
oil_filter = db.Column(db.VARCHAR(100))
oil_filter_2 = db.Column(db.VARCHAR(100))
oil_nozzle = db.Column(db.VARCHAR(10))
oil_nozzle_2 = db.Column(db.VARCHAR(10))
hot_water_tank = db.Column(db.INTEGER)
class Service_Call_Money_schema(ma.SQLAlchemyAutoSchema):
class Service_Parts_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Service_Call_Money
model = Service_Parts
scheduled_date = ma.DateTime(format='%Y-%m-%dT%H:%M:%S')
when_ordered = ma.DateTime(format='%Y-%m-%dT%H:%M:%S')
class Service_Call_Notes_Dispatcher(db.Model):
__tablename__ = 'service_notes_dispatcher'
__bind_key__ = 'eamco'
class Service_Plans(db.Model):
__tablename__ = 'service_plans'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -88,39 +77,13 @@ class Service_Call_Notes_Dispatcher(db.Model):
autoincrement=True,
unique=False)
service_call_id = db.Column(db.INTEGER)
dispatcher_notes = db.Column(db.TEXT)
dispatcher_subject = db.Column(db.VARCHAR(1024))
time_added = db.Column(db.TIMESTAMP(), default=datetime.utcnow())
dispatcher_id = db.Column(db.INTEGER)
dispatcher_name = db.Column(db.VARCHAR(140))
customer_id = db.Column(db.INTEGER)
contract_plan = db.Column(db.INTEGER, default=0) # 0=no contract, 1=standard, 2=premium
contract_years = db.Column(db.INTEGER, default=1)
contract_start_date = db.Column(db.DATE())
class Service_Call_Notes_Dispatcher_schema(ma.SQLAlchemyAutoSchema):
class Service_Plans_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Service_Call_Notes_Dispatcher
class Service_Call_Notes_Technician(db.Model):
__tablename__ = 'service_notes_technician'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
service_call_id = db.Column(db.INTEGER)
technician_comments = db.Column(db.TEXT)
time_added = db.Column(db.TIMESTAMP(), default=datetime.utcnow())
technician_id = db.Column(db.INTEGER)
technician_name = db.Column(db.VARCHAR(140))
class Service_Call_Notes_Technician_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Service_Call_Notes_Technician
model = Service_Plans
contract_start_date = ma.DateTime(format='%Y-%m-%d')

View File

@@ -0,0 +1,20 @@
from app import db, ma
from datetime import datetime
class Stats_Company(db.Model):
__tablename__ = 'stats_company'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
total_calls = db.Column(db.BigInteger)
class Stats_Company_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Stats_Company

16
app/classes/stats_customer.py Normal file → Executable file
View File

@@ -5,25 +5,27 @@ from datetime import datetime
class Stats_Customer(db.Model):
__tablename__ = 'stats_customer'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
customer_id = db.Column(db.INTEGER)
total_calls = db.Column(db.INTEGER)
service_calls_total = db.Column(db.INTEGER)
service_calls_total_spent = db.Column(db.DECIMAL(50, 2))
service_calls_total_profit = db.Column(db.DECIMAL(50, 2))
service_calls_total_spent = db.Column(db.DECIMAL(6, 2))
service_calls_total_profit = db.Column(db.DECIMAL(6, 2))
oil_deliveries = db.Column(db.INTEGER)
oil_total_gallons = db.Column(db.INTEGER)
oil_total_spent = db.Column(db.DECIMAL(50, 2))
oil_total_profit = db.Column(db.DECIMAL(50, 2))
oil_total_gallons = db.Column(db.DECIMAL(6, 2))
oil_total_spent = db.Column(db.DECIMAL(6, 2))
oil_total_profit = db.Column(db.DECIMAL(6, 2))
class Stats_Customer_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Stats_Customer

31
app/classes/stats_employee.py Normal file → Executable file
View File

@@ -1,23 +1,22 @@
from app import db, ma, login_manager
from app import db, ma
from datetime import datetime
class Stats_Employee_Oil(db.Model):
__tablename__ = 'stats_employee_oil'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
employee_id = db.Column(db.INTEGER)
total_deliveries = db.Column(db.INTEGER)
total_gallons_delivered = db.Column(db.INTEGER)
total_primes = db.Column(db.INTEGER)
total_gallons_fuel = db.Column(db.INTEGER)
oil_total_profit_delivered = db.Column(db.DECIMAL(50, 2))
oil_total_profit_delivered = db.Column(db.DECIMAL(6, 2))
oil_total_money_delivered = db.Column(db.DECIMAL(6, 2))
class Stats_Employee_Oil_schema(ma.SQLAlchemyAutoSchema):
class Meta:
@@ -26,9 +25,10 @@ class Stats_Employee_Oil_schema(ma.SQLAlchemyAutoSchema):
class Stats_Employee_Service(db.Model):
__tablename__ = 'stats_employee_service'
__bind_key__ = 'eamco'
class Stats_Employee_Office(db.Model):
__tablename__ = 'stats_employee_office'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
@@ -36,11 +36,12 @@ class Stats_Employee_Service(db.Model):
autoincrement=True,
unique=False)
total_service_calls = db.Column(db.INTEGER)
total_service_calls_hours = db.Column(db.INTEGER)
total_gallons_fuel = db.Column(db.INTEGER)
total_amount_billed= db.Column(db.DECIMAL(50, 2))
total_profit_made = db.Column(db.DECIMAL(50, 2))
class Stats_Employee_Service_schema(ma.SQLAlchemyAutoSchema):
employee_id = db.Column(db.INTEGER)
total_orders = db.Column(db.INTEGER)
total_credit_cards_proccessed = db.Column(db.INTEGER)
class Stats_Employee_Office_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Stats_Employee_Service
model = Stats_Employee_Office

View File

@@ -1,27 +0,0 @@
from app import db, ma
from datetime import datetime
class Delivery_Payment(db.Model):
__tablename__ = 'delivery_payment'
__bind_key__ = 'eamco'
__table_args__ = {"schema": "public"}
id = db.Column(db.Integer,
primary_key=True,
autoincrement=True,
unique=False)
delivery_id = db.Column(db.INTEGER)
time_added = db.Column(db.TIMESTAMP(), default=datetime.utcnow())
total_amount_oil = db.Column(db.DECIMAL(50, 2))
total_amount_emergency = db.Column(db.DECIMAL(50, 2))
total_amount_prime = db.Column(db.DECIMAL(50, 2))
total_amount_fee = db.Column(db.DECIMAL(50, 2))
total_amount = db.Column(db.DECIMAL(50, 2))
class Delivery_Payment_schema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Delivery_Payment

View File

@@ -0,0 +1,22 @@
from sqlalchemy import Column, Integer, String, Numeric, DateTime
from app import db
import datetime
class Transaction(db.Model):
__tablename__ = "transactions"
id = Column(Integer, primary_key=True, index=True)
preauthorize_amount = Column(Numeric(10, 2), nullable=True) # Amount preauthorized (for auth transactions)
charge_amount = Column(Numeric(10, 2), nullable=True) # Final charge amount (for charge/capture transactions)
transaction_type = Column(Integer) # 0 = charge, 1 = auth, 2 = capture
status = Column(Integer) # 0 = approved, 1 = declined
auth_net_transaction_id = Column(String, unique=True, index=True, nullable=True)
customer_id = Column(Integer)
service_id = Column(Integer, nullable=True) # Reference to Service_Service.id
delivery_id = Column(Integer, nullable=True) # Reference to Delivery_Delivery.id
card_id = Column(Integer, nullable=True) # Reference to credit card used for payment
auto_id = Column(Integer, nullable=True) # Reference to Auto_Delivery or Auto_Ticket.id
payment_gateway = Column(Integer, default=1) # 1 = Authorize.Net, 0 = Other
rejection_reason = Column(String, nullable=True) # Detailed error message when payment is declined
created_at = Column(DateTime, default=datetime.datetime.utcnow)

0
app/common/__init__.py Normal file → Executable file
View File

0
app/common/decorators.py Normal file → Executable file
View File

0
app/customer/__init__.py Normal file → Executable file
View File

476
app/customer/views.py Normal file → Executable file
View File

@@ -1,18 +1,39 @@
from flask import request, jsonify
from flask_login import login_required
from geopy.geocoders import Nominatim
from app.customer import customer
from app import db
from datetime import datetime
from app.classes.cards import Card_Card
from app.classes.customer import \
Customer_Customer, \
Customer_Customer_schema
Customer_Customer_schema,\
Customer_Description, \
Customer_Description_schema,\
Customer_Tank_Inspection_schema,\
Customer_Tank_Inspection
from app.classes.service import Service_Parts
from app.classes.admin import Admin_Company
from app.classes.auto import Auto_Delivery,Auto_Delivery_schema
from app.classes.stats_customer import Stats_Customer
import string
import random
def generate_random_number_string(length):
# Ensure the length is at least 1
if length < 1:
raise ValueError("Length must be at least 1")
# Generate a random number with the specified length
random_number = ''.join(random.choices(string.digits, k=length))
return random_number
@customer.route("/all", methods=["GET"])
@login_required
def all_customers_around():
customer_list = db.session \
.query(Customer_Customer) \
@@ -22,13 +43,13 @@ def all_customers_around():
@customer.route("/all/<int:page>", methods=["GET"])
@login_required
def all_customers(page):
"""
pagination all customers
"""
per_page_amount = 50
per_page_amount = 100
if page is None:
offset_limit = 0
elif page == 1:
@@ -38,6 +59,7 @@ def all_customers(page):
customer_list = db.session \
.query(Customer_Customer) \
.order_by(Customer_Customer.id.desc()) \
.limit(per_page_amount).offset(offset_limit)
customer_schema = Customer_Customer_schema(many=True)
@@ -47,7 +69,6 @@ def all_customers(page):
@customer.route("/<int:customer_id>", methods=["GET"])
def get_a_customer(customer_id):
"""
Checks auth token to ensure user is authenticated
"""
get_customer = (db.session
.query(Customer_Customer)
@@ -56,20 +77,105 @@ def get_a_customer(customer_id):
customer_schema = Customer_Customer_schema(many=False)
return jsonify(customer_schema.dump(get_customer))
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
@customer.route("/description/<int:customer_id>", methods=["GET"])
def get_a_customer_description(customer_id):
"""
"""
get_customer_description = (db.session
.query(Customer_Description)
.filter(Customer_Description.customer_id == customer_id)
.first())
if get_customer_description is None:
get_customer = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.id == customer_id)
.first())
new_description = Customer_Description(
customer_id = customer_id,
account_number = get_customer.account_number,
company_id = get_customer.company_id,
fill_location = None,
description = None,
)
db.session.add(new_description)
db.session.commit()
get_customer_description = (db.session
.query(Customer_Description)
.filter(Customer_Description.customer_id == customer_id)
.first())
customer_schema = Customer_Description_schema(many=False)
return jsonify(customer_schema.dump(get_customer_description))
@customer.route("/tank/<int:customer_id>", methods=["GET"])
def get_a_customer_tank(customer_id):
"""
"""
get_customer_tank = (db.session
.query(Customer_Tank_Inspection)
.filter(Customer_Tank_Inspection.customer_id == customer_id)
.first())
if get_customer_tank is None:
new_tank = Customer_Tank_Inspection(
customer_id = customer_id,
last_tank_inspection = None,
tank_status = False,
outside_or_inside = True,
tank_size = 275,
)
db.session.add(new_tank)
db.session.commit()
get_customer_tank = (db.session
.query(Customer_Tank_Inspection)
.filter(Customer_Tank_Inspection.customer_id == customer_id)
.first())
customer_schema = Customer_Tank_Inspection_schema(many=False)
return jsonify(customer_schema.dump(get_customer_tank))
@customer.route("/create", methods=["POST"])
@login_required
def create_customer():
"""
"""
now = datetime.utcnow()
get_company = db.session.query(Admin_Company).filter(Admin_Company.id == 1).first()
get_company = (db.session
.query(Admin_Company)
.filter(Admin_Company.id == 1)
.first())
starter_digits = str(get_company.account_prefix) + '-' + id_generator()
get_company = (db.session
.query(Admin_Company)
.filter(Admin_Company.id == 1)
.first())
made_account_number = starter_digits
random_string = generate_random_number_string(6)
made_account_number = str(get_company.account_prefix) + '-' + str(random_string)
see_if_exists = (db.session.query(Customer_Customer).filter(Customer_Customer.account_number == made_account_number).first())
if see_if_exists is not None:
random_string = generate_random_number_string(10)
made_account_number = str(get_company.account_prefix) + '-' + str(random_string)
see_if_exists = (db.session.query(Customer_Customer).filter(Customer_Customer.account_number == made_account_number).first())
if see_if_exists is not None:
random_string = generate_random_number_string(10)
made_account_number = str(get_company.account_prefix) + '-' + str(random_string)
see_if_exists = (db.session.query(Customer_Customer).filter(Customer_Customer.account_number == made_account_number).first())
response_customer_last_name = request.json["customer_last_name"]
response_customer_first_name = request.json["customer_first_name"]
@@ -77,20 +183,77 @@ def create_customer():
response_customer_state = request.json["customer_state"]
response_customer_zip = request.json["customer_zip"]
response_customer_email = request.json["customer_email"]
response_customer_automatic = request.json["customer_automatic"]
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"]
if response_customer_automatic is True:
auto_customer = 1
else:
auto_customer = 0
customer_description_msg = request.json["customer_description"]
int_customer_home_type = int(response_customer_home_type)
response_customer_zip = int(response_customer_zip)
response_customer_zip = str(response_customer_zip)
response_customer_state = int(response_customer_state)
if response_customer_state == 0:
the_state = 'MA'
elif response_customer_state == 1:
the_state = 'RI'
elif response_customer_state == 2:
the_state = 'NH'
else:
the_state = 'MA'
if response_customer_town == 0:
the_town = 'Auburn'
elif response_customer_state == 1:
the_town = 'Charlton'
elif response_customer_state == 2:
the_town = 'Cherry Valley'
elif response_customer_state == 3:
the_town = 'Dudley'
elif response_customer_state == 4:
the_town = 'Grafton'
elif response_customer_state == 5:
the_town = 'Leicester'
elif response_customer_state == 6:
the_town = 'Millbury'
elif response_customer_state == 7:
the_town = 'N Oxford'
elif response_customer_state == 8:
the_town = 'Oxford'
elif response_customer_state == 9:
the_town = 'Rochdale'
elif response_customer_state == 10:
the_town = 'Shrewsbury'
elif response_customer_state == 11:
the_town = 'Southbridge'
elif response_customer_state == 12:
the_town = 'Spencer'
elif response_customer_state == 13:
the_town = 'Sturbridge'
elif response_customer_state == 14:
the_town = 'Webster'
elif response_customer_state == 15:
the_town = 'Worcester'
else:
the_town = 'NA'
geolocator = Nominatim(user_agent="auburnoil")
address_string = customer_address + ' ' + response_customer_town+ ' ' + the_state
try:
location = geolocator.geocode(address_string)
user_lat =location.latitude
user_long = location.longitude
cor_ad = True
except:
user_lat =None
user_long = None
cor_ad = False
new_customer = Customer_Customer(
account_number=made_account_number,
customer_last_name=response_customer_last_name,
@@ -100,15 +263,51 @@ def create_customer():
customer_zip=response_customer_zip,
customer_first_call=now,
customer_email=response_customer_email,
customer_automatic=auto_customer,
customer_automatic=0,
customer_home_type=int_customer_home_type,
customer_phone_number=customer_phone_number,
customer_address=customer_address,
customer_apt=customer_apt
customer_apt=customer_apt,
company_id=1,
customer_latitude=user_lat,
customer_longitude=user_long,
correct_address=cor_ad
)
db.session.add(new_customer)
db.session.flush()
create_stats_customer = Stats_Customer(
customer_id = new_customer.id,
total_calls = 0,
service_calls_total = 0,
service_calls_total_spent = 0,
service_calls_total_profit = 0,
oil_deliveries = 0,
oil_total_gallons = 0,
oil_total_spent = 0,
oil_total_profit = 0,
)
db.session.add(create_stats_customer)
new_description = Customer_Description(
customer_id = new_customer.id,
account_number = made_account_number,
description = customer_description_msg,
fill_location=None,
company_id=1,
)
db.session.add(new_description)
new_tank = Customer_Tank_Inspection(
customer_id = new_customer.id,
last_tank_inspection=None,
tank_status = False,
outside_or_inside = True,
tank_size=275,
)
db.session.add(new_tank)
db.session.commit()
return jsonify({
@@ -121,6 +320,7 @@ def create_customer():
}), 200
@customer.route("/edit/<int:customer_id>", methods=["PUT"])
@login_required
def edit_customer(customer_id):
@@ -130,6 +330,10 @@ def edit_customer(customer_id):
.query(Customer_Customer)
.filter(Customer_Customer.id == customer_id)
.first())
get_customer_description = (db.session
.query(Customer_Description)
.filter(Customer_Description.customer_id == customer_id)
.first())
response_customer_last_name = request.json["customer_last_name"]
response_customer_first_name = request.json["customer_first_name"]
response_customer_town = request.json["customer_town"]
@@ -137,13 +341,43 @@ def edit_customer(customer_id):
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_automatic = request.json["customer_automatic"]
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"]
if get_customer_description is not None:
get_customer_description.description = response_customer_description
get_customer_description.fill_location = response_customer_fill_location
db.session.add(get_customer_description)
if response_customer_state == 0:
the_state = 'MA'
elif response_customer_state == 1:
the_state = 'RI'
elif response_customer_state == 1:
the_state = 'NH'
else:
the_state = 'MA'
geolocator = Nominatim(user_agent="auburnoil")
address_string = response_customer_address + ' ' + response_customer_town+ ' ' + the_state
try:
location = geolocator.geocode(address_string, timeout=10)
get_customer.customer_latitude = location.latitude
get_customer.customer_longitude = location.longitude
cor_ad = True
except:
get_customer.customer_latitude = None
get_customer.customer_longitude = None
cor_ad = False
get_customer.customer_address = response_customer_address
get_customer.customer_home_type = response_customer_home_type
get_customer.customer_automatic = response_customer_automatic
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
@@ -151,6 +385,9 @@ def edit_customer(customer_id):
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.commit()
@@ -194,3 +431,196 @@ def delete_customer(customer_id):
}), 200
@customer.route("/count", methods=["GET"])
@login_required
def customer_count():
"""
"""
get_customer = (db.session
.query(Customer_Customer)
.count())
return jsonify({
"ok": True,
'count': get_customer
}), 200
@customer.route("/automatic/status/<int:customer_id>", methods=["GET"])
@login_required
def customer_automatic_status(customer_id):
"""
"""
get_customer = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.id == customer_id)
.first())
if get_customer.customer_automatic == 1:
status = 1
if get_customer.customer_automatic == 0:
status = 0
return jsonify({
"ok": True,
'status': status
}), 200
@customer.route("/automatic/deliveries", methods=["GET"])
@login_required
def get_all_automatic_deliveries():
"""
Get all automatic deliveries for the table.
"""
try:
deliveries = Auto_Delivery.query.all()
schema = Auto_Delivery_schema(many=True)
return jsonify(schema.dump(deliveries)), 200
except Exception as e:
return jsonify({"error": str(e)}), 500
@customer.route("/automatic/assign/<int:customer_id>", methods=["GET"])
@login_required
def customer_automatic_assignment(customer_id):
"""
"""
get_customer = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.id == customer_id)
.first())
get_auto = (db.session
.query(Auto_Delivery)
.filter(Auto_Delivery.customer_id == customer_id)
.first())
get_main_credit_card = (db.session
.query(Card_Card)
.filter(Card_Card.user_id == customer_id)
.filter(Card_Card.main_card == True)
.first())
get_customer_tank = (db.session
.query(Customer_Tank_Inspection)
.filter(Customer_Tank_Inspection.customer_id == customer_id)
.first())
get_service_parts = (db.session
.query(Service_Parts)
.filter(Service_Parts.customer_id == customer_id)
.first())
if get_customer.customer_automatic == 1:
# customer becomes will call
get_customer.customer_automatic = 0
db.session.add(get_customer)
if get_auto is not None:
db.session.delete(get_auto)
status = 3
else:
if get_main_credit_card is None:
status = 2
return jsonify({
"ok": True,
'status': status
}), 200
# customer becomes an automatic
if get_auto is None:
hot_water_value = get_service_parts.hot_water_tank if get_service_parts and get_service_parts.hot_water_tank is not None else 0
create_auto = Auto_Delivery(customer_id=customer_id,
customer_full_name=get_customer.customer_first_name + ' ' + get_customer.customer_last_name,
account_number=get_customer.account_number,
customer_town=get_customer.customer_town,
customer_state=get_customer.customer_state,
customer_zip=get_customer.customer_zip,
customer_address=get_customer.customer_address,
last_fill=None,
last_updated=None,
estimated_gallons_left=0,
estimated_gallons_left_prev_day=0,
tank_height=0,
tank_size=get_customer_tank.tank_size,
house_factor=1,
auto_status=1,
days_since_last_fill=0,
hot_water_summer=hot_water_value
)
db.session.add(create_auto)
get_customer.customer_automatic = 1
db.session.add(get_customer)
status = 1
db.session.commit()
return jsonify({
"ok": True,
'status': status
}), 200
@customer.route("/edit/tank/<int:customer_id>", methods=["PUT"])
@login_required
def edit_customer_tank(customer_id):
"""
Safely edits or creates tank and description details for a customer.
"""
get_customer = db.session.query(Customer_Customer).filter(Customer_Customer.id == customer_id).one_or_none()
if not get_customer:
return jsonify({"ok": False, "error": "Customer not found"}), 404
get_customer_description = db.session.query(Customer_Description).filter(Customer_Description.customer_id == customer_id).first()
if not get_customer_description:
get_customer_description = Customer_Description(customer_id=customer_id)
db.session.add(get_customer_description)
get_customer_tank = db.session.query(Customer_Tank_Inspection).filter(Customer_Tank_Inspection.customer_id == customer_id).first()
if not get_customer_tank:
get_customer_tank = Customer_Tank_Inspection(customer_id=customer_id)
db.session.add(get_customer_tank)
data = request.get_json()
if 'tank_status' in data:
get_customer_tank.tank_status = data["tank_status"]
if 'outside_or_inside' in data:
get_customer_tank.outside_or_inside = data["outside_or_inside"]
response_last_tank_inspection = data.get("last_tank_inspection", None)
response_tank_size = data.get("tank_size", 0)
# --- FIX APPLIED HERE ---
# 1. Get the value from the request. Default to 0 if it's missing.
response_customer_fill_location = data.get("fill_location", 0)
# 2. Add a safety check: if the frontend sent an empty string, convert it to 0.
if response_customer_fill_location == "":
response_customer_fill_location = 0
get_customer_tank.last_tank_inspection = response_last_tank_inspection
get_customer_tank.tank_size = response_tank_size
get_customer_description.fill_location = response_customer_fill_location
if get_customer.customer_automatic == 1:
get_auto_info = db.session.query(Auto_Delivery).filter(Auto_Delivery.customer_id == customer_id).first()
if get_auto_info:
get_auto_info.tank_size = response_tank_size
db.session.add(get_auto_info)
db.session.commit()
return jsonify({"ok": True}), 200

0
app/delivery/__init__.py Normal file → Executable file
View File

731
app/delivery/views.py Normal file → Executable file
View File

@@ -3,71 +3,157 @@ from flask_login import current_user
from datetime import date, datetime, timedelta
from app.delivery import delivery
from app import db
from app.classes.customer import Customer_Customer
from sqlalchemy import or_
from app.classes.customer import (Customer_Customer)
from app.classes.delivery import (Delivery_Delivery,
Delivery_Delivery_schema,
Delivery_Notes_Driver,
Delivery_Payment,
Delivery_Payment_schema,
)
from app.classes.employee import Employee_Employee
from app.classes.cards import Card_Card
from app.classes.pricing import Pricing_Oil_Oil
from app.classes.auth import Auth_User
from app.classes.pricing import Pricing_Service_General
from app.classes.promo import Promo_Promo
from app.classes.stats_customer import Stats_Customer
from app.classes.auto import Tickets_Auto_Delivery, Tickets_Auto_Delivery_schema
# This endpoint is fine, but I've added some comments for clarity.
@delivery.route("/updatestatus", methods=["GET"])
def move_deliveries():
"""
Batch updates delivery statuses based on their expected delivery date relative to today.
- Today's deliveries -> "Out for Delivery" (2)
- Tomorrow's deliveries -> "Scheduled for Tomorrow" (3)
- Future deliveries -> "Waiting" (0)
- Past-due deliveries -> "Pending" (9)
"""
counter = 0
today = date.today()
tomorrow = today + timedelta(days=1)
# Update statuses for deliveries scheduled for today
deliveries_today = db.session.query(Delivery_Delivery).filter(
Delivery_Delivery.delivery_status.notin_([1, 5, 10]), # Not cancelled, issue, or finalized
Delivery_Delivery.expected_delivery_date == today,
Delivery_Delivery.delivery_status != 2 # Avoid redundant updates
).all()
for delivery_item in deliveries_today:
delivery_item.delivery_status = 2
db.session.add(delivery_item)
counter += 1
# Update statuses for deliveries scheduled for tomorrow
deliveries_tomorrow = db.session.query(Delivery_Delivery).filter(
Delivery_Delivery.delivery_status.notin_([1, 5, 10]),
Delivery_Delivery.expected_delivery_date == tomorrow,
Delivery_Delivery.delivery_status != 3
).all()
for delivery_item in deliveries_tomorrow:
delivery_item.delivery_status = 3
db.session.add(delivery_item)
counter += 1
# Update statuses for future deliveries (after tomorrow)
deliveries_waiting = db.session.query(Delivery_Delivery).filter(
Delivery_Delivery.delivery_status.notin_([1, 5, 10]),
Delivery_Delivery.expected_delivery_date > tomorrow,
Delivery_Delivery.delivery_status != 0
).all()
for delivery_item in deliveries_waiting:
delivery_item.delivery_status = 0
db.session.add(delivery_item)
counter += 1
# Update statuses for deliveries that are past their expected date
deliveries_pending = db.session.query(Delivery_Delivery).filter(
Delivery_Delivery.delivery_status.notin_([1, 5, 10]),
Delivery_Delivery.expected_delivery_date < today,
Delivery_Delivery.delivery_status != 9
).all()
for delivery_item in deliveries_pending:
delivery_item.delivery_status = 9
db.session.add(delivery_item)
counter += 1
if counter > 0:
db.session.commit()
return jsonify({"ok": True, 'update': True}), 200
return jsonify({"ok": True, 'update': False}), 200
@delivery.route("/<int:delivery_id>", methods=["GET"])
def get_a_delivery(delivery_id):
"""
Get a single delivery's details.
"""
get_delivery = db.session\
.query(Delivery_Delivery)\
.filter(Delivery_Delivery.id == delivery_id)\
.first()
return jsonify({
"ok": True,
'delivery': {
'id': get_delivery.id,
'customer_id': get_delivery.customer_id,
'delivery_expected_delivery_date': str(get_delivery.expected_delivery_date),
'delivery_asked_for_fill': get_delivery.customer_asked_for_fill,
'delivery_gallons_ordered': get_delivery.gallons_ordered,
'delivery_dispatcher_notes': get_delivery.dispatcher_notes,
'delivery_prime': get_delivery.prime,
'delivery_same_day': get_delivery.same_day,
'when_ordered': get_delivery.when_ordered,
'customer_price': get_delivery.customer_price,
'delivery_status': get_delivery.delivery_status,
'payment_type': get_delivery.payment_type,
'payment_card_id': get_delivery.payment_card_id,
'driver_employee_id': get_delivery.driver_employee_id,
'driver_first_name': get_delivery.driver_first_name,
'driver_last_name': get_delivery.driver_last_name,
},
}), 200
get_delivery = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.id == delivery_id).first()
if not get_delivery:
return jsonify({"ok": False, "error": "Delivery not found"}), 404
# Using the schema is cleaner and less error-prone than building a manual dictionary.
delivery_schema = Delivery_Delivery_schema(many=False)
return jsonify({"ok": True, "delivery": delivery_schema.dump(get_delivery)}), 200
@delivery.route("/past1/<int:customer_id>", methods=["GET"])
def get_customer_past_delivery1(customer_id):
get_customer_past_delivery = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.customer_id == customer_id)
.filter(Delivery_Delivery.delivery_status == 10)
.order_by(Delivery_Delivery.id.desc())
.limit(5))
delivery_schema = Delivery_Delivery_schema(many=True)
return jsonify(delivery_schema.dump(get_customer_past_delivery))
@delivery.route("/past2/<int:customer_id>", methods=["GET"])
def get_customer_past_delivery2(customer_id):
get_customer_past_delivery = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.customer_id == customer_id)
.order_by(Delivery_Delivery.id.desc())
.offset(5)
.limit(5))
delivery_schema = Delivery_Delivery_schema(many=True)
return jsonify(delivery_schema.dump(get_customer_past_delivery))
@delivery.route("/auto/<int:customer_id>", methods=["GET"])
def get_customer_auto_delivery(customer_id):
get_customer_past_delivery = (db.session
.query(Tickets_Auto_Delivery)
.filter(Tickets_Auto_Delivery.customer_id == customer_id)
.order_by(Tickets_Auto_Delivery.id.desc())
.offset(5)
.limit(5))
delivery_schema = Tickets_Auto_Delivery_schema(many=True)
return jsonify(delivery_schema.dump(get_customer_past_delivery))
@delivery.route("/order/<int:delivery_id>", methods=["GET"])
def get_a_specific_delivery(delivery_id):
"""
Get a single delivery by its ID.
"""
get_delivery = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.id == delivery_id).first()
if not get_delivery:
return jsonify({"ok": False, "error": "Delivery not found"}), 404
get_delivery = db.session\
.query(Delivery_Delivery)\
.filter(Delivery_Delivery.id == delivery_id)\
.first()
delivery_schema = Delivery_Delivery_schema(many=False)
return jsonify(delivery_schema.dump(get_delivery))
return jsonify({"ok": True, "delivery": delivery_schema.dump(get_delivery)}), 200
@delivery.route("/order/money/<int:delivery_id>", methods=["GET"])
def get_a_specific_delivery_money(delivery_id):
get_delivery_money = db.session\
.query(Delivery_Payment)\
.filter(Delivery_Payment.id == delivery_id)\
.first()
delivery_schema = Delivery_Payment_schema(many=False)
return jsonify(delivery_schema.dump(get_delivery_money))
@delivery.route("/cash/<int:delivery_id>/<int:type_of_payment>", methods=["PUT"])
@@ -89,24 +175,9 @@ def update_a_delivery_payment(delivery_id, type_of_payment):
return jsonify({"ok": True}), 200
@delivery.route("/all", methods=["GET"])
def get_deliveries_not_delivered_all():
"""
This will get deliveries not done
"""
deliveries = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.delivery_status != 1) \
.filter(Delivery_Delivery.delivery_status != 3) \
.all()
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/customer/<int:customer_id>/<int:page>", methods=["GET"])
def get_deliveries_from_customer(customer_id, page):
@delivery.route("/all/<int:page>", methods=["GET"])
def get_deliveries_all(page):
"""
This will get deliveries not done
"""
@@ -118,15 +189,44 @@ def get_deliveries_from_customer(customer_id, page):
else:
offset_limit = (per_page_amount * page) - per_page_amount
deliveries = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.customer_id == customer_id) \
.limit(per_page_amount).offset(offset_limit)
deliveries = (db.session
.query(Delivery_Delivery)
.order_by(Delivery_Delivery.id.desc())
.limit(per_page_amount).offset(offset_limit))
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/all/<int:page>", methods=["GET"])
@delivery.route("/customer/<int:customer_id>/<int:page>", methods=["GET"])
def get_deliveries_from_customer(customer_id, page):
"""
This will get deliveries not done
"""
per_page_amount = 50
if page is None:
offset_limit = 0
elif page == 1:
offset_limit = 0
else:
offset_limit = (per_page_amount * page) - per_page_amount
deliveries = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.customer_id == customer_id)
.order_by(Delivery_Delivery.id.desc())
.limit(per_page_amount).offset(offset_limit))
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/all/order/<int:page>", methods=["GET"])
def get_deliveries_not_delivered(page):
"""
@@ -140,15 +240,17 @@ def get_deliveries_not_delivered(page):
else:
offset_limit = (per_page_amount * page) - per_page_amount
deliveries = db.session\
.query(Delivery_Delivery)\
.filter(Delivery_Delivery.delivery_status == 0)\
.order_by(Delivery_Delivery.when_ordered.desc())\
.limit(per_page_amount).offset(offset_limit)
deliveries = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.delivery_status != 10)
.order_by(Delivery_Delivery.when_ordered.desc())
.limit(per_page_amount).offset(offset_limit))
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/waiting/<int:page>", methods=["GET"])
def get_deliveries_waiting(page):
"""
@@ -162,19 +264,24 @@ def get_deliveries_waiting(page):
else:
offset_limit = (per_page_amount * page) - per_page_amount
deliveries = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.delivery_status == 0) \
.order_by(Delivery_Delivery.when_ordered.desc()) \
.limit(per_page_amount).offset(offset_limit)
deliveries = (db.session
.query(Delivery_Delivery)
.filter(or_(Delivery_Delivery.delivery_status == 0,
)
)
.filter(Delivery_Delivery.expected_delivery_date != date.today())
.order_by(Delivery_Delivery.when_ordered.desc())
.limit(per_page_amount).offset(offset_limit))
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/delivered/<int:page>", methods=["GET"])
def get_deliveries_delivered(page):
@delivery.route("/pending/<int:page>", methods=["GET"])
def get_deliveries_pending(page):
"""
This will get deliveries not done
"""
per_page_amount = 50
if page is None:
@@ -184,11 +291,11 @@ def get_deliveries_delivered(page):
else:
offset_limit = (per_page_amount * page) - per_page_amount
deliveries = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.delivery_status == 1) \
.order_by(Delivery_Delivery.when_ordered.desc()) \
.limit(per_page_amount).offset(offset_limit)
deliveries = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.delivery_status == 9)
.order_by(Delivery_Delivery.delivery_status.asc())
.limit(per_page_amount).offset(offset_limit))
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@@ -196,7 +303,6 @@ def get_deliveries_delivered(page):
@delivery.route("/outfordelivery/<int:page>", methods=["GET"])
def get_deliveries_outfordelivery(page):
"""
This will get deliveries not done
"""
per_page_amount = 50
if page is None:
@@ -206,15 +312,43 @@ def get_deliveries_outfordelivery(page):
else:
offset_limit = (per_page_amount * page) - per_page_amount
deliveries = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.delivery_status == 2) \
.order_by(Delivery_Delivery.when_ordered.desc()) \
.limit(per_page_amount).offset(offset_limit)
deliveries = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.delivery_status == 2)
.order_by(Delivery_Delivery.delivery_status.asc())
.limit(per_page_amount).offset(offset_limit))
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/tommorrow/<int:page>", methods=["GET"])
def get_deliveries_tommorrow(page):
"""
This will get deliveries not done
"""
tomm = date.today() + timedelta(days=1)
per_page_amount = 50
if page is None:
offset_limit = 0
elif page == 1:
offset_limit = 0
else:
offset_limit = (per_page_amount * page) - per_page_amount
deliveries = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.delivery_status == 3)
.order_by(Delivery_Delivery.id.desc())
.limit(per_page_amount).offset(offset_limit))
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/finalized/<int:page>", methods=["GET"])
def get_deliveries_finalized(page):
"""
@@ -228,11 +362,11 @@ def get_deliveries_finalized(page):
else:
offset_limit = (per_page_amount * page) - per_page_amount
deliveries = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.delivery_status == 10) \
.order_by(Delivery_Delivery.when_ordered.desc()) \
.limit(per_page_amount).offset(offset_limit)
deliveries = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.delivery_status == 10)
.order_by(Delivery_Delivery.id.desc())
.limit(per_page_amount).offset(offset_limit))
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@@ -252,16 +386,17 @@ def get_deliveries_cancelled(page):
else:
offset_limit = (per_page_amount * page) - per_page_amount
deliveries = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.delivery_status == 3) \
.order_by(Delivery_Delivery.when_ordered.desc()) \
.limit(per_page_amount).offset(offset_limit)
deliveries = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.delivery_status == 1)
.order_by(Delivery_Delivery.when_ordered.desc())
.limit(per_page_amount).offset(offset_limit))
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/partialdelivery/<int:page>", methods=["GET"])
def get_deliveries_partial(page):
"""
@@ -275,15 +410,17 @@ def get_deliveries_partial(page):
else:
offset_limit = (per_page_amount * page) - per_page_amount
deliveries = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.delivery_status == 4) \
.order_by(Delivery_Delivery.when_ordered.desc()) \
.limit(per_page_amount).offset(offset_limit)
deliveries = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.delivery_status == 4)
.order_by(Delivery_Delivery.when_ordered.desc())
.limit(per_page_amount).offset(offset_limit))
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/issue/<int:page>", methods=["GET"])
def get_deliveries_issue(page):
"""
@@ -297,149 +434,131 @@ def get_deliveries_issue(page):
else:
offset_limit = (per_page_amount * page) - per_page_amount
deliveries = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.delivery_status == 5) \
.order_by(Delivery_Delivery.when_ordered.desc()) \
.limit(per_page_amount).offset(offset_limit)
deliveries = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.delivery_status == 5)
.order_by(Delivery_Delivery.when_ordered.desc())
.limit(per_page_amount).offset(offset_limit))
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/time/today", methods=["GET"])
def get_deliveries_today():
"""
This will get today's deliveries
"""
deliveries = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.expected_delivery_date == date.today()) \
.all()
deliveries = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.delivery_status == 2)
.all())
customer_schema = Delivery_Delivery_schema(many=True)
return jsonify(customer_schema.dump(deliveries))
@delivery.route("/amount/<int:delivery_id>", methods=["GET"])
def get_deliveries_amount_total(delivery_id):
"""
This will get deliveries totals
"""
delivery_amount = db.session \
.query(Delivery_Payment) \
.filter(Delivery_Payment.delivery_id == delivery_id) \
.all()
delivery_schema = Delivery_Delivery_schema(many=False)
return jsonify(delivery_schema.dump(delivery_amount))
@delivery.route("/edit/<int:delivery_id>", methods=["POST"])
def edit_a_delivery(delivery_id):
"""
This will create a delivery using a customer id
This will edit a delivery using a delivery id.
"""
get_delivery = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.id == delivery_id) \
.first()
get_today_price = db.session \
.query(Pricing_Oil_Oil) \
.order_by(Pricing_Oil_Oil.id.desc()) \
.first()
get_customer = db.session \
.query(Customer_Customer) \
.filter(Customer_Customer.id == get_delivery.customer_id) \
.first()
data = request.json
get_delivery = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.id == delivery_id).first()
if not get_delivery:
return jsonify({"ok": False}), 200
else:
return jsonify({"ok": False, "error": "Delivery not found"}), 404
gallons_ordered = request.json["gallons_ordered"]
delivery_status = request.json["delivery_status"]
when_to_deliver = request.json["expected_delivery_date"]
dispatcher_notes_taken = request.json["dispatcher_notes_taken"]
customer_wants_fill = request.json["customer_asked_for_fill"]
card_payment = request.json["credit"]
cash_payment = request.json["cash"]
delivery_driver_id = request.json["driver_employee_id"]
# --- Fetch related data ---
get_customer = db.session.query(Customer_Customer).filter(Customer_Customer.id == get_delivery.customer_id).first()
if not get_customer:
return jsonify({"ok": False, "error": "Associated customer not found"}), 404
get_today_price = db.session.query(Pricing_Oil_Oil).order_by(Pricing_Oil_Oil.id.desc()).first()
if not get_today_price:
return jsonify({"ok": False, "error": "Pricing information not available"}), 500
get_driver = (db.session
.query(Employee_Employee)
.filter(Employee_Employee.id == delivery_driver_id)
.first())
if request.json["credit_card_id"]:
card_payment_id = request.json["credit_card_id"]
else:
card_payment_id = None
# --- Process Form Input (using .get() for safety) ---
get_delivery.gallons_ordered = data.get("gallons_ordered", get_delivery.gallons_ordered)
get_delivery.delivery_status = data.get("delivery_status", get_delivery.delivery_status)
get_delivery.expected_delivery_date = data.get("expected_delivery_date")
get_delivery.when_ordered = data.get("created_delivery_date")
get_delivery.dispatcher_notes = data.get("dispatcher_notes_taken", "")
get_delivery.payment_type = data.get("payment_type", 0)
if card_payment_id is not None:
get_card = (db.session
.query(Card_Card)
.filter(Card_Card.id == card_payment_id)
.filter(Card_Card.user_id == get_customer.id)
.first())
card_id_from_customer = get_card.id
else:
card_id_from_customer = None
if cash_payment is True and card_payment is False:
delivery_payment_method = 0
elif card_payment is True and cash_payment is False:
delivery_payment_method = 1
elif card_payment is True and cash_payment is True:
delivery_payment_method = 2
else:
delivery_payment_method = 3
if customer_wants_fill is True:
customer_wants_fill = 1
else:
customer_wants_fill = 0
same_day_info = request.json["same_day"]
if same_day_info is True:
same_day_info = 1
else:
same_day_info = 0
prime_info = request.json["prime"]
if prime_info is True:
prime_info = 1
else:
prime_info = 0
get_delivery.delivery_status = delivery_status
get_delivery.gallons_ordered = gallons_ordered
# Convert booleans to 1 or 0 for the database
customer_wants_fill = 1 if data.get("customer_asked_for_fill") else 0
get_delivery.customer_asked_for_fill = customer_wants_fill
get_delivery.expected_delivery_date = when_to_deliver
get_delivery.dispatcher_notes = dispatcher_notes_taken
get_delivery.prime = prime_info
get_delivery.same_day = same_day_info
get_delivery.gallons_ordered = gallons_ordered
get_delivery.payment_type = delivery_payment_method
get_delivery.payment_card_id = card_id_from_customer
get_delivery.prime = 1 if data.get("prime") else 0
get_delivery.same_day = 1 if data.get("same_day") else 0
get_delivery.emergency = 1 if data.get("emergency") else 0
get_delivery.driver_last_name = get_driver.employee_last_name
get_delivery.driver_first_name = get_driver.employee_first_name
# --- Handle Driver Assignment ---
driver_id = data.get("driver_employee_id")
if driver_id:
get_driver = db.session.query(Employee_Employee).filter(Employee_Employee.id == driver_id).first()
if get_driver:
get_delivery.driver_employee_id = get_driver.id
get_delivery.driver_first_name = get_driver.employee_first_name
get_delivery.driver_last_name = get_driver.employee_last_name
else:
# Optionally, handle the case where the driver ID is invalid
# For now, we'll just not update the driver info.
pass
else:
# No driver provided, set to empty values
get_delivery.driver_employee_id = 0
get_delivery.driver_first_name = ""
get_delivery.driver_last_name = ""
# --- Handle Promotion ---
promo_id = data.get("promo_id")
if promo_id and promo_id != 0:
get_promo = db.session.query(Promo_Promo).filter(Promo_Promo.id == promo_id).first()
if get_promo:
get_delivery.promo_id = get_promo.id
get_delivery.promo_money_discount = get_promo.money_off_delivery
else: # Clear promo if "No Promotion" is selected
get_delivery.promo_id = None
get_delivery.promo_money_discount = None
# --- Handle Credit Card Assignment ---
card_id = data.get("credit_card_id")
# Only assign card if payment type is Card (1) and a valid card_id is provided
if get_delivery.payment_type == 1 and card_id:
get_card = db.session.query(Card_Card).filter(Card_Card.id == card_id, Card_Card.user_id == get_customer.id).first()
if get_card:
get_delivery.payment_card_id = get_card.id
else: # Clear card if payment is not by card
get_delivery.payment_card_id = None
# --- Recalculate Pricing (This logic could be moved to a helper function) ---
gallons_for_calc = 250 if customer_wants_fill else int(get_delivery.gallons_ordered)
base_price = gallons_for_calc * get_today_price.price_for_customer
# Add fees
total_price = base_price
if get_delivery.prime:
total_price += get_today_price.price_prime
if get_delivery.same_day:
total_price += get_today_price.price_same_day
if get_delivery.emergency:
total_price += get_today_price.price_emergency
get_delivery.total_price = base_price # Price before fees
get_delivery.pre_charge_amount = total_price # Price including fees
# --- Commit Changes ---
db.session.add(get_delivery)
db.session.commit()
return jsonify({
"ok": True,
'customer': {
'user_id': get_customer.id,
},
'message': f"Delivery {delivery_id} updated successfully.",
'customer_id': get_customer.id # Keep this if the frontend uses it for navigation
}), 200
@@ -458,33 +577,76 @@ def create_a_delivery(user_id):
.order_by(Pricing_Oil_Oil.id.desc())\
.first()
get_service_prices = (db.session
.query(Pricing_Service_General)
.order_by(Pricing_Service_General.id.desc())
.first())
if not get_customer:
return jsonify({"ok": False}), 200
else:
gallons_ordered = request.json["gallons_ordered"]
customer_wants_fill = request.json["customer_asked_for_fill"]
when_to_deliver = request.json["expected_delivery_date"]
dispatcher_notes_taken = request.json["dispatcher_notes_taken"]
prime_info = request.json["prime"]
same_day_info = request.json["same_day"]
emergency_info = request.json["emergency"]
delivery_driver_id = request.json.get("driver_employee_id", 0)
card_payment = request.json["credit"]
cash_payment = request.json["cash"]
check_payment = request.json["check"]
other_payment = request.json["other"]
delivery_driver_id = request.json["driver_employee_id"]
## promo
try:
if request.json["promo_id"]:
promo_id = request.json["promo_id"]
else:
promo_id = None
except:
promo_id = None
if promo_id is not None:
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
.first())
promo_id_get_delivery =get_promo_data.id,
promo_money_discount_get_delivery = get_promo_data.money_off_delivery
else:
promo_id_get_delivery =None
promo_money_discount_get_delivery = None
# 0 = cash only
# 1 = CC - Tiger (Physical)
# 11 = CC - Authorize (API)
# 2 = credit /cash
# 3 = check
# 4 = other
if cash_payment is True:
delivery_payment_method = 0
elif card_payment is True:
delivery_payment_method = 1 # Default to Tiger physical machine
elif check_payment is True:
delivery_payment_method = 3
elif other_payment is True:
delivery_payment_method = 4
else:
delivery_payment_method = 5
if delivery_driver_id:
get_driver = (db.session
.query(Employee_Employee)
.filter(Employee_Employee.id == delivery_driver_id)
.first())
driver_l_name = get_driver.employee_last_name
driver_f_name = get_driver.employee_first_name
driver_emp_id = get_driver.id
else:
driver_l_name = ""
driver_f_name = ""
driver_emp_id = 0
try:
if request.json["credit_card_id"]:
@@ -504,21 +666,19 @@ def create_a_delivery(user_id):
else:
card_id_from_customer = None
if cash_payment is True and card_payment is False:
delivery_payment_method = 0
elif card_payment is True and cash_payment is False:
delivery_payment_method = 1
elif card_payment is True and cash_payment is True:
delivery_payment_method = 2
else:
delivery_payment_method = 3
if customer_wants_fill is True:
customer_fill_up = 1
gallons_ordered = 250
else:
customer_fill_up = 0
gallons_ordered = request.json["gallons_ordered"]
if emergency_info is True:
emergency_asked = 1
else:
emergency_asked = 0
if prime_info is True:
prime_asked = 1
@@ -530,24 +690,31 @@ def create_a_delivery(user_id):
else:
same_day_asked = 0
date_object = datetime.strptime(when_to_deliver, '%Y-%m-%d').date()
customer_filled_name = get_customer.customer_last_name + ' ' + get_customer.customer_first_name
customer_filled_name = get_customer.customer_first_name + ' ' + get_customer.customer_last_name
now = datetime.utcnow()
# Pricing
if customer_fill_up == 1:
# Fill
precharge_amount = (250 * get_today_price.price_for_customer)
else:
# Gallons
precharge_amount = int(gallons_ordered) * get_today_price.price_for_customer
# if prime/emergency/sameday
if same_day_asked == 1 and prime_asked == 0:
total_precharge_amount = precharge_amount + get_today_price.price_same_day
elif prime_asked == 1 and same_day_asked == 0:
total_precharge_amount = precharge_amount + get_today_price.price_prime
elif emergency_asked == 1:
total_precharge_amount = precharge_amount + get_today_price.price_emergency
else:
total_precharge_amount = precharge_amount + get_today_price.price_prime + get_today_price.price_same_day
@@ -566,8 +733,9 @@ def create_a_delivery(user_id):
delivery_status=0,
when_ordered=now,
when_delivered=None,
expected_delivery_date=date_object,
expected_delivery_date=when_to_deliver,
automatic=get_customer.customer_automatic,
automatic_id=None,
oil_id=get_today_price.id,
supplier_price=get_today_price.price_from_supplier,
customer_price=get_today_price.price_for_customer,
@@ -575,6 +743,7 @@ def create_a_delivery(user_id):
dispatcher_notes=dispatcher_notes_taken,
prime=prime_asked,
same_day=same_day_asked,
emergency=emergency_asked,
payment_type=delivery_payment_method,
payment_card_id=card_id_from_customer,
pre_charge_amount=total_precharge_amount,
@@ -583,9 +752,22 @@ def create_a_delivery(user_id):
driver_last_name=driver_l_name,
driver_first_name=driver_f_name,
driver_employee_id=driver_emp_id,
promo_id=promo_id_get_delivery,
promo_money_discount=promo_money_discount_get_delivery
)
get_stats_customer = (db.session
.query(Stats_Customer)
.filter(Stats_Customer.customer_id == get_customer.id)
.first())
new_calls = int(get_stats_customer.total_calls) + 1
get_stats_customer.total_calls = new_calls
db.session.add(get_stats_customer)
db.session.add(new_delivery)
db.session.commit()
@@ -606,7 +788,7 @@ def cancel_a_delivery(delivery_id):
.filter(Delivery_Delivery.id == delivery_id)\
.first()
get_delivery.delivery_status = 3
get_delivery.delivery_status = 1
db.session.add(get_delivery)
db.session.commit()
@@ -671,15 +853,15 @@ def delivery_note_driver(delivery_id):
driver_notes = request.json["driver_notes"]
now = datetime.utcnow()
user = db.session\
.query(Auth_User)\
.filter(Auth_User.id == current_user.id)\
.first()
user = (db.session
.query(Auth_User)
.filter(Auth_User.id == current_user.id)
.first())
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())
create_new_note = Delivery_Notes_Driver(
delivery_id=get_delivery.id,
@@ -696,7 +878,7 @@ def delivery_note_driver(delivery_id):
@delivery.route("/delete/<int:delivery_id>", methods=["DELETE"])
def service_delete_call(delivery_id):
def delete_call(delivery_id):
"""
delete a delivery call
"""
@@ -708,3 +890,76 @@ def service_delete_call(delivery_id):
db.session.commit()
return jsonify({"ok": True}), 200
@delivery.route("/total/<int:delivery_id>", methods=["GET"])
def calculate_total(delivery_id):
"""
This will get deliveries not done
"""
get_delivery = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.id == delivery_id)
.first())
# Use gallons_delivered if available and > 0, otherwise use gallons_ordered
gallons = get_delivery.gallons_delivered if get_delivery.gallons_delivered and get_delivery.gallons_delivered > 0 else get_delivery.gallons_ordered
if get_delivery.promo_id:
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == get_delivery.promo_id)
.first())
discount_gallon_price = get_delivery.customer_price - get_promo_data.money_off_delivery
total_amount_after_discount = (gallons * discount_gallon_price)
discount = (gallons * get_delivery.customer_price) - total_amount_after_discount
else:
discount = 0
total_amount_after_discount = gallons * get_delivery.customer_price
get_price_query = (db.session
.query(Pricing_Oil_Oil)
.order_by(Pricing_Oil_Oil.date.desc())
.first())
if get_delivery.prime == 1:
priceprime = float(get_price_query.price_prime)
else:
priceprime = 0
if get_delivery.emergency == 1:
priceemergency = float(get_price_query.price_emergency)
else:
priceemergency = 0
if get_delivery.same_day == 1:
pricesameday = float(get_price_query.price_same_day)
else:
pricesameday = 0
# Recalculate base price using actual gallons
base_price = gallons * get_delivery.customer_price
total = float(base_price) + float(priceprime) + float(pricesameday) + float(priceemergency)
priceprime = round(priceprime, 2)
pricesameday = round(pricesameday, 2)
priceemergency = round(priceemergency, 2)
total_amount_after_discount = round(total_amount_after_discount, 2)
discount = round(discount, 2)
total = round(total, 2)
return jsonify({
"ok": True,
'priceprime': priceprime,
'pricesameday': pricesameday,
'priceemergency': priceemergency,
'total_amount':total,
'discount': discount,
'total_amount_after_discount':total_amount_after_discount,
}), 200

0
app/delivery_data/__init__.py Normal file → Executable file
View File

207
app/delivery_data/views.py Normal file → Executable file
View File

@@ -1,123 +1,160 @@
from flask import request, jsonify
from flask_login import current_user
from datetime import date
from datetime import datetime
from decimal import Decimal
from app.delivery_data import delivery_data
from app import db
from datetime import datetime
from app.classes.customer import Customer_Customer
from app.classes.delivery import (Delivery_Delivery,
Delivery_Delivery_schema,
Delivery_Notes_Driver,
Delivery_Payment,
Delivery_Payment_schema,
)
from app.classes.customer import Customer_Customer, Customer_Description
from app.classes.delivery import Delivery_Delivery
from app.classes.employee import Employee_Employee
from app.classes.cards import Card_Card
from app.classes.pricing import Pricing_Oil_Oil
from app.classes.auth import Auth_User
from app.classes.pricing import Pricing_Service_General
@delivery_data.route("/pending", methods=["GET"])
def pending_delivery():
"""
Get deliveries that have been delivered
"""
delivery_ticket = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.delivery_status!=0)
.all())
delivery_schema = Delivery_Delivery_schema(many=True)
return jsonify(delivery_schema.dump(delivery_ticket))
from app.classes.stats_employee import Stats_Employee_Oil
from app.classes.auto import Auto_Delivery
from app.classes.stats_customer import Stats_Customer
@delivery_data.route("/finalize/<int:delivery_id>", methods=["PUT"])
def finalize_delivery(delivery_id):
def office_finalize_delivery(delivery_id):
"""
Get deliveries that have been delivered
This will make a delivery finalized from the driver
"""
"""
Finalizes a delivery from office
"""
now = datetime.utcnow()
get_delivery = db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.id == delivery_id) \
.first()
get_today_price = db.session \
.query(Pricing_Oil_Oil) \
.order_by(Pricing_Oil_Oil.id.desc()) \
.first()
get_customer = db.session \
.query(Customer_Customer) \
.filter(Customer_Customer.id == get_delivery.customer_id) \
.first()
get_customer_description = db.session \
.query(Customer_Description) \
.filter(Customer_Description.customer_id == get_delivery.customer_id) \
.first()
if get_customer_description is None:
new_customer_desc = Customer_Description(
customer_id = get_customer.id,
account_number =get_customer.account_number,
company_id = get_customer.company_id,
fill_location = None,
description = None,
)
db.session.add(new_customer_desc)
db.session.flush()
get_customer_description = db.session \
.query(Customer_Description) \
.filter(Customer_Description.customer_id == get_delivery.customer_id) \
.first()
#TODO hardcode for now
delivery_driver_id = 2
get_driver = (db.session
.query(Employee_Employee)
.filter(Employee_Employee.id == delivery_driver_id)
.first())
get_stats_employee = (db.session
.query(Stats_Employee_Oil)
.filter(Stats_Employee_Oil.employee_id == get_delivery.driver_employee_id)
.first())
get_stats_customer = (db.session
.query(Stats_Customer)
.filter(Stats_Customer.customer_id == get_customer.id)
.first())
if get_stats_customer is None:
create_stats_customer = Stats_Customer(
customer_id = get_customer.id,
total_calls = 1,
service_calls_total = 0,
service_calls_total_spent = 0,
service_calls_total_profit = 0,
oil_deliveries = 1,
oil_total_gallons = 0,
oil_total_spent = 0,
oil_total_profit = 0,
)
db.session.add(create_stats_customer)
db.session.flush()
get_stats_customer = (db.session
.query(Stats_Customer)
.filter(Stats_Customer.customer_id == get_customer.id)
.first())
if get_stats_employee is None:
create_stats = Stats_Employee_Oil(
employee_id = get_delivery.driver_employee_id,
total_deliveries = 0,
total_gallons_delivered = 0,
total_primes = 0,
oil_total_profit_delivered = 0,
)
db.session.add(create_stats)
db.session.flush()
get_stats_employee = (db.session
.query(Stats_Employee_Oil)
.filter(Stats_Employee_Oil.employee_id == get_delivery.driver_employee_id)
.first())
if request.json["cash_recieved"]:
cash_amount = request.json["cash_recieved"]
else:
cash_amount = None
gallons_delivered = request.json["gallons_delivered"]
card_payment = request.json["credit"]
cash_payment = request.json["cash"]
if request.json["credit_card_id"]:
card_payment_id = request.json["credit_card_id"]
else:
card_payment_id = None
check_number = request.json["check_number"]
fill_location = request.json["fill_location"]
if card_payment_id is not None:
get_card = (db.session
.query(Card_Card)
.filter(Card_Card.id == card_payment_id)
.filter(Card_Card.user_id == get_customer.id)
.first())
card_id_from_customer = get_card.id
else:
card_id_from_customer = None
if cash_payment is True and card_payment is False:
delivery_payment_method = 0
elif card_payment is True and cash_payment is False:
delivery_payment_method = 1
elif card_payment is True and cash_payment is True:
delivery_payment_method = 2
else:
delivery_payment_method = 3
same_day_info = request.json["same_day"]
if same_day_info is True:
same_day_info = 1
else:
same_day_info = 0
prime_info = request.json["prime"]
if prime_info is True:
prime_info = 1
else:
prime_info = 0
# update driver
get_delivery.driver_last_name = get_driver.employee_last_name
get_delivery.driver_first_name = get_driver.employee_first_name
get_delivery.driver_employee_id = get_driver.id
# update delivery
get_delivery.when_delivered = now
get_delivery.gallons_delivered = gallons_delivered
get_delivery.prime = prime_info
get_delivery.same_day = same_day_info
get_delivery.payment_type = delivery_payment_method
get_delivery.payment_card_id = card_id_from_customer
get_delivery.cash_recieved = cash_amount
get_delivery.check_number = check_number
get_delivery.delivery_status = 10
# update stats employee
current_deliveres = get_stats_employee.total_deliveries + 1
get_stats_employee.total_deliveries = current_deliveres
current_gallons_delivered = Decimal(get_stats_employee.total_gallons_delivered) + Decimal(gallons_delivered)
get_stats_employee.total_gallons_delivered = current_gallons_delivered
# update stats customer
current_deliveres = int(get_stats_customer.oil_deliveries) + 1
get_stats_customer.oil_deliveries = current_deliveres
new_gallons = Decimal(get_stats_customer.oil_total_gallons) + Decimal(gallons_delivered)
get_stats_customer.oil_total_gallons = new_gallons
# update fill location
get_customer_description.fill_location = fill_location
db.session.add(get_customer_description)
db.session.add(get_stats_customer)
db.session.add(get_stats_employee)
db.session.add(get_delivery)
db.session.commit()
return jsonify({
"ok": True,
'delivery': {
'id': get_delivery.id,
},
}), 200

0
app/delivery_status/__init__.py Normal file → Executable file
View File

99
app/delivery_status/views.py Normal file → Executable file
View File

@@ -1,62 +1,67 @@
from flask import request, jsonify
from flask_login import current_user
from datetime import date, timedelta, time
from flask import jsonify
from datetime import date, timedelta
from app.delivery_status import deliverystatus
from app import db
from datetime import datetime
from app.classes.customer import Customer_Customer
from app.classes.delivery import (Delivery_Delivery,
Delivery_Delivery_schema,
Delivery_Notes_Driver,
Delivery_Payment,
Delivery_Payment_schema,
)
from app.classes.cards import Card_Card
from app.classes.pricing import Pricing_Oil_Oil
from app.classes.auth import Auth_User
from app.classes.pricing import Pricing_Service_General
from app.classes.service import Service_Service
from app.classes.auto import Auto_Delivery
from app.classes.transactions import Transaction
from datetime import date, timedelta, datetime
from zoneinfo import ZoneInfo
@deliverystatus.route("/today/driver/<int:user_id>", methods=["GET"])
def get_deliveries_driver_day(user_id):
# --- NEW EFFICIENT ENDPOINT ---
@deliverystatus.route("/stats/sidebar-counts", methods=["GET"])
def get_sidebar_counts():
"""
Get deliveries for driver that day
Efficiently gets all counts needed for the navigation sidebar in a single request.
This combines logic from all the individual /count/* endpoints.
"""
get_delivery = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.driver_employee_id == user_id)
.filter(Delivery_Delivery.expected_delivery_date == date.today())
.all())
try:
eastern = ZoneInfo("America/New_York")
now_local = datetime.now(eastern).replace(tzinfo=None) # naive local time
today_date = datetime.now(eastern).date() # local date
delivery_schema = Delivery_Delivery_schema(many=True)
return jsonify(delivery_schema.dump(get_delivery))
# Replicate the logic from each of your /count/* endpoints
today_count = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.delivery_status == 2).count()
@deliverystatus.route("/tommorrow/driver/<int:user_id>", methods=["GET"])
def get_deliveries_driver_tommorrow(user_id):
"""
Get deliveries for driver tommrrow
"""
tomm = datetime.now() + timedelta(days=1)
tomorrow_count = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.delivery_status == 3).count()
get_delivery = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.driver_employee_id == user_id)
.filter(Delivery_Delivery.expected_delivery_date == tomm)
.all())
waiting_count = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.delivery_status == 0).count()
delivery_schema = Delivery_Delivery_schema(many=True)
return jsonify(delivery_schema.dump(get_delivery))
pending_count = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.delivery_status == 9).count()
@deliverystatus.route("/waiting/driver/<int:user_id>", methods=["GET"])
def get_deliveries_driver_waiting(user_id):
"""
waiting deliveries scheduled out
"""
get_delivery = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.driver_employee_id == user_id)
.filter(Delivery_Delivery.delivery_status == 1)
.all())
automatic_count = db.session.query(Auto_Delivery).filter(Auto_Delivery.estimated_gallons_left <= 80).count()
delivery_schema = Delivery_Delivery_schema(many=True)
return jsonify(delivery_schema.dump(get_delivery))
start_of_today = datetime.combine(today_date, datetime.min.time())
start_of_tomorrow = datetime.combine(today_date + timedelta(days=1), datetime.min.time())
today_service_count = db.session.query(Service_Service).filter(
Service_Service.scheduled_date >= start_of_today,
Service_Service.scheduled_date < start_of_tomorrow
).count()
# Upcoming service calls start from tomorrow, not today
upcoming_service_count = db.session.query(Service_Service).filter(Service_Service.scheduled_date >= start_of_tomorrow).count()
transaction_count = db.session.query(Transaction).filter(Transaction.transaction_type == 0).count()
return jsonify({
"ok": True,
"counts": {
"today": today_count,
"tomorrow": tomorrow_count,
"waiting": waiting_count,
"pending": pending_count,
"automatic": automatic_count,
"upcoming_service": upcoming_service_count,
"today_service": today_service_count,
"transaction": transaction_count,
}
}), 200
except Exception as e:
# Basic error handling
return jsonify({"ok": False, "error": str(e)}), 500

0
app/employees/__init__.py Normal file → Executable file
View File

57
app/employees/views.py Normal file → Executable file
View File

@@ -1,21 +1,39 @@
from flask import request, jsonify
from flask_login import current_user
from sqlalchemy import or_
from datetime import date, timedelta
from flask_login import login_required
from app.employees import employees
from app import db
from datetime import datetime
from app.classes.employee import Employee_Employee, Employee_Employee_schema
from app.classes.auth import Auth_User
from app.classes.stats_employee import Stats_Employee_Oil, Stats_Employee_Office
@employees.route("/<int:userid>", methods=["GET"])
@login_required
def get_specific_employee(userid):
print(userid)
employee = db.session \
.query(Employee_Employee) \
.filter(Employee_Employee.id == userid) \
.filter(Employee_Employee.user_id == userid) \
.first()
# Get active status from Auth_User
user = db.session.query(Auth_User).filter(Auth_User.id == userid).first()
active_status = user.active if user else 1
employee_schema = Employee_Employee_schema(many=False)
employee_data = employee_schema.dump(employee)
employee_data['active'] = active_status
return jsonify(employee_data)
@employees.route("/byid/<int:employee_id>", methods=["GET"])
@login_required
def get_employee_by_id(employee_id):
employee = db.session \
.query(Employee_Employee) \
.filter(Employee_Employee.id == employee_id) \
.first()
employee_schema = Employee_Employee_schema(many=False)
return jsonify(employee_schema.dump(employee))
@@ -132,8 +150,25 @@ def employee_create():
employee_phone_number=e_phone_number,
)
db.session.add(new_employee)
db.session.commit()
db.session.flush()
new_stats_office = Stats_Employee_Office(
employee_id = new_employee.id,
total_orders = 0,
total_credit_cards_proccessed = 0,
)
db.session.add(new_stats_office)
new_stats_oil = Stats_Employee_Oil(
employee_id = new_employee.id,
total_deliveries = 0,
total_gallons_delivered = 0,
total_primes = 0,
oil_total_profit_delivered = 0,
)
db.session.add(new_stats_oil)
return jsonify({"ok": True,
'user_id': new_employee.id,
@@ -154,7 +189,7 @@ def employee_edit(employee_id):
e_type = request.json["employee_type"]
e_start_date = request.json["employee_start_date"]
e_end_date = request.json["employee_end_date"]
e_active = request.json.get("active", 1)
get_employee = db.session \
.query(Employee_Employee) \
@@ -172,6 +207,12 @@ def employee_edit(employee_id):
if e_end_date != 'None':
get_employee.employee_end_date = e_end_date
# Update active status in Auth_User
user = db.session.query(Auth_User).filter(Auth_User.id == get_employee.user_id).first()
if user:
user.active = int(e_active)
db.session.add(user)
db.session.add(get_employee)
db.session.commit()

0
app/info/__init__.py Normal file → Executable file
View File

59
app/info/views.py Normal file → Executable file
View File

@@ -1,36 +1,65 @@
from flask import jsonify
from decimal import Decimal
from app.info import info
from app import db
from app.classes.pricing import Pricing_Oil_Oil, Pricing_Service_General
from app.classes.pricing import Pricing_Oil_Oil, Pricing_Oil_Oil_schema
from app.classes.admin import Admin_Company
from app.classes.delivery import Delivery_Delivery
from app.classes.service import Service_Service
@info.route("/price/oil/tiers", methods=["GET"])
def get_pricing_tiers():
get_price_query = (db.session
.query(Pricing_Oil_Oil)
.order_by(Pricing_Oil_Oil.date.desc())
.first())
if not get_price_query:
return jsonify({"error": "No pricing data available"}), 404
# Get the single price per gallon from the database, e.g., Decimal('2.92')
price_per_gallon = get_price_query.price_for_customer
# Define the specific gallon amounts you want to display totals for
gallon_tiers = [100, 125, 150, 175, 200, 220]
# Calculate the total price for each gallon amount by multiplication
pricing_totals = {
gallons: price_per_gallon * gallons
for gallons in gallon_tiers
}
# Return the dictionary of totals
return jsonify(pricing_totals)
@info.route("/price/oil", methods=["GET"])
def get_oil_price():
def get_oil_price_today():
get_price_query = (db.session
.query(Pricing_Oil_Oil)
.order_by(Pricing_Oil_Oil.date.desc())
.first())
return jsonify({"ok": True,
'price': get_price_query.price_for_customer,
'price_from_supplier': get_price_query.price_from_supplier,
'price_for_customer': get_price_query.price_for_customer,
'price_for_employee': get_price_query.price_for_employee,
'price_same_day': get_price_query.price_same_day,
'price_prime': get_price_query.price_prime,
'price_emergency': get_price_query.price_emergency,
}), 200
@info.route("/price/service", methods=["GET"])
def get_service_price():
@info.route("/price/oil/table", methods=["GET"])
def get_pricing():
get_price_query = (db.session
.query(Pricing_Service_General)
.order_by(Pricing_Service_General.date.desc())
.query(Pricing_Oil_Oil)
.order_by(Pricing_Oil_Oil.date.desc())
.first())
delivery_schema = Pricing_Oil_Oil_schema(many=False)
return jsonify(delivery_schema.dump(get_price_query))
return jsonify({"ok": True,
'price_hourly': get_price_query.price_service_hour,
'emergency_fee': get_price_query.price_emergency_call,
'emergency_rate': get_price_query.price_emergency_service_hour,
'prime': get_price_query.price_prime,
'cleaning': get_price_query.price_cleaning,
'out_of_oil': get_price_query.price_out_of_oil,
}), 200
@info.route("/company", methods=["GET"])

0
app/main/__init__.py Normal file → Executable file
View File

6
app/main/views.py Normal file → Executable file
View File

@@ -1,6 +1,10 @@
from flask import jsonify, Response
from flask import jsonify, Response, url_for
from app import app
@app.route("/favicon.ico")
def favicon():
return url_for('static', filename='data:,')
@app.route('/robots.txt')
@app.route('/sitemap.xml')

8
app/money/__init__.py Normal file
View File

@@ -0,0 +1,8 @@
# coding=utf-8
from flask import Blueprint
money = Blueprint('money', __name__)
from . import views

83
app/money/views.py Normal file
View File

@@ -0,0 +1,83 @@
from flask import jsonify
from app.money import money
from app import db
import datetime
from datetime import date
from app.classes.money import Money_delivery, Money_delivery_schema
from app.classes.delivery import Delivery_Delivery, Delivery_Delivery_schema
def get_monday_date(date_object):
"""Gets the date of the Monday for the given date."""
# Get the day of the week as an integer (0 = Monday, 6 = Sunday)
day_of_week = date_object.weekday()
# Calculate the number of days to subtract to get to Monday
days_to_monday = day_of_week - 0 # Monday is 0
# Subtract the days from the given date to get Monday's date
monday_date = date_object - datetime.timedelta(days=days_to_monday)
return monday_date
@money.route("/profit/week", methods=["GET"])
def total_profit_week():
# Get today's date
total_profit = 0
total_deliveries = 0
today = datetime.date.today()
# Get the date of the Monday for today
monday = get_monday_date(today)
get_total = (db.session
.query(Money_delivery)
.filter(Money_delivery.time_added >= monday)
.filter(Money_delivery.time_added <= today)
.all())
for f in get_total:
total_profit = total_profit + f.total_profit
total_deliveries = total_deliveries + 1
return jsonify({"ok": True,
'total_profit': total_profit,
'total_deliveries': total_deliveries
}), 200
@money.route("/profit/year", methods=["GET"])
def total_profit_year():
# Get today's date
total_profit = 0
first_of_year = date(date.today().year, 1, 1)
last_of_year = date(date.today().year, 12, 31)
# Get the date of the Monday for today
get_total = (db.session
.query(Money_delivery)
.filter(Money_delivery.time_added >= first_of_year)
.filter(Money_delivery.time_added <= last_of_year)
.all())
for f in get_total:
total_profit = total_profit + f.total_profit
return jsonify({"ok": True,
'total': total_profit
}), 200
@money.route("/<int:delivery_id>", methods=["GET"])
def get_money_delivery(delivery_id):
"""
"""
profit = (db.session
.query(Money_delivery)
.filter(Money_delivery.delivery_id == delivery_id)
.first())
money_schema = Money_delivery_schema(many=False)
return jsonify(money_schema.dump(profit))

0
app/payment/__init__.py Normal file → Executable file
View File

580
app/payment/views.py Normal file → Executable file
View File

@@ -3,27 +3,52 @@ from app.payment import payment
from app import db
from app.classes.customer import Customer_Customer
from app.classes.cards import Card_Card, Card_Card_schema
from flask_login import current_user
from app.classes.transactions import Transaction
from app.classes.delivery import Delivery_Delivery
from app.classes.service import Service_Service, Service_Service_schema
def set_card_main(user_id):
def set_card_main(user_id, card_id):
"""
updates a card of a user
"""
get_card_count = db.session \
.query(Card_Card) \
.filter(Card_Card.user_id == user_id) \
get_card_count = (
db.session
.query(Card_Card)
.filter(Card_Card.user_id == user_id)
.count()
if get_card_count > 0:
get_old_card = db.session \
.query(Card_Card) \
.filter(Card_Card.main_card == True) \
.filter(Card_Card.user_id == user_id) \
)
get_card = (
db.session
.query(Card_Card)
.filter(Card_Card.user_id == user_id)
.filter(Card_Card.id == card_id)
.first()
)
if get_card_count > 0:
get_old_card = (
db.session
.query(Card_Card)
.filter(Card_Card.main_card == True)
.filter(Card_Card.user_id == user_id)
.first()
)
get_old_card.main_card = False
get_card.main_card = True
db.session.add(get_old_card)
db.session.commit()
else:
get_card.main_card = True
db.session.add(get_card)
db.session.commit()
@payment.route("/cards/<int:user_id>", methods=["GET"])
@@ -31,10 +56,10 @@ def get_user_cards(user_id):
"""
gets all cards of a user
"""
get_u_cards = db.session \
.query(Card_Card) \
.filter(Card_Card.user_id == user_id) \
.all()
get_u_cards = (db.session
.query(Card_Card)
.filter(Card_Card.user_id == user_id)
.all())
card_schema = Card_Card_schema(many=True)
return jsonify(card_schema.dump(get_u_cards))
@@ -46,10 +71,10 @@ def get_user_cards_count(user_id):
gets all cards of a user
"""
get_u_cards = db.session \
.query(Card_Card) \
.filter(Card_Card.user_id == user_id) \
.count()
get_u_cards = (db.session
.query(Card_Card)
.filter(Card_Card.user_id == user_id)
.count())
return jsonify({
"ok": True,
@@ -63,56 +88,15 @@ def get_user_specific_card(card_id):
gets a specific card of a user
"""
get_user_card = db.session \
.query(Card_Card) \
.filter(Card_Card.id == card_id) \
.first()
get_user_card = (db.session
.query(Card_Card)
.filter(Card_Card.id == card_id)
.first())
card_schema = Card_Card_schema(many=False)
return jsonify(card_schema.dump(get_user_card))
@payment.route("/card/create/<int:user_id>", methods=["POST"])
def create_user_card(user_id):
"""
adds a card of a user
"""
get_customer = db.session \
.query(Customer_Customer) \
.filter(Customer_Customer.id == user_id) \
.first()
name_on_card = request.json["card_name"]
expiration_month = request.json["expiration_month"]
expiration_year = request.json["expiration_year"]
type_of_card = request.json["type_of_card"]
security_number = request.json["security_number"]
main_card = request.json["main_card"]
card_number = request.json["card_number"]
last_four = card_number[-4]
create_new_card = Card_Card(
user_id=get_customer.id,
card_number=card_number,
last_four_digits=last_four,
name_on_card=name_on_card,
expiration_month=expiration_month,
expiration_year=expiration_year,
type_of_card=type_of_card,
security_number=security_number,
accepted_or_declined=None,
main_card=main_card,
)
print(main_card)
if main_card is True:
set_card_main(user_id=get_customer.id)
db.session.add(create_new_card)
db.session.commit()
return jsonify({"ok": True}), 200
@payment.route("/card/main/<int:card_id>/<int:user_id>", methods=["PUT"])
def set_main_card(user_id, card_id):
@@ -120,17 +104,18 @@ def set_main_card(user_id, card_id):
updates a card of a user
"""
get_new_main_card = db.session \
.query(Card_Card) \
.filter(Card_Card.user_id == user_id) \
.filter(Card_Card.id == card_id) \
.first()
get_new_main_card = (db.session
.query(Card_Card)
.filter(Card_Card.user_id == user_id)
.filter(Card_Card.id == card_id)
.first())
get_other_card = (db.session
.query(Card_Card)
.filter(Card_Card.main_card == True)
.filter(Card_Card.user_id == user_id)
.first())
get_other_card = db.session \
.query(Card_Card) \
.filter(Card_Card.main_card == True) \
.filter(Card_Card.user_id == user_id) \
.first()
if get_other_card is not None:
get_other_card.main_card = False
db.session.add(get_other_card)
@@ -142,45 +127,6 @@ def set_main_card(user_id, card_id):
return jsonify({"ok": True}), 200
@payment.route("/card/edit/<int:card_id>", methods=["PUT"])
def update_user_card(card_id):
"""
edits a card
"""
get_card = db.session \
.query(Card_Card) \
.filter(Card_Card.id == card_id) \
.first()
get_customer = db.session \
.query(Customer_Customer) \
.filter(Customer_Customer.id == get_card.user_id) \
.first()
name_on_card = request.json["card_name"]
expiration_month = request.json["expiration_month"]
expiration_year = request.json["expiration_year"]
type_of_card = request.json["type_of_card"]
security_number = request.json["security_number"]
card_number = request.json["card_number"]
main_card = request.json["main_card"]
get_card.user_id = get_customer.id
get_card.card_number = card_number
get_card.name_on_card = name_on_card
get_card.expiration_month = expiration_month
get_card.expiration_year = expiration_year
get_card.type_of_card = type_of_card
get_card.security_number = security_number
get_card.main_card = main_card
if main_card is True:
set_card_main(user_id=get_customer.id, card_id=get_card.id)
db.session.add(get_card)
db.session.commit()
return jsonify({"ok": True}), 200
@payment.route("/card/remove/<int:card_id>", methods=["DELETE"])
@@ -189,12 +135,414 @@ def remove_user_card(card_id):
removes a card
"""
get_card = db.session \
.query(Card_Card) \
.filter(Card_Card.id == card_id) \
.first()
get_card = (db.session
.query(Card_Card)
.filter(Card_Card.id == card_id)
.first())
db.session.delete(get_card)
db.session.commit()
return jsonify({"ok": True}), 200
# In your Flask payment routes file (e.g., app/routes/payment.py)
# ... (your existing imports: jsonify, request, db, Customer_Customer, Card_Card) ...
@payment.route("/card/create/<int:user_id>", methods=["POST"])
def create_user_card(user_id):
"""
Adds a card for a user to the local database. This is its only job.
"""
get_customer = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.id == user_id)
.first())
if not get_customer:
return jsonify({"ok": False, "error": "Customer not found"}), 404
data = request.get_json()
name_on_card = data.get("name_on_card")
expiration_month = data.get("expiration_month")
expiration_year = data.get("expiration_year")
type_of_card = data.get("type_of_card")
security_number = data.get("security_number")
main_card = data.get("main_card", False)
zip_code = data.get("zip_code")
card_number = data.get("card_number")
last_four = card_number[-4:] if card_number else ""
try:
create_new_card = Card_Card(
user_id=get_customer.id,
card_number=card_number,
last_four_digits=last_four,
name_on_card=name_on_card,
expiration_month=expiration_month,
expiration_year=expiration_year,
type_of_card=type_of_card,
security_number=security_number,
accepted_or_declined=None, # This is correct, as we don't know the status yet
main_card=main_card,
zip_code=zip_code
)
db.session.add(create_new_card)
db.session.flush()
if main_card:
# Assuming set_card_main is another function you have
set_card_main(user_id=get_customer.id, card_id=create_new_card.id)
db.session.commit()
print(f"SUCCESS: Card saved locally for user {user_id} with new ID {create_new_card.id}")
except Exception as e:
db.session.rollback()
print(f"DATABASE ERROR: Could not save card for user {user_id}. Error: {e}")
return jsonify({"ok": False, "error": "Failed to save card information."}), 500
# Return a success response with the card_id
return jsonify({"ok": True, "card_id": create_new_card.id}), 200
@payment.route("/card/update_payment_profile/<int:card_id>", methods=["PUT"])
def update_card_payment_profile(card_id):
"""
Updates the auth_net_payment_profile_id for a card
"""
get_card = (db.session
.query(Card_Card)
.filter(Card_Card.id == card_id)
.first())
if not get_card:
return jsonify({"ok": False, "error": "Card not found"}), 404
data = request.get_json()
auth_net_payment_profile_id = data.get("auth_net_payment_profile_id")
get_card.auth_net_payment_profile_id = auth_net_payment_profile_id
db.session.add(get_card)
db.session.commit()
return jsonify({"ok": True}), 200
@payment.route("/card/edit/<int:card_id>", methods=["PUT"])
def update_user_card(card_id):
"""
edits a card
"""
get_card = (db.session
.query(Card_Card)
.filter(Card_Card.id == card_id)
.first())
if not get_card:
return jsonify({"ok": False, "error": "Card not found"}), 404
data = request.get_json()
# FIX: Use .get() for safety and get the correct key 'name_on_card'
name_on_card = data.get("name_on_card") # <-- This now matches the frontend
expiration_month = data.get("expiration_month")
expiration_year = data.get("expiration_year")
type_of_card = data.get("type_of_card")
security_number = data.get("security_number")
card_number = data.get("card_number")
main_card = data.get("main_card", False)
zip_code = data.get("zip_code")
auth_net_payment_profile_id = data.get("auth_net_payment_profile_id")
get_card.card_number = card_number
get_card.name_on_card = name_on_card
get_card.expiration_month = expiration_month
get_card.expiration_year = expiration_year
get_card.type_of_card = type_of_card
get_card.security_number = security_number
get_card.main_card = main_card
get_card.zip_code = zip_code
get_card.auth_net_payment_profile_id = auth_net_payment_profile_id
# FIX: Correctly slice the last four digits on edit
if card_number and card_number[-4:].isdigit():
get_card.last_four_digits = int(card_number[-4:])
if main_card:
set_card_main(user_id=get_card.user_id, card_id=get_card.id)
db.session.add(get_card)
db.session.commit()
return jsonify({"ok": True}), 200
@payment.route("/transactions/authorize/<int:page>", methods=["GET"])
def get_authorize_transactions(page):
"""
Gets transactions with transaction_type = 0 (charge), for the authorize page
"""
try:
per_page = 50
offset = (page - 1) * per_page
query = (
db.session
.query(Transaction, Customer_Customer)
.join(Customer_Customer, Transaction.customer_id == Customer_Customer.id)
.order_by(Transaction.created_at.desc())
.offset(offset)
.limit(per_page)
)
results = query.all()
transactions_data = []
for transaction, customer in results:
transactions_data.append({
"id": transaction.id,
"preauthorize_amount": transaction.preauthorize_amount,
"charge_amount": transaction.charge_amount,
"transaction_type": transaction.transaction_type,
"status": transaction.status,
"customer_name": f"{customer.customer_first_name} {customer.customer_last_name}",
"created_at": transaction.created_at.isoformat(),
"auth_net_transaction_id": transaction.auth_net_transaction_id,
"rejection_reason": transaction.rejection_reason,
"delivery_id": transaction.delivery_id,
"service_id": transaction.service_id,
"auto_id": transaction.auto_id,
})
return jsonify(transactions_data), 200
except Exception as e:
return jsonify({"ok": False, "error": str(e)}), 500
@payment.route("/authorize/cleanup/<int:customer_id>", methods=["POST"])
def cleanup_authorize_profile(customer_id):
"""
Clean up Authorize.Net profile data in local database when API check fails.
Sets customer auth_net_profile_id to null and clears all card payment profile IDs.
"""
try:
# Get customer and set auth_net_profile_id to null
customer = db.session.query(Customer_Customer).filter(Customer_Customer.id == customer_id).first()
if not customer:
return jsonify({"ok": False, "error": "Customer not found"}), 404
customer.auth_net_profile_id = None
# Get all cards for this customer and set their auth_net_payment_profile_id to null
cards = db.session.query(Card_Card).filter(Card_Card.user_id == customer_id).all()
for card in cards:
card.auth_net_payment_profile_id = None
# Commit all changes
db.session.commit()
return jsonify({"ok": True, "message": f"Cleaned up Authorize.Net data for customer {customer_id}"}), 200
except Exception as e:
db.session.rollback()
return jsonify({"ok": False, "error": f"Failed to cleanup profile: {str(e)}"}), 500
@payment.route("/authorize/<int:delivery_id>", methods=["PUT"])
def update_delivery_payment_authorize(delivery_id):
"""
Update a delivery's payment_type to 11 (CC - Authorize API) after successful preauthorization
"""
get_delivery = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.id == delivery_id)
.first())
if not get_delivery:
return jsonify({"ok": False, "error": "Delivery not found"}), 404
get_delivery.payment_type = 11
db.session.add(get_delivery)
db.session.commit()
return jsonify({"ok": True}), 200
@payment.route("/transaction/delivery/<int:delivery_id>", methods=["GET"])
def get_transaction_by_delivery(delivery_id):
"""
Get a single transaction by delivery_id for Authorize.net payments
"""
transaction = (db.session
.query(Transaction)
.filter(Transaction.delivery_id == delivery_id)
.first())
if not transaction:
return jsonify({"ok": False, "error": "Transaction not found"}), 404
# Convert to dict-like format for frontend
return jsonify({
"ok": True,
"transaction": {
"id": transaction.id,
"preauthorize_amount": float(transaction.preauthorize_amount or 0),
"charge_amount": float(transaction.charge_amount or 0),
"transaction_type": transaction.transaction_type,
"status": transaction.status,
"auth_net_transaction_id": transaction.auth_net_transaction_id,
"delivery_id": transaction.delivery_id,
"customer_id": transaction.customer_id,
"service_id": transaction.service_id,
"card_id": transaction.card_id,
"auto_id": transaction.auto_id,
"created_at": transaction.created_at.isoformat() if transaction.created_at else None
}
})
@payment.route("/transactions/customer/<int:customer_id>/<int:page>", methods=["GET"])
def get_customer_transactions(customer_id, page):
"""
Gets transactions for a specific customer
"""
try:
per_page = 50
offset = (page - 1) * per_page
query = (
db.session
.query(Transaction)
.filter(Transaction.customer_id == customer_id)
.order_by(Transaction.created_at.desc())
.offset(offset)
.limit(per_page)
)
results = query.all()
transactions_data = []
for transaction in results:
transactions_data.append({
"id": transaction.id,
"preauthorize_amount": transaction.preauthorize_amount,
"charge_amount": transaction.charge_amount,
"transaction_type": transaction.transaction_type,
"status": transaction.status,
"created_at": transaction.created_at.isoformat(),
"auth_net_transaction_id": transaction.auth_net_transaction_id,
"rejection_reason": transaction.rejection_reason,
"delivery_id": transaction.delivery_id,
"service_id": transaction.service_id,
"auto_id": transaction.auto_id,
})
return jsonify(transactions_data), 200
except Exception as e:
return jsonify({"ok": False, "error": str(e)}), 500
@payment.route("/service/payment/<int:service_id>/<int:payment_type>", methods=["PUT"])
def process_service_payment_tiger(service_id, payment_type):
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
if not service:
return jsonify({"ok": False, "error": "Service not found"}), 404
# Set payment columns as specified
service.payment_type = payment_type # 1 for Tiger
service.payment_status = 2 # As specified
# payment_card_id retains the selected card's ID if set in the service record
try:
db.session.commit()
return jsonify({"ok": True}), 200
except Exception as e:
db.session.rollback()
return jsonify({"error": str(e)}), 500
@payment.route("/authorize/service/<int:service_id>", methods=["PUT"])
def update_service_payment_authorize(service_id):
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
if not service:
return jsonify({"error": "Service not found"}), 404
data = request.get_json()
card_id = data.get('card_id')
status = data.get('status', 0)
service.payment_type = 11 # CC - Authorize
service.payment_status = status
if card_id:
service.payment_card_id = card_id
try:
db.session.commit()
return jsonify({"ok": True}), 200
except Exception as e:
db.session.rollback()
return jsonify({"error": str(e)}), 500
@payment.route("/capture/service/<int:service_id>", methods=["PUT"])
def update_service_payment_capture(service_id):
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
if not service:
return jsonify({"error": "Service not found"}), 404
data = request.get_json()
card_id = data.get('card_id')
status = data.get('status', 3) # Default to 3 for capture
if service.payment_type is None or service.payment_type != 11:
service.payment_type = 11 # CC - Authorize
service.payment_status = status # 3 for capture
if card_id:
service.payment_card_id = card_id
try:
db.session.commit()
return jsonify({"ok": True}), 200
except Exception as e:
db.session.rollback()
return jsonify({"error": str(e)}), 500
@payment.route("/transactions/service/<int:service_id>", methods=["GET"])
def get_service_transactions(service_id):
"""
Gets all transactions for a specific service ID
"""
try:
query = (
db.session
.query(Transaction)
.filter(Transaction.service_id == service_id)
.order_by(Transaction.created_at.desc())
)
transactions = query.all()
transactions_data = []
for transaction in transactions:
transactions_data.append({
"id": transaction.id,
"preauthorize_amount": float(transaction.preauthorize_amount or 0),
"charge_amount": float(transaction.charge_amount or 0),
"transaction_type": transaction.transaction_type,
"status": transaction.status,
"created_at": transaction.created_at.isoformat() if transaction.created_at else None,
"auth_net_transaction_id": transaction.auth_net_transaction_id,
"rejection_reason": transaction.rejection_reason,
"delivery_id": transaction.delivery_id,
"service_id": transaction.service_id,
"card_id": transaction.card_id,
})
return jsonify(transactions_data), 200
except Exception as e:
print(f"Error fetching transactions for service {service_id}: {str(e)}")
return jsonify({"ok": False, "error": str(e)}), 500

7
app/promo/__init__.py Normal file
View File

@@ -0,0 +1,7 @@
# coding=utf-8
from flask import Blueprint
promo = Blueprint('promo', __name__)
from . import views

182
app/promo/views.py Normal file
View File

@@ -0,0 +1,182 @@
from flask import request, jsonify
import decimal
from datetime import datetime
from app.promo import promo
from app import db
from app.classes.promo import (
Promo_Promo,
Promo_Promo_schema)
from app.classes.delivery import (Delivery_Delivery,
Delivery_Delivery_schema,
Delivery_Notes_Driver,
)
def convert_to_decimal(text):
try:
number = float(text)
return round(number, 2)
except ValueError:
return "0"
@promo.route("/<int:promo_id>", methods=["GET"])
def get_promo(promo_id):
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
.first())
query_schema = Promo_Promo_schema(many=False)
return jsonify(query_schema.dump(get_promo_data))
@promo.route("/promoprice/<int:delivery_id>", methods=["GET"])
def get_promo_price(delivery_id):
"""
"""
get_delivery = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.id == delivery_id)
.first())
price = get_delivery.customer_price - get_delivery.promo_money_discount
price = convert_to_decimal(price)
return jsonify({
"ok": True,
"price": price,
}), 200
@promo.route("/all", methods=["GET"])
def get_all_promo():
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
.all())
query_schema = Promo_Promo_schema(many=True)
return jsonify(query_schema.dump(get_promo_data))
@promo.route("/delete/<int:promo_id>", methods=["DELETE"])
def delete_a_promo(promo_id):
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
.first())
db.session.delete(get_promo_data)
db.session.commit()
return jsonify({
"ok": True,
}), 200
@promo.route("/create", methods=["POST"])
def create_promo():
"""
"""
date_created = datetime.utcnow()
name_of_promotion = request.json["name_of_promotion"]
money_off_delivery = request.json["money_off_delivery"]
description = request.json["description"]
text_on_ticket = request.json["text_on_ticket"]
# see if it exists
amount_off = convert_to_decimal(money_off_delivery)
new_promo = Promo_Promo(
name_of_promotion = name_of_promotion,
money_off_delivery = amount_off,
description = description,
date_created = date_created,
text_on_ticket=text_on_ticket
)
db.session.add(new_promo)
db.session.commit()
return jsonify({
"ok": True,
'promo_id':new_promo.id,
}), 200
@promo.route("/edit/<int:promo_id>", methods=["PUT"])
def edit_promo(promo_id):
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
.first())
text_on_ticket = request.json["text_on_ticket"]
name_of_promotion = request.json["name_of_promotion"]
money_off_delivery = request.json["money_off_delivery"]
description = request.json["description"]
amount_off = convert_to_decimal(money_off_delivery)
get_promo_data.text_on_ticket = text_on_ticket
get_promo_data.description = description
get_promo_data.name_of_promotion = name_of_promotion
get_promo_data.money_off_delivery = amount_off
db.session.add(get_promo_data)
db.session.commit()
return jsonify({
"ok": True,
'promo_id':get_promo_data.id,
}), 200
@promo.route("/on/<int:promo_id>", methods=["PATCH"])
def turn_on_promo(promo_id):
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
.first())
get_promo_data.active = True
db.session.add(get_promo_data)
db.session.commit()
return jsonify({
"ok": True,
'promo_id':get_promo_data.id,
}), 200
@promo.route("/off/<int:promo_id>", methods=["PATCH"])
def turn_off_promo(promo_id):
"""
"""
get_promo_data = (db.session
.query(Promo_Promo)
.filter(Promo_Promo.id == promo_id)
.first())
get_promo_data.active = False
db.session.add(get_promo_data)
db.session.commit()
return jsonify({
"ok": True,
'promo_id':get_promo_data.id,
}), 200

0
app/query/__init__.py Normal file → Executable file
View File

50
app/query/views.py Normal file → Executable file
View File

@@ -1,20 +1,28 @@
from flask import request, jsonify
from flask_login import current_user
from datetime import date, timedelta
from flask import jsonify
from app.query import query
from app import db
from datetime import datetime
from app.classes.query import Query_StateList, \
Query_DeliveryStatusList, \
Query_DeliveryStatusList_Schema, \
Query_StateList_Schema, \
Query_CustomerTypeList, \
Query_CustomerTypeList_Schema,\
Query_EmployeeTypeList, \
Query_EmployeeTypeList_Schema,\
Query_ServiceTypeList,\
Query_ServiceTypeList_Schema
from app.classes.admin import Admin_Company
from app.classes.query import (Query_StateList,
Query_DeliveryStatusList,
Query_DeliveryStatusList_Schema,
Query_StateList_Schema,
Query_CustomerTypeList,
Query_CustomerTypeList_Schema,
Query_EmployeeTypeList,
Query_EmployeeTypeList_Schema)
@query.route("/company/<int:company_id>", methods=["GET"])
def get_company(company_id):
"""
This will get the company from env variable
"""
query_data = (db.session
.query(Admin_Company)
.filter(Admin_Company.id == company_id)
.first())
delivery_schema = Query_DeliveryStatusList_Schema(many=False)
return jsonify(delivery_schema.dump(query_data))
@query.route("/states", methods=["GET"])
def get_state_list():
@@ -43,17 +51,6 @@ def get_customer_type_list():
return jsonify(customer_schema.dump(query_data))
@query.route("/servicetype", methods=["GET"])
def get_service_type_list():
"""
This will get types of service
"""
query_data = db.session \
.query(Query_ServiceTypeList) \
.all()
customer_schema = Query_ServiceTypeList_Schema(many=True)
return jsonify(customer_schema.dump(query_data))
@query.route("/employeetype", methods=["GET"])
@@ -80,3 +77,6 @@ def get_delivery_status_list():
.all()
delivery_schema = Query_DeliveryStatusList_Schema(many=True)
return jsonify(delivery_schema.dump(query_data))

0
app/reports/__init__.py Normal file → Executable file
View File

36
app/reports/views.py Normal file → Executable file
View File

@@ -1,16 +1,10 @@
from flask import request, jsonify
from flask_login import current_user
from flask import jsonify
from sqlalchemy.sql import func
from datetime import date, timedelta
from app.reports import reports
from app import db
from datetime import datetime
from app.classes.auth import Auth_User
from app.classes.customer import Customer_Customer
from app.classes.service import Service_Call, Service_Call_schema
from app.classes.employee import Employee_Employee
from app.classes.service import Service_Call_Notes_Dispatcher, Service_Call_Notes_Technician
from app.classes.delivery import Delivery_Delivery
@@ -21,4 +15,28 @@ def oil_total_gallons():
.group_by(Delivery_Delivery.id)\
.all()
return jsonify({"ok": True }), 200
return jsonify({"ok": True, "oil": total_oil }), 200
@reports.route("/customers/list", methods=["GET"])
def customer_list():
"""
Retrieve a list of customers with selected fields for printing.
Returns account number, first name, last name, address, town, and phone number.
Ordered by last name from A to Z.
"""
customers = db.session.query(Customer_Customer).order_by(Customer_Customer.customer_last_name.asc()).all()
customer_data = [
{
"account_number": customer.account_number,
"first_name": customer.customer_first_name,
"last_name": customer.customer_last_name,
"address": customer.customer_address,
"town": customer.customer_town,
"phone_number": customer.customer_phone_number
}
for customer in customers
]
response = jsonify({"ok": True, "customers": customer_data})
return response, 200

0
app/search/__init__.py Normal file → Executable file
View File

29
app/search/views.py Normal file → Executable file
View File

@@ -1,16 +1,9 @@
from flask import request, jsonify
from flask_login import current_user
from sqlalchemy.sql import func
from datetime import date, timedelta
from app.search import search
from app import db
from datetime import datetime
from app.classes.auth import Auth_User
from sqlalchemy import or_
from app.classes.customer import Customer_Customer, Customer_Customer_schema
from app.classes.service import Service_Call, Service_Call_schema
from app.classes.employee import Employee_Employee
from app.classes.service import Service_Call_Notes_Dispatcher, Service_Call_Notes_Technician
from app.classes.delivery import Delivery_Delivery, Delivery_Delivery_schema
@@ -26,14 +19,15 @@ def search_customers():
search = search.replace("!", "")
search = search.replace("#", "")
search = search.replace("@", "")
search = search.replace("$", "")
# search by last name
if search_type == '@':
search = search[1:]
customer_list = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.customer_first_name.ilike(search))
.filter(Customer_Customer.customer_last_name.ilike(search))
.all())
# Customer Address
elif search_type == '!':
search = search[::1]
@@ -48,11 +42,22 @@ def search_customers():
.query(Customer_Customer)
.filter(Customer_Customer.customer_phone_number.ilike(search))
.all())
# Account Number
elif search_type == '$':
search = search[::1]
customer_list = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.account_number.ilike(search))
.order_by(Customer_Customer.account_number.asc())
.all())
else:
customer_list = (db.session
.query(Customer_Customer)
.filter(Customer_Customer.customer_last_name.ilike(search))
.filter(or_(Customer_Customer.customer_last_name.ilike(search),
Customer_Customer.customer_first_name.ilike(search),
Customer_Customer.customer_address.ilike(search)))
.all())

View File

@@ -1,397 +1,415 @@
from flask import request, jsonify
from flask_login import current_user, login_required
from app.service import service
from app import db
from datetime import datetime
from app.classes.auth import Auth_User
from app.classes.customer import Customer_Customer
from app.classes.service import (Service_Call,
Service_Call_schema,
Service_Call_Notes_Dispatcher,
Service_Call_Notes_Technician,
Service_Call_Notes_Dispatcher_schema,
from datetime import datetime, date, timedelta
from app.classes.customer import (Customer_Customer)
from app.classes.service import (Service_Service,
Service_Service_schema, Service_Parts, Service_Parts_schema,
Service_Plans, Service_Plans_schema
)
from app.classes.cards import Card_Card
from app.classes.employee import Employee_Employee
@service.route("/<string:service_id>", methods=["GET"])
@login_required
def get_specific_service_call(service_id):
service_call = db.session \
.query(Service_Call) \
.filter(Service_Call.id == service_id) \
.first()
service_schema = Service_Call_schema(many=False)
return jsonify(service_schema.dump(service_call))
@service.route("/paymenttype/<int:service_id>/<int:type_of_payment>", methods=["PUT"])
def update_a_service_payment(service_id, type_of_payment):
"""
This update a delivery for example if user updates to a fill
"""
service_call = (db.session
.query(Service_Call)
.filter(Service_Call.id == service_id)
.first())
service_call.payment_type = type_of_payment
db.session.add(service_call)
db.session.commit()
return jsonify({"ok": True}), 200
@service.route("/call/notes/<string:service_id>", methods=["GET"])
@login_required
def get_service_notes_call(service_id):
service_call = db.session \
.query(Service_Call_Notes_Dispatcher) \
.filter(Service_Call_Notes_Dispatcher.service_call_id == service_id) \
.first()
service_schema = Service_Call_Notes_Dispatcher_schema(many=False)
return jsonify(service_schema.dump(service_call))
from app.classes.auto import Auto_Delivery
@service.route("/all", methods=["GET"])
def service_view_all():
"""
Get all service calls
"""
service_calls = db.session \
.query(Service_Call) \
.filter(Service_Call.completed == 0) \
.order_by(Service_Call.when_called.desc()) \
.all()
customer_schema = Service_Call_schema(many=True)
return jsonify(customer_schema.dump(service_calls))
@service.route("/all/<int:page>", methods=["GET"])
def service_view(page):
"""
Get all service calls
"""
per_page_amount = 50
if page is None:
offset_limit = 0
elif page == 1:
offset_limit = 0
else:
offset_limit = (per_page_amount * page) - per_page_amount
service_calls = db.session \
.query(Service_Call) \
.filter(Service_Call.completed == 0) \
.order_by(Service_Call.when_called.desc()) \
.limit(per_page_amount).offset(offset_limit)
customer_schema = Service_Call_schema(many=True)
return jsonify(customer_schema.dump(service_calls))
@service.route("/customer/<int:customer_id>/<int:page>", methods=["GET"])
def service_customer_view(customer_id, page):
"""
Get all service calls
"""
per_page_amount = 50
if page is None:
offset_limit = 0
elif page == 1:
offset_limit = 0
else:
offset_limit = (per_page_amount * page) - per_page_amount
service_calls = db.session \
.query(Service_Call) \
.filter(Service_Call.customer_id == customer_id) \
.order_by(Service_Call.id.desc()) \
.limit(per_page_amount).offset(offset_limit)
customer_schema = Service_Call_schema(many=True)
return jsonify(customer_schema.dump(service_calls))
@service.route("/create/<int:user_id>", methods=["POST"])
def service_create_call(user_id):
"""
create a service call
"""
now = datetime.utcnow()
get_customer = db.session \
.query(Customer_Customer) \
.filter(Customer_Customer.id == user_id) \
.first()
print(request.json)
get_service_type = request.json["type_of_service"]
service_note = request.json["dispatcher_notes_taken"]
service_subject = request.json["dispatcher_subject_taken"]
scheduled_date_date = request.json["date_scheduled"]
dispatcher_id = request.json["dispatcher_id"]
card_payment = request.json["credit"]
cash_payment = request.json["cash"]
def get_all_service_calls():
try:
if request.json["credit_card_id"]:
card_payment_id = request.json["credit_card_id"]
else:
card_payment_id = None
except:
card_payment_id = None
all_services = Service_Service.query.all()
color_map = {
0: {"backgroundColor": "blue", "textColor": "white"}, 1: {"backgroundColor": "red", "textColor": "white"},
2: {"backgroundColor": "green", "textColor": "white"}, 3: {"backgroundColor": "yellow", "textColor": "black"},
4: {"backgroundColor": "black", "textColor": "white"}
}
service_type_map = {0: 'Tune-up', 1: 'No Heat', 2: 'Fix', 3: 'Tank Install', 4: 'Other'}
if cash_payment is True and card_payment is False:
delivery_payment_method = 0
elif card_payment is True and cash_payment is False:
delivery_payment_method = 1
calendar_events = []
for service_record in all_services:
service_type_text = service_type_map.get(service_record.type_service_call, 'Service')
event_title = f"{service_type_text}: {service_record.customer_name}"
event_colors = color_map.get(service_record.type_service_call, {"backgroundColor": "gray", "textColor": "white"})
elif card_payment is True and cash_payment is True:
delivery_payment_method = 2
else:
delivery_payment_method = 3
# Use the schema to safely get the date string
serialized_record = Service_Service_schema().dump(service_record)
start_date = serialized_record.get('scheduled_date')
if card_payment_id is not None:
get_card = (db.session
.query(Card_Card)
.filter(Card_Card.id == card_payment_id)
.filter(Card_Card.user_id == get_customer.id)
.first())
card_id_from_customer = get_card.id
else:
card_id_from_customer = None
event_data = {
"id": service_record.id,
"title": event_title,
"start": start_date,
"end": None,
"extendedProps": {
"customer_id": service_record.customer_id,
"description": service_record.description,
"type_service_call": service_record.type_service_call,
"service_cost": str(service_record.service_cost) if service_record.service_cost is not None else None
},
"backgroundColor": event_colors.get("backgroundColor"),
"textColor": event_colors.get("textColor"),
"borderColor": event_colors.get("backgroundColor")
}
calendar_events.append(event_data)
date_object = datetime.strptime(scheduled_date_date, '%Y-%m-%d').date()
return jsonify(calendar_events), 200
except Exception as e:
# Add error logging to see what's happening
print(f"An error occurred in /service/all: {e}")
return jsonify(error=str(e)), 500
get_tech = (db.session
.query(Employee_Employee)
.first())
create_a_call = Service_Call(
customer_id=get_customer.id,
customer_last_name=get_customer.customer_last_name,
customer_first_name=get_customer.customer_first_name,
customer_town=get_customer.customer_town,
customer_state=get_customer.customer_state,
customer_zip=get_customer.customer_zip,
customer_apt=get_customer.customer_apt,
customer_address=get_customer.customer_address,
status=0,
service_type=get_service_type,
when_called=now,
scheduled_date=date_object,
when_serviced=None,
tech_id=get_tech.id,
tech_first_name=get_tech.employee_first_name,
tech_last_name=get_tech.employee_last_name,
completed=0,
payment_type=delivery_payment_method,
payment_card_id=card_id_from_customer,
# --- THIS IS THE FIX ---
# The logic from /all has been copied here to ensure a consistent data structure.
@service.route("/upcoming", methods=["GET"])
def get_upcoming_service_calls():
"""
Fetches a list of all future service calls from today onwards.
"""
now = datetime.now()
upcoming_services = (
Service_Service.query
.filter(Service_Service.scheduled_date >= now)
.order_by(Service_Service.scheduled_date.asc())
.limit(100)
.all()
)
db.session.add(create_a_call)
db.session.flush()
service_schema = Service_Service_schema(many=True)
result = service_schema.dump(upcoming_services)
create_new_note = Service_Call_Notes_Dispatcher(
service_call_id=create_a_call.id,
dispatcher_subject=service_subject,
dispatcher_notes=service_note,
time_added=now,
dispatcher_id=dispatcher_id,
dispatcher_name=None,
return jsonify(result), 200
@service.route("/past", methods=["GET"])
def get_past_service_calls():
"""
Fetches a list of all past service calls before today.
"""
past_services = (
Service_Service.query
.filter(Service_Service.scheduled_date < datetime.combine(date.today(), datetime.min.time()))
.order_by(Service_Service.scheduled_date.asc())
.limit(100)
.all()
)
db.session.add(create_new_note)
service_schema = Service_Service_schema(many=True)
result = service_schema.dump(past_services)
return jsonify(result), 200
@service.route("/today", methods=["GET"])
def get_today_service_calls():
"""
Fetches a list of all service calls for today.
"""
start_of_today = datetime.combine(date.today(), datetime.min.time())
start_of_tomorrow = datetime.combine(date.today() + timedelta(days=1), datetime.min.time())
today_services = (
Service_Service.query
.filter(Service_Service.scheduled_date >= start_of_today)
.filter(Service_Service.scheduled_date < start_of_tomorrow)
.order_by(Service_Service.scheduled_date.asc())
.limit(100)
.all()
)
service_schema = Service_Service_schema(many=True)
result = service_schema.dump(today_services)
return jsonify(result), 200
@service.route("/upcoming/count", methods=["GET"])
def get_upcoming_service_calls_count():
now = datetime.now()
try:
count = (db.session.query(Service_Service).filter(Service_Service.scheduled_date >= now).count())
return jsonify({"count": count}), 200
except Exception as e:
return jsonify({"error": str(e)}), 500
@service.route("/for-customer/<int:customer_id>", methods=["GET"])
def get_service_calls_for_customer(customer_id):
service_records = (Service_Service.query.filter_by(customer_id=customer_id).order_by(Service_Service.scheduled_date.desc()).all())
service_schema = Service_Service_schema(many=True)
result = service_schema.dump(service_records)
return jsonify(result), 200
@service.route("/create", methods=["POST"])
def create_service_call():
data = request.get_json()
if not data: return jsonify({"error": "No data provided"}), 400
cus_id=data.get('customer_id')
get_customer = (db.session.query(Customer_Customer).filter(Customer_Customer.id == cus_id).first())
if not get_customer: return jsonify({"error": f"Customer with id {cus_id} not found."}), 404
scheduled_datetime_str = data.get('expected_delivery_date')
scheduled_datetime_obj = datetime.fromisoformat(scheduled_datetime_str)
new_service_call = Service_Service(
customer_id=get_customer.id, customer_name=get_customer.customer_first_name + ' ' + get_customer.customer_last_name,
customer_address=get_customer.customer_address, customer_town=get_customer.customer_town,
customer_state=get_customer.customer_state, customer_zip=get_customer.customer_zip,
type_service_call=data.get('type_service_call'), when_ordered=datetime.utcnow(),
scheduled_date=scheduled_datetime_obj, description=data.get('description'), service_cost=None,
)
db.session.add(new_service_call)
db.session.commit()
return jsonify({ "ok": True, "id": new_service_call.id }), 201
@service.route("/update-cost/<int:id>", methods=["PUT"])
def update_service_cost(id):
"""
Dedicated endpoint to update only the service cost for a service call.
This is used after payment capture/charge to update the actual amount.
"""
try:
# Find the service
service_record = Service_Service.query.get_or_404(id)
# Get request data - only service_cost
data = request.get_json()
if not data:
return jsonify({"error": "No data provided"}), 400
# Extract and validate the service_cost
new_cost = data.get('service_cost')
if new_cost is None:
return jsonify({"error": "service_cost is required"}), 400
# Convert to float for validation
try:
new_cost_float = float(new_cost)
except (ValueError, TypeError):
return jsonify({"error": "service_cost must be a valid number"}), 400
# Update the service_cost
service_record.service_cost = new_cost_float
# Commit the transaction
db.session.commit()
db.session.commit()
return jsonify({"ok": True,
'user_id': get_customer.id,
'service_id': create_a_call.id,
# Return success response
return jsonify({
"ok": True,
"service_id": id,
"service_cost_updated": new_cost_float,
"message": f"Service {id} cost updated to ${new_cost_float}"
}), 200
@service.route("/delete/<int:service_id>", methods=["DELETE"])
def service_delete_call(service_id):
"""
delete a service call
"""
get_call_to_delete = (db.session
.query(Service_Call)
.filter(Service_Call.id == service_id)
.first())
db.session.delete(get_call_to_delete)
except Exception as e:
db.session.rollback()
print(f"Error updating service cost for service {id}: {str(e)}")
return jsonify({"error": str(e)}), 500
@service.route("/update/<int:id>", methods=["PUT"])
def update_service_call(id):
service_record = Service_Service.query.get_or_404(id)
data = request.get_json()
if not data: return jsonify({"error": "No data provided"}), 400
scheduled_datetime_str = data.get('scheduled_date')
if scheduled_datetime_str:
service_record.scheduled_date = datetime.fromisoformat(scheduled_datetime_str)
service_record.type_service_call = data.get('type_service_call', service_record.type_service_call)
service_record.description = data.get('description', service_record.description)
service_record.service_cost = data.get('service_cost', service_record.service_cost)
try:
db.session.commit()
return jsonify({"ok": True}), 200
service_schema = Service_Service_schema(many=False)
return jsonify({"ok": True, "service": service_schema.dump(service_record)}), 200
except Exception as e:
db.session.rollback()
return jsonify({"error": str(e)}), 500
@service.route("/edit/<int:service_id>", methods=["PUT"])
def service_edit_call(service_id):
# Service Plans CRUD endpoints
@service.route("/plans/active", methods=["GET"])
def get_active_service_plans():
"""
Update a service call
Get all active service plans (contract_plan > 0)
"""
try:
plans = Service_Plans.query.filter(Service_Plans.contract_plan > 0).all()
plans_schema = Service_Plans_schema(many=True)
result = plans_schema.dump(plans)
get_service_type = request.json["type_of_service"]
scheduled_date_date = request.json["date_scheduled"]
dispatcher_subject_taken = request.json["dispatcher_subject_taken"]
dispatcher_notes_taken = request.json["dispatcher_notes_taken"]
tech_id = request.json["tech_id"]
# Add customer info to each plan
for plan in result:
customer = Customer_Customer.query.get(plan['customer_id'])
if customer:
plan['customer_name'] = f"{customer.customer_first_name} {customer.customer_last_name}"
plan['customer_address'] = customer.customer_address
plan['customer_town'] = customer.customer_town
card_payment = request.json["credit"]
cash_payment = request.json["cash"]
return jsonify(result), 200
except Exception as e:
return jsonify({"error": str(e)}), 500
if request.json["credit_card_id"]:
card_payment_id = request.json["credit_card_id"]
@service.route("/plans/customer/<int:customer_id>", methods=["GET"])
def get_customer_service_plan(customer_id):
"""
Get service plan for a specific customer
"""
try:
plan = Service_Plans.query.filter_by(customer_id=customer_id).first()
if plan:
plan_schema = Service_Plans_schema()
return jsonify(plan_schema.dump(plan)), 200
else:
card_payment_id = None
get_tech = db.session \
.query(Employee_Employee) \
.filter(Employee_Employee.id == tech_id) \
.first()
get_service_call_call = db.session \
.query(Service_Call) \
.filter(Service_Call.id == service_id) \
.first()
if card_payment_id is not None:
get_customer = db.session \
.query(Customer_Customer) \
.filter(Customer_Customer.id == get_service_call_call.customer_id) \
.first()
get_card = (db.session
.query(Card_Card)
.filter(Card_Card.id == card_payment_id)
.filter(Card_Card.user_id == get_customer.id)
.first())
card_id_from_customer = get_card.id
else:
card_id_from_customer = None
if cash_payment is True and card_payment is False:
delivery_payment_method = 0
elif card_payment is True and cash_payment is False:
delivery_payment_method = 1
elif card_payment is True and cash_payment is True:
delivery_payment_method = 2
else:
delivery_payment_method = 3
get_service_call_notes = (db.session
.query(Service_Call_Notes_Dispatcher)
.filter(Service_Call_Notes_Dispatcher.service_call_id == get_service_call_call.id)
.first())
get_service_call_notes.dispatcher_subject = dispatcher_subject_taken
get_service_call_notes.dispatcher_notes = dispatcher_notes_taken
get_service_call_call.service_type = get_service_type
get_service_call_call.scheduled_date = scheduled_date_date
get_service_call_call.tech_id = get_tech.id
get_service_call_call.payment_type = delivery_payment_method
get_service_call_call.payment_card_id = card_id_from_customer
db.session.add(get_service_call_call)
db.session.commit()
return jsonify({"ok": True}), 200
return jsonify(None), 200
except Exception as e:
return jsonify({"error": str(e)}), 500
@service.route("/update/type/<int:service_id>", methods=["PUT"])
def service_update_service_type(service_id):
@service.route("/plans/create", methods=["POST"])
def create_service_plan():
"""
Update a service call diagnosis
Create a new service plan for a customer
"""
get_service_type = request.json["service_type"]
data = request.get_json()
if not data:
return jsonify({"error": "No data provided"}), 400
get_service_call = db.session \
.query(Service_Call) \
.filter(Service_Call.service_id == service_id) \
.first()
get_service_call.service_type = get_service_type
db.session.add(get_service_call)
db.session.commit()
return jsonify({"ok": True}), 200
@service.route("/note/dispatcher/<int:service_id>", methods=["PUT"])
def service_create_note_dispatcher(service_id):
"""
Initial dispatcher note about the call
"""
service_note = request.json["dispatcher_text"]
now = datetime.utcnow()
user = db.session \
.query(Auth_User) \
.filter(Auth_User.id == current_user.id) \
.first()
get_service_call_order = db.session \
.query(Service_Call) \
.filter(Service_Call.service_id == service_id) \
.first()
create_new_note = Service_Call_Notes_Dispatcher(
service_call_id=get_service_call_order.id,
dispatcher_notes=service_note,
time_added=now,
dispatcher_id=user.id,
dispatcher_name=user.username,
try:
new_plan = Service_Plans(
customer_id=data['customer_id'],
contract_plan=data['contract_plan'],
contract_years=data['contract_years'],
contract_start_date=datetime.fromisoformat(data['contract_start_date'])
)
db.session.add(create_new_note)
db.session.add(new_plan)
db.session.commit()
return jsonify({"ok": True}), 200
plan_schema = Service_Plans_schema()
return jsonify({"ok": True, "plan": plan_schema.dump(new_plan)}), 201
except Exception as e:
db.session.rollback()
return jsonify({"error": str(e)}), 500
@service.route("/note/technician/<int:service_id>", methods=["PUT"])
def service_create_note_technician(service_id):
@service.route("/plans/update/<int:customer_id>", methods=["PUT"])
def update_service_plan(customer_id):
"""
Technician can create notes on the call
Update existing service plan for a customer
"""
data = request.get_json()
if not data:
return jsonify({"error": "No data provided"}), 400
service_technician_notes = request.json["technician_comments"]
now = datetime.utcnow()
try:
plan = Service_Plans.query.filter_by(customer_id=customer_id).first()
if not plan:
# Create new plan if it doesn't exist
plan = Service_Plans(customer_id=customer_id)
db.session.add(plan)
user = db.session \
.query(Auth_User) \
.filter(Auth_User.id == current_user.id) \
.first()
plan.contract_plan = data.get('contract_plan', plan.contract_plan)
plan.contract_years = data.get('contract_years', plan.contract_years)
if data.get('contract_start_date'):
plan.contract_start_date = datetime.fromisoformat(data['contract_start_date'])
get_service_call = db.session \
.query(Service_Call) \
.filter(Service_Call.service_id == service_id) \
.first()
create_new_note = Service_Call_Notes_Technician(
service_call_id=get_service_call.id,
technician_comments=service_technician_notes,
time_added=now,
technician_id=user.id,
technician_name=user.username,
)
db.session.add(create_new_note)
db.session.commit()
plan_schema = Service_Plans_schema()
return jsonify({"ok": True, "plan": plan_schema.dump(plan)}), 200
except Exception as e:
db.session.rollback()
return jsonify({"error": str(e)}), 500
@service.route("/plans/delete/<int:customer_id>", methods=["DELETE"])
def delete_service_plan(customer_id):
"""
Delete service plan for a customer
"""
try:
plan = Service_Plans.query.filter_by(customer_id=customer_id).first()
if not plan:
return jsonify({"error": "Service plan not found"}), 404
db.session.delete(plan)
db.session.commit()
return jsonify({"ok": True, "message": "Service plan deleted successfully"}), 200
except Exception as e:
db.session.rollback()
return jsonify({"error": str(e)}), 500
@service.route("/<int:id>", methods=["GET"])
def get_service_by_id(id):
service_record = Service_Service.query.get_or_404(id)
service_schema = Service_Service_schema()
return jsonify({"ok": True, "service": service_schema.dump(service_record)}), 200
@service.route("/delete/<int:id>", methods=["DELETE"])
def delete_service_call(id):
service_record = Service_Service.query.get_or_404(id)
try:
db.session.delete(service_record)
db.session.commit()
return jsonify({"ok": True, "message": "Service deleted successfully"}), 200
except Exception as e:
db.session.rollback()
return jsonify({"error": str(e)}), 500
@service.route("/parts/customer/<int:customer_id>", methods=["GET"])
def get_service_parts(customer_id):
parts = Service_Parts.query.filter_by(customer_id=customer_id).first()
if parts:
parts_schema = Service_Parts_schema()
return jsonify(parts_schema.dump(parts)), 200
else:
return jsonify({
"customer_id": customer_id, "oil_filter": "", "oil_filter_2": "",
"oil_nozzle": "", "oil_nozzle_2": "", "hot_water_tank": 0
}), 200
@service.route("/parts/update/<int:customer_id>", methods=["POST"])
def update_service_parts(customer_id):
try:
data = request.get_json()
if not data:
return jsonify({"error": "No data provided"}), 400
get_customer = db.session.query(Customer_Customer).filter(Customer_Customer.id == customer_id).first()
parts = Service_Parts.query.filter_by(customer_id=customer_id).first()
if not parts:
parts = Service_Parts(customer_id=customer_id)
db.session.add(parts)
parts.oil_filter = data.get('oil_filter', parts.oil_filter)
parts.oil_filter_2 = data.get('oil_filter_2', parts.oil_filter_2)
parts.oil_nozzle = data.get('oil_nozzle', parts.oil_nozzle)
parts.oil_nozzle_2 = data.get('oil_nozzle_2', parts.oil_nozzle_2)
parts.hot_water_tank = data.get('hot_water_tank', parts.hot_water_tank if parts.hot_water_tank is not None else 0)
# Sync to Auto_Delivery if customer is automatic
if get_customer and get_customer.customer_automatic == 1:
get_auto = db.session.query(Auto_Delivery).filter(Auto_Delivery.customer_id == customer_id).first()
if get_auto:
get_auto.hot_water_summer = parts.hot_water_tank
db.session.add(get_auto)
db.session.commit()
return jsonify({"ok": True, "message": "Service parts updated successfully"}), 200
except Exception as e:
db.session.rollback()
return jsonify({"error": str(e)}), 500
@service.route("/payment/<int:service_id>/<int:payment_type>", methods=["PUT"])
def process_service_payment(service_id, payment_type):
service = db.session.query(Service_Service).filter(Service_Service.id == service_id).first()
if not service:
return jsonify({"ok": False, "error": "Service not found"}), 404
# Set payment columns as specified
service.payment_type = payment_type # e.g., 1 for Tiger
service.payment_status = 2 # As specified
# payment_card_id retains the selected card's ID if set in the service record
try:
db.session.commit()
return jsonify({"ok": True}), 200
except Exception as e:
db.session.rollback()
return jsonify({"error": str(e)}), 500

7
app/social/__init__.py Normal file
View File

@@ -0,0 +1,7 @@
# coding=utf-8
from flask import Blueprint
social = Blueprint('social', __name__)
from . import views

77
app/social/views.py Normal file
View File

@@ -0,0 +1,77 @@
from flask import jsonify, request
import datetime
from app.social import social
from app import db
from app.classes.customer_social import (Customer_Customer_Social_schema,
Customer_Customer_Social)
@social.route("/posts/<int:customer_id>/<int:page>", methods=["GET"])
def get_customer_posts(customer_id, page):
per_page_amount = 50
if page is None:
offset_limit = 0
elif page == 1:
offset_limit = 0
else:
offset_limit = (per_page_amount * page) - per_page_amount
customer_posts = (db.session
.query(Customer_Customer_Social)
.filter(Customer_Customer_Social.customer_id == customer_id)
.order_by(Customer_Customer_Social.id.desc())
.limit(per_page_amount).offset(offset_limit))
customer_social_schema = Customer_Customer_Social_schema(many=True)
return jsonify(customer_social_schema.dump(customer_posts))
@social.route("/create/<int:customer_id>", methods=["POST"])
def create_post(customer_id):
comment = request.json["comment"]
poster_employee_id = request.json["poster_employee_id"]
create_post = Customer_Customer_Social(
created = datetime.datetime.utcnow(),
customer_id = customer_id,
poster_employee_id = poster_employee_id,
comment = comment
)
db.session.add(create_post)
db.session.commit()
return jsonify({ "ok": True,}), 200
@social.route("/posts/<int:post_id>", methods=["PATCH"])
def edit_post(post_id):
customer_post = (db.session
.query(Customer_Customer_Social)
.filter(Customer_Customer_Social.id == post_id)
.first())
comment = request.json["comment"]
customer_post.comment = comment
db.session.add(customer_post)
db.session.commit()
return jsonify({ "ok": True,}), 200
@social.route("/delete/<int:post_id>", methods=["DELETE"])
def delete_post(post_id):
customer_post = (db.session
.query(Customer_Customer_Social)
.filter(Customer_Customer_Social.id == post_id)
.first())
db.session.delete(customer_post)
db.session.commit()
return jsonify({ "ok": True,}), 200

0
app/stats/__init__.py Normal file → Executable file
View File

213
app/stats/views.py Normal file → Executable file
View File

@@ -1,31 +1,218 @@
from flask import jsonify
from sqlalchemy import func
from datetime import date
from app.stats import stats
import datetime
from app import db
from app.classes.delivery import Delivery_Delivery
from app.classes.service import Service_Call
from app.classes.stats_company import Stats_Company, Stats_Company_schema
from app.classes.stats_customer import Stats_Customer, Stats_Customer_schema
def get_monday_date(date_object):
"""Gets the date of the Monday for the given date."""
# Get the day of the week as an integer (0 = Monday, 6 = Sunday)
day_of_week = date_object.weekday()
# Calculate the number of days to subtract to get to Monday
days_to_monday = day_of_week - 0 # Monday is 0
# Subtract the days from the given date to get Monday's date
monday_date = date_object - datetime.timedelta(days=days_to_monday)
return monday_date
@stats.route("/calls/add", methods=["PUT"])
def total_calls_post():
total_calls_today = (db.session
.query(Stats_Company)
.filter(Stats_Company.expected_delivery_date == date.today())
.first())
current_call_count = total_calls_today.total_calls
new_call = current_call_count + 1
total_calls_today.total_calls = new_call
db.session.add(total_calls_today)
db.session.commit()
return jsonify({"ok": True,}), 200
@stats.route("/calls/count/today", methods=["GET"])
def total_calls_today():
total_calls_today = (db.session
.query(Stats_Company)
.filter(Stats_Company.expected_delivery_date == date.today())
.count())
return jsonify({"ok": True,
'data': total_calls_today,
}), 200
@stats.route("/gallons/total/<int:driver_id>", methods=["GET"])
def total_gallons_delivered_driver(driver_id):
gallons_list = []
total_gallons = db.session\
.query(Delivery_Delivery)\
.filter(Delivery_Delivery.driver_employee_id == driver_id)\
.all()
for f in total_gallons:
gallons_list.append(f.gallons_delivered)
sum_of_gallons = (sum(gallons_list))
return jsonify({"ok": True,
'data': sum_of_gallons,
}), 200
@stats.route("/delivery/total/<int:driver_id>", methods=["GET"])
def total_deliveries_driver(driver_id):
total_stops = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.driver_employee_id == driver_id)
.count())
return jsonify({"ok": True,
'data': total_stops,
}), 200
@stats.route("/primes/total/<int:driver_id>", methods=["GET"])
def total_primes_driver(driver_id):
total_stops = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.driver_employee_id == driver_id)
.filter(Delivery_Delivery.prime == 1)
.count())
return jsonify({"ok": True,
'data': total_stops,
}), 200
@stats.route("/delivery/count/today", methods=["GET"])
def get_delivery_today():
today_deliveries = (db.session
def total_deliveries_today():
total_stops = (db.session
.query(Delivery_Delivery)
.order_by(func.date(Delivery_Delivery.expected_delivery_date) == date.today())
.filter(Delivery_Delivery.expected_delivery_date == date.today())
.count())
return jsonify({"ok": True,
'data': today_deliveries,
'data': total_stops,
}), 200
@stats.route("/service/count/today", methods=["GET"])
def get_service_today():
today_calls = (db.session
.query(Service_Call)
.order_by(func.date(Service_Call.scheduled_date) == date.today())
@stats.route("/delivery/count/delivered/today", methods=["GET"])
def total_deliveries_today_finished():
total_stops = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.expected_delivery_date == date.today())
.filter((Delivery_Delivery.delivery_status == 10))
.count())
return jsonify({"ok": True,
'data': today_calls,
'data': total_stops,
}), 200
@stats.route("/user/<int:user_id>", methods=["GET"])
def get_user_stats(user_id):
"""
gets stats of user
"""
get_user = db.session \
.query(Stats_Customer) \
.filter(Stats_Customer.customer_id == user_id) \
.first()
if get_user is None:
new_stats = Stats_Customer(
customer_id = user_id,
total_calls = 1,
service_calls_total = 0,
service_calls_total_spent = 0,
service_calls_total_profit = 0,
oil_deliveries = 0,
oil_total_gallons = 0,
oil_total_spent = 0,
oil_total_profit = 0,
)
db.session.add(new_stats)
db.session.commit()
get_user = db.session \
.query(Stats_Customer) \
.filter(Stats_Customer.customer_id == user_id) \
.first()
user_schema = Stats_Customer_schema(many=False)
return jsonify(user_schema.dump(get_user))
@stats.route("/user/lastdelivery/<int:user_id>", methods=["GET"])
def get_user_last_delivery(user_id):
"""
gets users last delivery. used on profile page
"""
get_delivery= db.session \
.query(Delivery_Delivery) \
.filter(Delivery_Delivery.customer_id == user_id) \
.filter(Delivery_Delivery.delivery_status == 10) \
.order_by(Delivery_Delivery.id.desc())\
.first()
if get_delivery:
date_delivered = get_delivery.when_delivered
else:
date_delivered = "no deliveries on record"
return jsonify({"ok": True,
'date': str(date_delivered),
}), 200
@stats.route("/gallons/week", methods=["GET"])
def total_gallons_delivered_this_week():
# Get today's date
total_gallons = 0
today = datetime.date.today()
# Get the date of the Monday for today
monday = get_monday_date(today)
get_total = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.when_delivered >= monday)
.filter(Delivery_Delivery.when_delivered <= today)
.all())
for f in get_total:
total_gallons = total_gallons + f.gallons_delivered
return jsonify({"ok": True,
'total': total_gallons,
}), 200
@stats.route("/gallons/check/total/<int:user_id>", methods=["GET"])
def calculate_gallons_user(user_id):
# Get today's date
total_gallons = 0
# Get the date of the Monday for today
get_total = (db.session
.query(Delivery_Delivery)
.filter(Delivery_Delivery.customer_id == user_id)
.all())
get_user = db.session \
.query(Stats_Customer) \
.filter(Stats_Customer.customer_id == user_id) \
.first()
for f in get_total:
total_gallons = total_gallons + f.gallons_delivered
get_user.oil_total_gallons = total_gallons
db.session.add(get_user)
db.session.commit()
return jsonify({"ok": True,
}), 200

7
app/ticket/__init__.py Normal file
View File

@@ -0,0 +1,7 @@
# coding=utf-8
from flask import Blueprint
ticket = Blueprint('ticket', __name__)
from . import views

14
app/ticket/views.py Normal file
View File

@@ -0,0 +1,14 @@
from flask import jsonify
from app.ticket import ticket
from app import db
from app.classes.delivery import Delivery_Delivery
@ticket.route("/<int:ticket_id>", methods=["GET"])
def get_ticket_printer_letter(ticket_id):
return jsonify({"ok": True,
}), 200

24
config.py Normal file
View File

@@ -0,0 +1,24 @@
import os
def load_config(mode=os.environ.get('MODE')):
try:
print(f"mode is {mode}")
if mode == 'PRODUCTION':
from settings_prod import ApplicationConfig
return ApplicationConfig
elif mode == 'DEVELOPMENT':
from settings_dev import ApplicationConfig
return ApplicationConfig
elif mode == 'LOCAL':
from settings_local import ApplicationConfig
return ApplicationConfig
else:
from settings_prod import ApplicationConfig
return ApplicationConfig
except ImportError:
from settings_local import ApplicationConfig
return ApplicationConfig

View File

@@ -0,0 +1 @@
# 0 = charge, 1 = auth, 3 = capture

8
info_delivery_status.txt Normal file
View File

@@ -0,0 +1,8 @@
0: Waiting
1: Cancelled
2: Today
3: Tomorrow_Delivery
4: Partial_Delivery
5: Issue_Delivery
9: Pending
10: Finalized

7
info_home_type.txt Normal file
View File

@@ -0,0 +1,7 @@
0: Residential
1: apartment
2: condo
3: commercial
4: business
5: construction
6: container

13
info_paymant_type.txt Normal file
View File

@@ -0,0 +1,13 @@
0: Cash
1: CC
2: Cash/CC
3: Check
4: Other
0: Cash
1: CC - Tiger
11: CC - Authorize
2: Cash/CC
3: Check
4: Other

7
info_state_list.txt Normal file
View File

@@ -0,0 +1,7 @@
0: MA
1: RI
2: NH
3: ME
4: VT
5: CT
6: NY

17
nginx.conf Normal file
View File

@@ -0,0 +1,17 @@
server {
listen 80;
server_name _;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /app;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

View File

@@ -1,19 +1,35 @@
flask==2.3.3
flask_sqlalchemy
flask_session==0.5.0
flask-login==0.6.3
flask-moment
flask-paranoid
flask-bcrypt
flask-cors
flask_marshmallow
gunicorn
python-dateutil
python-dotenv
marshmallow-sqlalchemy
psycopg2-binary
redis
sqlalchemy
flask_wtf
flask_mail
Werkzeug==2.3.8
bcrypt==4.3.0
blinker==1.9.0
cachelib==0.13.0
click==8.1.8
Flask==3.1.0
Flask-Bcrypt==1.0.1
flask-cors==5.0.1
Flask-Login==0.6.3
Flask-Mail==0.10.0
flask-marshmallow==1.3.0
Flask-Moment==1.0.6
Flask-Paranoid==0.3.0
Flask-Session==0.8.0
Flask-SQLAlchemy==3.1.1
Flask-WTF==1.2.2
geographiclib==2.0
geopy==2.4.1
greenlet==3.2.2
gunicorn==23.0.0
itsdangerous==2.2.0
Jinja2==3.1.6
MarkupSafe==3.0.2
marshmallow==4.0.0
marshmallow-sqlalchemy==1.4.2
msgspec==0.19.0
packaging==25.0
psycopg2-binary==2.9.10
python-dateutil==2.9.0.post0
python-dotenv==1.1.0
redis==6.0.0
six==1.17.0
SQLAlchemy==2.0.40
typing_extensions==4.13.2
Werkzeug==3.1.3
WTForms==3.2.1

20
requirements.txt.bak Executable file
View File

@@ -0,0 +1,20 @@
flask==2.3.3
flask_sqlalchemy
flask_session==0.5.0
flask-login==0.6.3
flask-moment
flask-paranoid
flask-bcrypt
flask-cors
flask_marshmallow
gunicorn
python-dateutil
python-dotenv
marshmallow-sqlalchemy
psycopg2-binary
redis
sqlalchemy
flask_wtf
flask_mail
Werkzeug==2.3.8
geopy

9
local_settings.py → settings_dev.py Executable file → Normal file
View File

@@ -1,4 +1,3 @@
import redis
class ApplicationConfig:
@@ -33,6 +32,8 @@ class ApplicationConfig:
SECRET_KEY = "youwillneverguessthiskeycia"
# sessions
# Available SESSION_TYPE options: 'redis', 'sqlalchemy', 'mongodb', 'filesystem', 'memcached'
SESSION_TYPE = "sqlalchemy"
SESSION_COOKIE_NAME = "eamco_session"
SESSION_COOKIE_SECURE = False
SESSION_COOKIE_HTTPONLY = True
@@ -43,12 +44,12 @@ class ApplicationConfig:
# CORS
ORIGIN_URL = "*"
CORS_ALLOWED_ORIGINS = [
"*"
]
CORS_SEND_WILDCARD = False
CORS_SUPPORT_CREDENTIALS = True
CORS_EXPOSE_HEADERS = None
CORS_ALLOW_HEADERS = "*"
CORS_ORIGIN_WHITELIST = ['http://localhost:5173', '*']

58
settings_local.py Executable file
View File

@@ -0,0 +1,58 @@
class ApplicationConfig:
"""
Basic Configuration for a generic User
"""
CURRENT_SETTINGS = 'LOCAL'
# databases info
POSTGRES_USERNAME = 'postgres'
POSTGRES_PW = 'password'
POSTGRES_SERVER = '192.168.1.204:5432'
POSTGRES_DBNAME00 = 'auburnoil'
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(POSTGRES_USERNAME,
POSTGRES_PW,
POSTGRES_SERVER,
POSTGRES_DBNAME00
)
SQLALCHEMY_BINDS = {'auburnoil': SQLALCHEMY_DATABASE_URI}
# sqlalchemy config
SQLALCHEMY_TRACK_MODIFICATIONS = False
TRAP_HTTP_EXCEPTIONS = True
PROPAGATE_EXCEPTIONS = True
DEBUG = True
UPLOADED_FILES_DEST_ITEM = '/data/item'
# file uploads
UPLOADED_FILES_ALLOW = ['png', 'jpeg', 'jpg', 'png', 'gif']
MAX_CONTENT_LENGTH = 5 * 2500 * 2500
ALLOWED_EXTENSIONS = ['png', 'jpeg', 'jpg', 'png', 'gif']
# secret keys
SECRET_KEY = "youwillneverguessthiskeycia"
# sessions
# Available SESSION_TYPE options: 'redis', 'sqlalchemy', 'mongodb', 'filesystem', 'memcached'
SESSION_TYPE = "sqlalchemy"
SESSION_COOKIE_NAME = "eamco_session"
SESSION_COOKIE_SECURE = False
SESSION_COOKIE_HTTPONLY = True
REMEMBER_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Strict"
SESSION_PERMANENT = False
SESSION_USE_SIGNER = True
# CORS
CORS_SEND_WILDCARD = False
CORS_SUPPORT_CREDENTIALS = True
CORS_EXPOSE_HEADERS = None
CORS_ALLOW_HEADERS = "*"
CORS_ALLOWED_ORIGINS = [
'http://192.168.1.204:9610',
'http://192.168.1.204:9611',
'http://192.168.1.204:9612',
'http://192.168.1.204:9613',
'http://192.168.1.204:9614',
]

56
settings_prod.py Normal file
View File

@@ -0,0 +1,56 @@
class ApplicationConfig:
"""
Basic Configuration for a generic User
"""
CURRENT_SETTINGS = 'PRODUCTION'
# databases info
POSTGRES_USERNAME = 'postgres'
POSTGRES_PW = 'password'
POSTGRES_SERVER = '192.168.1.204:5432'
POSTGRES_DBNAME00 = 'auburnoil'
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(POSTGRES_USERNAME,
POSTGRES_PW,
POSTGRES_SERVER,
POSTGRES_DBNAME00
)
SQLALCHEMY_BINDS = {'auburnoil': SQLALCHEMY_DATABASE_URI}
# sqlalchemy config
SQLALCHEMY_TRACK_MODIFICATIONS = False
TRAP_HTTP_EXCEPTIONS = True
PROPAGATE_EXCEPTIONS = True
DEBUG = False
UPLOADED_FILES_DEST_ITEM = '/data/item'
# file uploads
UPLOADED_FILES_ALLOW = ['png', 'jpeg', 'jpg', 'png', 'gif']
MAX_CONTENT_LENGTH = 5 * 2500 * 2500
ALLOWED_EXTENSIONS = ['png', 'jpeg', 'jpg', 'png', 'gif']
# secret keys
SECRET_KEY = "34dsfkjh43123cxzfvqwer23432dsf233214efdasf2134321"
# sessions
SESSION_TYPE = "sqlalchemy"
SESSION_COOKIE_NAME = "eamco_session"
SESSION_COOKIE_SECURE = False
SESSION_COOKIE_HTTPONLY = True
REMEMBER_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Strict"
SESSION_PERMANENT = False
SESSION_USE_SIGNER = True
# CORS
CORS_SEND_WILDCARD = False
CORS_SUPPORT_CREDENTIALS = True
CORS_EXPOSE_HEADERS = None
CORS_ALLOW_HEADERS = "*"
CORS_ALLOWED_ORIGINS = [
'https://oil.edwineames.com',
'https://edwineames.com'
]

8
start.sh Normal file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
set -e
# Start Gunicorn
gunicorn --bind 127.0.0.1:8000 --workers 4 --timeout 120 app:app &
# Start Nginx
nginx -g 'daemon off;'

13
update_requirements.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/bash
# Script to update pip packages and regenerate requirements.txt
# Extract package names from requirements.txt, removing version specifiers
packages=$(cat requirements.txt | sed 's/==.*//' | sed 's/<.*//' | sed 's/>.*//' | tr '\n' ' ')
# Upgrade all packages
pip3 install --upgrade $packages
# Regenerate requirements.txt with the new versions
pip3 freeze > requirements.txt
echo "Requirements updated successfully."