Compare commits
66 Commits
b71bbe2dc5
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 47c3e98dbf | |||
| 6a1cd0eab5 | |||
| 701d9a9cc0 | |||
| 2cca684908 | |||
| d8e5d6eedc | |||
| 19f5c70735 | |||
| 10d82cf81a | |||
| deaf2f111a | |||
| c9464b1605 | |||
| 1404a0432a | |||
| 5d96031992 | |||
| 2209145e74 | |||
| cfbc12da3b | |||
| fd906a574b | |||
| 628eb8eaa6 | |||
| 8c146d24f6 | |||
| 908100514f | |||
| 8d9ecf6935 | |||
| f0544779bb | |||
| 382e12671b | |||
| 14abc3c2b4 | |||
| 8753e3e103 | |||
| a280194079 | |||
| cd3f4471cc | |||
| 66f00aa7b5 | |||
| ca6e7ad778 | |||
| 20f9a4485e | |||
| d250e136c3 | |||
| 9a2f9a6564 | |||
| 067c9055d2 | |||
| 652947b30a | |||
| c526284d98 | |||
| 51f2e986a9 | |||
| 3e259a530c | |||
| 79aa32e8e4 | |||
| b97d729ef1 | |||
| 09fafa59d4 | |||
| 86d6d2dadd | |||
| 98a2c94083 | |||
| e6f85ff014 | |||
| 86ec25a499 | |||
| 5e5b9274e1 | |||
| b3f0e85574 | |||
| 5649294be0 | |||
| 8cee9dc5bf | |||
| d0641950f9 | |||
| d91460fa82 | |||
| fec638a5c8 | |||
| 0e827053de | |||
| c456ef301c | |||
| d7c809af82 | |||
| d77c4e2478 | |||
| 93fc535eaf | |||
| bc1e38c327 | |||
| ebeecccd63 | |||
| 12d973d785 | |||
| 9672b804e6 | |||
| 2a266eea23 | |||
| ca3ebf9f9b | |||
| 2433dbb447 | |||
| 2a4804ecb2 | |||
| 6fab39bf86 | |||
| 666d0895e4 | |||
| 52172812cb | |||
| ca518af9e8 | |||
| 001b8218bd |
4
.dockerignore
Executable file
4
.dockerignore
Executable file
@@ -0,0 +1,4 @@
|
||||
local_settings.py
|
||||
.git
|
||||
.gitignore
|
||||
githubtoken.txt
|
||||
133
.gitignore
vendored
Executable file
133
.gitignore
vendored
Executable file
@@ -0,0 +1,133 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Python template
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.idea
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
*.iml
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
|
||||
db.sqlite3
|
||||
|
||||
# Flask stuff:
|
||||
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
venvwindows/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
app/package.json
|
||||
app/package-lock.json
|
||||
.vscode/
|
||||
clearnet.ini
|
||||
|
||||
rsync_svg.txt
|
||||
setup/
|
||||
word_seeds.txt
|
||||
workspace.code-workspace
|
||||
app/static/bootstrap
|
||||
/app/static/images/
|
||||
/app/static/fonts/
|
||||
/app/static/css/
|
||||
/app/static/js/
|
||||
/app/static/javascriptaddons/
|
||||
|
||||
instance/config.py
|
||||
.idea/
|
||||
/passwords.py
|
||||
|
||||
getnewitems.py
|
||||
helperfunctions/
|
||||
test.py
|
||||
tools/
|
||||
nginx.txt
|
||||
app/node_modules/
|
||||
20
Dockerfile.dev
Executable file
20
Dockerfile.dev
Executable file
@@ -0,0 +1,20 @@
|
||||
FROM python:3.13.3-bullseye
|
||||
|
||||
ENV PYTHONFAULTHANDLER=1
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
ENV MODE="DEVELOPMENT"
|
||||
|
||||
RUN mkdir -p /app
|
||||
|
||||
COPY requirements.txt /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN pip3 install -r requirements.txt
|
||||
|
||||
COPY . /app
|
||||
|
||||
CMD ["python", "app.py", "--host", "0.0.0.0"]
|
||||
|
||||
37
Dockerfile.local
Normal file
37
Dockerfile.local
Normal 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
23
Dockerfile.prod
Normal 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"]
|
||||
116
app/__init__.py
Normal file → Executable file
116
app/__init__.py
Normal file → Executable 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')
|
||||
if api_key:
|
||||
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()
|
||||
|
||||
# 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()
|
||||
if user:
|
||||
return user
|
||||
|
||||
# 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,15 +168,15 @@ 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')
|
||||
|
||||
from .delivery_data import delivery_data as delivery_data_blueprint
|
||||
app.register_blueprint(delivery_data_blueprint, url_prefix='/deliverydata')
|
||||
|
||||
from .delivery_status import deliverystatus as delivery_status_blueprint
|
||||
app.register_blueprint(delivery_status_blueprint, url_prefix='/deliverystatus')
|
||||
|
||||
from .search import search as search_blueprint
|
||||
app.register_blueprint(search_blueprint, url_prefix='/search')
|
||||
|
||||
@@ -192,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')
|
||||
|
||||
@@ -204,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
0
app/admin/__init__.py
Normal file → Executable file
87
app/admin/views.py
Normal file → Executable file
87
app/admin/views.py
Normal file → Executable 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():
|
||||
@@ -18,13 +17,27 @@ def create_oil_price():
|
||||
price_from_supplier = request.json["price_from_supplier"]
|
||||
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()
|
||||
@@ -35,49 +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_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,
|
||||
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():
|
||||
@@ -90,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
0
app/auth/__init__.py
Normal file → Executable file
173
app/auth/views.py
Normal file → Executable file
173
app/auth/views.py
Normal file → Executable file
@@ -1,47 +1,45 @@
|
||||
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.
|
||||
"""
|
||||
|
||||
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()
|
||||
return jsonify({
|
||||
"ok": True,
|
||||
'user': {
|
||||
'user_name': user.username,
|
||||
'user_id': user.id,
|
||||
'user_email': user.email,
|
||||
'user_admin': user.admin_role,
|
||||
'token': user.api_key,
|
||||
'confirmed': user.confirmed
|
||||
},
|
||||
'token': user.api_key
|
||||
}), 200
|
||||
auth_header = request.headers.get('Authorization')
|
||||
if not auth_header:
|
||||
return jsonify({"ok": False, "error": "Authorization header missing"}), 401
|
||||
|
||||
# --- 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': {
|
||||
'user_name': user.username,
|
||||
'user_id': user.id,
|
||||
'user_email': user.email,
|
||||
'user_admin': user.admin_role,
|
||||
'token': user.api_key,
|
||||
'confirmed': user.confirmed
|
||||
},
|
||||
}), 200
|
||||
|
||||
|
||||
@auth.route("/amiconfirmed", methods=["GET"])
|
||||
@@ -76,46 +74,31 @@ 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": "Invalid password"}), 401 # Use a more descriptive error and status code
|
||||
|
||||
current_fails = int(user.fails)
|
||||
new_fails = current_fails + 1
|
||||
user.fails = new_fails
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({"error": True}), 200
|
||||
user.locked = 0
|
||||
user.fails = 0
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
|
||||
# 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_id': user.id,
|
||||
'user_email': user.email,
|
||||
'admin_role': user.admin_role,
|
||||
'token': user.api_key
|
||||
},
|
||||
'user': {
|
||||
'user_name': user.username,
|
||||
'user_id': user.id,
|
||||
'user_email': user.email,
|
||||
'admin_role': user.admin_role,
|
||||
},
|
||||
'token': user.api_key
|
||||
}), 200
|
||||
|
||||
@@ -189,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
|
||||
|
||||
@@ -211,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
0
app/classes/__init__.py
Normal file → Executable file
9
app/classes/admin.py
Normal file → Executable file
9
app/classes/admin.py
Normal file → Executable 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)
|
||||
6
app/classes/auth.py
Normal file → Executable file
6
app/classes/auth.py
Normal file → Executable 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
|
||||
@@ -76,4 +78,4 @@ class AnonymousUser(AnonymousUserMixin):
|
||||
self.username = 'Guest'
|
||||
|
||||
|
||||
login_manager.anonymous_user = AnonymousUser
|
||||
login_manager.anonymous_user = AnonymousUser
|
||||
|
||||
82
app/classes/auto.py
Normal file → Executable file
82
app/classes/auto.py
Normal file → Executable 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
9
app/classes/cards.py
Normal file → Executable 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
5
app/classes/company.py
Normal file → Executable 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):
|
||||
|
||||
70
app/classes/customer.py
Normal file → Executable file
70
app/classes/customer.py
Normal file → Executable file
@@ -1,32 +1,35 @@
|
||||
#
|
||||
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:
|
||||
model = Customer_Customer
|
||||
@@ -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
|
||||
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
|
||||
|
||||
|
||||
25
app/classes/customer_social.py
Normal file
25
app/classes/customer_social.py
Normal 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
|
||||
|
||||
72
app/classes/delivery.py
Normal file → Executable file
72
app/classes/delivery.py
Normal file → Executable 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)
|
||||
|
||||
driver_employee_id = db.Column(db.VARCHAR(140))
|
||||
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
5
app/classes/employee.py
Normal file → Executable 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
46
app/classes/money.py
Normal 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))
|
||||
32
app/classes/pricing.py
Normal file → Executable file
32
app/classes/pricing.py
Normal file → Executable file
@@ -2,34 +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_same_day = 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,
|
||||
@@ -37,9 +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_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
26
app/classes/promo.py
Normal 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
23
app/classes/query.py
Normal file → Executable 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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
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)
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
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,60 +52,38 @@ 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 Meta:
|
||||
model = Service_Call_Money
|
||||
|
||||
|
||||
class Service_Call_Notes_Dispatcher(db.Model):
|
||||
__tablename__ = 'service_notes_dispatcher'
|
||||
__bind_key__ = 'eamco'
|
||||
__table_args__ = {"schema": "public"}
|
||||
|
||||
class Service_Parts_schema(ma.SQLAlchemyAutoSchema):
|
||||
class Meta:
|
||||
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_Plans(db.Model):
|
||||
__tablename__ = 'service_plans'
|
||||
__table_args__ = {"schema": "public"}
|
||||
|
||||
id = db.Column(db.Integer,
|
||||
primary_key=True,
|
||||
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))
|
||||
|
||||
|
||||
class Service_Call_Notes_Dispatcher_schema(ma.SQLAlchemyAutoSchema):
|
||||
|
||||
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_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')
|
||||
|
||||
20
app/classes/stats_company.py
Normal file
20
app/classes/stats_company.py
Normal 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
16
app/classes/stats_customer.py
Normal file → Executable 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
31
app/classes/stats_employee.py
Normal file → Executable 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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
22
app/classes/transactions.py
Normal file
22
app/classes/transactions.py
Normal 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
0
app/common/__init__.py
Normal file → Executable file
0
app/common/decorators.py
Normal file → Executable file
0
app/common/decorators.py
Normal file → Executable file
0
app/customer/__init__.py
Normal file → Executable file
0
app/customer/__init__.py
Normal file → Executable file
478
app/customer/views.py
Normal file → Executable file
478
app/customer/views.py
Normal file → Executable 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,30 +69,113 @@ 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)
|
||||
.filter(Customer_Customer.id == customer_id)
|
||||
.first())
|
||||
print(get_customer)
|
||||
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"]
|
||||
@@ -78,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,
|
||||
@@ -101,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({
|
||||
@@ -122,6 +320,7 @@ def create_customer():
|
||||
}), 200
|
||||
|
||||
|
||||
|
||||
@customer.route("/edit/<int:customer_id>", methods=["PUT"])
|
||||
@login_required
|
||||
def edit_customer(customer_id):
|
||||
@@ -131,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"]
|
||||
@@ -138,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
|
||||
@@ -152,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()
|
||||
@@ -186,7 +422,6 @@ def delete_customer(customer_id):
|
||||
|
||||
db.session.delete(get_customer)
|
||||
db.session.commit()
|
||||
print("deleted")
|
||||
return jsonify({
|
||||
"ok": True,
|
||||
'user': {
|
||||
@@ -196,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
0
app/delivery/__init__.py
Normal file → Executable file
763
app/delivery/views.py
Normal file → Executable file
763
app/delivery/views.py
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
0
app/delivery_data/__init__.py
Normal file → Executable file
0
app/delivery_data/__init__.py
Normal file → Executable file
207
app/delivery_data/views.py
Normal file → Executable file
207
app/delivery_data/views.py
Normal file → Executable 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
|
||||
|
||||
|
||||
7
app/delivery_status/__init__.py
Executable file
7
app/delivery_status/__init__.py
Executable file
@@ -0,0 +1,7 @@
|
||||
# coding=utf-8
|
||||
|
||||
from flask import Blueprint
|
||||
|
||||
deliverystatus = Blueprint('delivery_status', __name__)
|
||||
|
||||
from . import views
|
||||
67
app/delivery_status/views.py
Executable file
67
app/delivery_status/views.py
Executable file
@@ -0,0 +1,67 @@
|
||||
from flask import jsonify
|
||||
from datetime import date, timedelta
|
||||
from app.delivery_status import deliverystatus
|
||||
from app import db
|
||||
|
||||
from app.classes.delivery import (Delivery_Delivery,
|
||||
Delivery_Delivery_schema,
|
||||
)
|
||||
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
|
||||
|
||||
|
||||
# --- NEW EFFICIENT ENDPOINT ---
|
||||
@deliverystatus.route("/stats/sidebar-counts", methods=["GET"])
|
||||
def get_sidebar_counts():
|
||||
"""
|
||||
Efficiently gets all counts needed for the navigation sidebar in a single request.
|
||||
This combines logic from all the individual /count/* endpoints.
|
||||
"""
|
||||
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
|
||||
|
||||
# Replicate the logic from each of your /count/* endpoints
|
||||
today_count = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.delivery_status == 2).count()
|
||||
|
||||
tomorrow_count = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.delivery_status == 3).count()
|
||||
|
||||
waiting_count = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.delivery_status == 0).count()
|
||||
|
||||
pending_count = db.session.query(Delivery_Delivery).filter(Delivery_Delivery.delivery_status == 9).count()
|
||||
|
||||
automatic_count = db.session.query(Auto_Delivery).filter(Auto_Delivery.estimated_gallons_left <= 80).count()
|
||||
|
||||
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
0
app/employees/__init__.py
Normal file → Executable file
63
app/employees/views.py
Normal file → Executable file
63
app/employees/views.py
Normal file → Executable file
@@ -1,20 +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):
|
||||
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))
|
||||
@@ -27,7 +46,6 @@ def get_specific_employee_user_id(userid):
|
||||
.query(Employee_Employee) \
|
||||
.filter(Employee_Employee.user_id == userid) \
|
||||
.first()
|
||||
# print(employee.id)
|
||||
employee_schema = Employee_Employee_schema(many=False)
|
||||
return jsonify(employee_schema.dump(employee))
|
||||
|
||||
@@ -69,9 +87,11 @@ def all_employees():
|
||||
def all_employees_drivers():
|
||||
employee_list = db.session \
|
||||
.query(Employee_Employee) \
|
||||
.filter(Employee_Employee.employee_type == 4) \
|
||||
.filter(or_(Employee_Employee.employee_type == 4,
|
||||
Employee_Employee.employee_type == 8)) \
|
||||
.all()
|
||||
customer_schema = Employee_Employee_schema(mwany=True)
|
||||
|
||||
customer_schema = Employee_Employee_schema(many=True)
|
||||
return jsonify(customer_schema.dump(employee_list))
|
||||
|
||||
|
||||
@@ -130,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,
|
||||
@@ -152,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"]
|
||||
print(request.json["employee_end_date"])
|
||||
e_active = request.json.get("active", 1)
|
||||
|
||||
get_employee = db.session \
|
||||
.query(Employee_Employee) \
|
||||
@@ -170,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
0
app/info/__init__.py
Normal file → Executable file
62
app/info/views.py
Normal file → Executable file
62
app/info/views.py
Normal file → Executable file
@@ -1,37 +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())
|
||||
.first())
|
||||
.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,
|
||||
'same_day': get_price_query.price_same_day,
|
||||
'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
0
app/main/__init__.py
Normal file → Executable file
6
app/main/views.py
Normal file → Executable file
6
app/main/views.py
Normal file → Executable 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
8
app/money/__init__.py
Normal 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
83
app/money/views.py
Normal 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
0
app/payment/__init__.py
Normal file → Executable file
580
app/payment/views.py
Normal file → Executable file
580
app/payment/views.py
Normal file → Executable file
@@ -3,32 +3,51 @@ 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()
|
||||
print(get_card_count)
|
||||
if get_card_count > 0:
|
||||
print("true")
|
||||
)
|
||||
|
||||
get_card = (
|
||||
db.session
|
||||
.query(Card_Card)
|
||||
.filter(Card_Card.user_id == user_id)
|
||||
.filter(Card_Card.id == card_id)
|
||||
.first()
|
||||
)
|
||||
|
||||
get_old_card = db.session \
|
||||
.query(Card_Card) \
|
||||
.filter(Card_Card.main_card == True) \
|
||||
.filter(Card_Card.user_id == user_id) \
|
||||
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()
|
||||
print(get_old_card.id)
|
||||
)
|
||||
|
||||
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()
|
||||
|
||||
|
||||
@@ -37,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))
|
||||
@@ -52,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,
|
||||
@@ -69,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):
|
||||
@@ -126,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)
|
||||
@@ -148,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"])
|
||||
@@ -195,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
7
app/promo/__init__.py
Normal 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
182
app/promo/views.py
Normal 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
0
app/query/__init__.py
Normal file → Executable file
50
app/query/views.py
Normal file → Executable file
50
app/query/views.py
Normal file → Executable 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
0
app/reports/__init__.py
Normal file → Executable file
36
app/reports/views.py
Normal file → Executable file
36
app/reports/views.py
Normal file → Executable 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
0
app/search/__init__.py
Normal file → Executable file
31
app/search/views.py
Normal file → Executable file
31
app/search/views.py
Normal file → Executable 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())
|
||||
|
||||
|
||||
@@ -76,4 +81,4 @@ def search_delivery():
|
||||
|
||||
|
||||
delivery_schema = Delivery_Delivery_schema(many=True)
|
||||
return jsonify(delivery_schema.dump(delivery_ticket))
|
||||
return jsonify(delivery_schema.dump(delivery_ticket))
|
||||
|
||||
@@ -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 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 datetime import datetime, date, timedelta
|
||||
from app.classes.customer import (Customer_Customer)
|
||||
from app.classes.service import (Service_Service,
|
||||
Service_Service_schema, Service_Parts, Service_Parts_schema,
|
||||
Service_Plans, Service_Plans_schema
|
||||
)
|
||||
from app.classes.auto import Auto_Delivery
|
||||
|
||||
@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"]
|
||||
all_services = Service_Service.query.all()
|
||||
color_map = {
|
||||
0: {"backgroundColor": "blue", "textColor": "white"}, 1: {"backgroundColor": "red", "textColor": "white"},
|
||||
2: {"backgroundColor": "green", "textColor": "white"}, 3: {"backgroundColor": "yellow", "textColor": "black"},
|
||||
4: {"backgroundColor": "black", "textColor": "white"}
|
||||
}
|
||||
service_type_map = {0: 'Tune-up', 1: 'No Heat', 2: 'Fix', 3: 'Tank Install', 4: 'Other'}
|
||||
|
||||
calendar_events = []
|
||||
for service_record in all_services:
|
||||
service_type_text = service_type_map.get(service_record.type_service_call, 'Service')
|
||||
event_title = f"{service_type_text}: {service_record.customer_name}"
|
||||
event_colors = color_map.get(service_record.type_service_call, {"backgroundColor": "gray", "textColor": "white"})
|
||||
|
||||
# Use the schema to safely get the date string
|
||||
serialized_record = Service_Service_schema().dump(service_record)
|
||||
start_date = serialized_record.get('scheduled_date')
|
||||
|
||||
event_data = {
|
||||
"id": service_record.id,
|
||||
"title": event_title,
|
||||
"start": start_date,
|
||||
"end": None,
|
||||
"extendedProps": {
|
||||
"customer_id": service_record.customer_id,
|
||||
"description": service_record.description,
|
||||
"type_service_call": service_record.type_service_call,
|
||||
"service_cost": str(service_record.service_cost) if service_record.service_cost is not None else None
|
||||
},
|
||||
"backgroundColor": event_colors.get("backgroundColor"),
|
||||
"textColor": event_colors.get("textColor"),
|
||||
"borderColor": event_colors.get("backgroundColor")
|
||||
}
|
||||
calendar_events.append(event_data)
|
||||
|
||||
return 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
|
||||
|
||||
|
||||
# --- 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()
|
||||
)
|
||||
|
||||
service_schema = Service_Service_schema(many=True)
|
||||
result = service_schema.dump(upcoming_services)
|
||||
|
||||
|
||||
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()
|
||||
)
|
||||
|
||||
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()
|
||||
|
||||
# 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
|
||||
|
||||
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()
|
||||
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 Plans CRUD endpoints
|
||||
@service.route("/plans/active", methods=["GET"])
|
||||
def get_active_service_plans():
|
||||
"""
|
||||
Get all active service plans (contract_plan > 0)
|
||||
"""
|
||||
try:
|
||||
plans = Service_Plans.query.filter(Service_Plans.contract_plan > 0).all()
|
||||
plans_schema = Service_Plans_schema(many=True)
|
||||
result = plans_schema.dump(plans)
|
||||
|
||||
# Add customer info to each plan
|
||||
for plan in result:
|
||||
customer = Customer_Customer.query.get(plan['customer_id'])
|
||||
if customer:
|
||||
plan['customer_name'] = f"{customer.customer_first_name} {customer.customer_last_name}"
|
||||
plan['customer_address'] = customer.customer_address
|
||||
plan['customer_town'] = customer.customer_town
|
||||
|
||||
return jsonify(result), 200
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@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
|
||||
except:
|
||||
card_payment_id = None
|
||||
return jsonify(None), 200
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
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
|
||||
@service.route("/plans/create", methods=["POST"])
|
||||
def create_service_plan():
|
||||
"""
|
||||
Create a new service plan for a customer
|
||||
"""
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return jsonify({"error": "No data provided"}), 400
|
||||
|
||||
try:
|
||||
new_plan = Service_Plans(
|
||||
customer_id=data['customer_id'],
|
||||
contract_plan=data['contract_plan'],
|
||||
contract_years=data['contract_years'],
|
||||
contract_start_date=datetime.fromisoformat(data['contract_start_date'])
|
||||
)
|
||||
db.session.add(new_plan)
|
||||
db.session.commit()
|
||||
|
||||
plan_schema = Service_Plans_schema()
|
||||
return 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("/plans/update/<int:customer_id>", methods=["PUT"])
|
||||
def update_service_plan(customer_id):
|
||||
"""
|
||||
Update existing service plan for a customer
|
||||
"""
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return jsonify({"error": "No data provided"}), 400
|
||||
|
||||
try:
|
||||
plan = Service_Plans.query.filter_by(customer_id=customer_id).first()
|
||||
if not plan:
|
||||
# Create new plan if it doesn't exist
|
||||
plan = Service_Plans(customer_id=customer_id)
|
||||
db.session.add(plan)
|
||||
|
||||
plan.contract_plan = data.get('contract_plan', plan.contract_plan)
|
||||
plan.contract_years = data.get('contract_years', plan.contract_years)
|
||||
if data.get('contract_start_date'):
|
||||
plan.contract_start_date = datetime.fromisoformat(data['contract_start_date'])
|
||||
|
||||
db.session.commit()
|
||||
|
||||
plan_schema = Service_Plans_schema()
|
||||
return 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:
|
||||
delivery_payment_method = 3
|
||||
return jsonify({
|
||||
"customer_id": customer_id, "oil_filter": "", "oil_filter_2": "",
|
||||
"oil_nozzle": "", "oil_nozzle_2": "", "hot_water_tank": 0
|
||||
}), 200
|
||||
|
||||
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
|
||||
@service.route("/parts/update/<int:customer_id>", methods=["POST"])
|
||||
def update_service_parts(customer_id):
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
date_object = datetime.strptime(scheduled_date_date, '%Y-%m-%d').date()
|
||||
if not data:
|
||||
return jsonify({"error": "No data provided"}), 400
|
||||
|
||||
get_tech = (db.session
|
||||
.query(Employee_Employee)
|
||||
.first())
|
||||
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)
|
||||
|
||||
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,
|
||||
)
|
||||
# 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.add(create_a_call)
|
||||
db.session.flush()
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
db.session.add(create_new_note)
|
||||
db.session.commit()
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({"ok": True,
|
||||
'user_id': get_customer.id,
|
||||
'service_id': create_a_call.id,
|
||||
}), 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)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({"ok": True}), 200
|
||||
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("/edit/<int:service_id>", methods=["PUT"])
|
||||
def service_edit_call(service_id):
|
||||
"""
|
||||
Update a service call
|
||||
"""
|
||||
@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
|
||||
|
||||
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"]
|
||||
# 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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
||||
@service.route("/update/type/<int:service_id>", methods=["PUT"])
|
||||
def service_update_service_type(service_id):
|
||||
"""
|
||||
Update a service call diagnosis
|
||||
"""
|
||||
get_service_type = request.json["service_type"]
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
db.session.add(create_new_note)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({"ok": True}), 200
|
||||
|
||||
|
||||
@service.route("/note/technician/<int:service_id>", methods=["PUT"])
|
||||
def service_create_note_technician(service_id):
|
||||
"""
|
||||
Technician can create notes on the call
|
||||
"""
|
||||
|
||||
service_technician_notes = request.json["technician_comments"]
|
||||
now = datetime.utcnow()
|
||||
|
||||
user = db.session \
|
||||
.query(Auth_User) \
|
||||
.filter(Auth_User.id == current_user.id) \
|
||||
.first()
|
||||
|
||||
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()
|
||||
|
||||
return jsonify({"ok": True}), 200
|
||||
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
7
app/social/__init__.py
Normal 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
77
app/social/views.py
Normal 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
0
app/stats/__init__.py
Normal file → Executable file
215
app/stats/views.py
Normal file → Executable file
215
app/stats/views.py
Normal file → Executable 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
7
app/ticket/__init__.py
Normal 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
14
app/ticket/views.py
Normal 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
24
config.py
Normal 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
|
||||
1
info_authorize_transactiopn_type.txt
Normal file
1
info_authorize_transactiopn_type.txt
Normal file
@@ -0,0 +1 @@
|
||||
# 0 = charge, 1 = auth, 3 = capture
|
||||
8
info_delivery_status.txt
Normal file
8
info_delivery_status.txt
Normal 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
7
info_home_type.txt
Normal 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
13
info_paymant_type.txt
Normal 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
7
info_state_list.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
0: MA
|
||||
1: RI
|
||||
2: NH
|
||||
3: ME
|
||||
4: VT
|
||||
5: CT
|
||||
6: NY
|
||||
17
nginx.conf
Normal file
17
nginx.conf
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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
20
requirements.txt.bak
Executable 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
|
||||
11
runProduction.py
Executable file
11
runProduction.py
Executable file
@@ -0,0 +1,11 @@
|
||||
# coding=utf-8
|
||||
from app import app
|
||||
|
||||
PORT = 6000
|
||||
HOST = '0.0.0.0'
|
||||
if __name__ == '__main__':
|
||||
app.run(
|
||||
host=HOST,
|
||||
port=PORT,
|
||||
threaded=True
|
||||
)
|
||||
55
settings_dev.py
Normal file
55
settings_dev.py
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
|
||||
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 = 'eamco'
|
||||
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(POSTGRES_USERNAME,
|
||||
POSTGRES_PW,
|
||||
POSTGRES_SERVER,
|
||||
POSTGRES_DBNAME00
|
||||
)
|
||||
SQLALCHEMY_BINDS = {'eamco': 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_ALLOWED_ORIGINS = [
|
||||
"*"
|
||||
]
|
||||
CORS_SEND_WILDCARD = False
|
||||
CORS_SUPPORT_CREDENTIALS = True
|
||||
CORS_EXPOSE_HEADERS = None
|
||||
CORS_ALLOW_HEADERS = "*"
|
||||
|
||||
|
||||
58
settings_local.py
Executable file
58
settings_local.py
Executable 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
56
settings_prod.py
Normal 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
8
start.sh
Normal 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
13
update_requirements.sh
Executable 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."
|
||||
Reference in New Issue
Block a user