init commit

This commit is contained in:
2025-08-31 17:55:26 +03:00
commit 876ddec94a
78 changed files with 11999 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
from flask import Blueprint
# Placeholder for blueprint registration if needed dynamically

View File

@@ -0,0 +1,204 @@
from flask import Blueprint, request, jsonify
from werkzeug.security import generate_password_hash, check_password_hash
from utils.email import send_email, send_gmail
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
from flask_jwt_extended import decode_token
import datetime
import random
import os
from datetime import timezone
from models.user import Users
auth_bp = Blueprint("auth", __name__)
@auth_bp.route("/register", methods=["POST"])
def register():
users = Users()
data = request.get_json()
name = data.get("name")
email = data.get("email")
password = data.get("password")
if not name or not email or not password:
return jsonify({"error": "Missing required fields"}), 400
existing_user = users.get_user_by_email(email)
if existing_user:
return jsonify({"error": "User already exists"}), 409
password_hash = generate_password_hash(password)
users.insert_user(name, email, password_hash)
return jsonify({"message": "User registered successfully!"}), 201
@auth_bp.route("/login", methods=["POST"])
def login():
users = Users()
data = request.get_json()
email = data.get("email", "").strip().lower()
password = data.get("password", "")
if not email or not password:
return jsonify({"error": "Missing email or password"}), 400
user = users.get_user_by_email(email)
if not user or not check_password_hash(user["password_hash"], password):
return jsonify({"error": "Invalid credentials"}), 401
otp_code = str(random.randint(100000, 999999))
expiration = datetime.datetime.now(timezone.utc) + datetime.timedelta(minutes=10)
users.update_user_otp(user["id"], otp_code, expiration)
send_gmail(
to_email=user["email"],
subject="Your Login Verification Code",
body=f"Your login verification code is: {otp_code}"
)
return jsonify({"message": "Verification code sent to your email."}), 200
@auth_bp.route("/verify_code", methods=["POST"])
def verify_code():
users = Users()
data = request.get_json()
email = data.get("email", "").strip().lower()
code = data.get("code", "")
if not email or not code:
return jsonify({"error": "Missing email or verification code"}), 400
user = users.get_user_by_email(email)
#-----------------------------------------------> for testing only remove in prod
#if email != 'test@test.com':
#-----------------------------------------------> for testing only remove in prod
if not user or user.get("otp_code") != code:
return jsonify({"error": "Invalid code"}), 401
exp = user.get("otp_expiration")
# Normalize to aware UTC datetime for safe comparison across SQLite (string) and Postgres (datetime)
now_utc = datetime.datetime.now(timezone.utc)
if isinstance(exp, str):
try:
exp_dt = datetime.datetime.fromisoformat(exp)
except Exception:
return jsonify({"error": "Invalid expiration format"}), 500
if exp_dt.tzinfo is None:
exp_dt = exp_dt.replace(tzinfo=timezone.utc)
else:
# Assume a datetime object from DB driver
exp_dt = exp
if exp_dt is None:
return jsonify({"error": "Missing expiration"}), 500
if exp_dt.tzinfo is None:
exp_dt = exp_dt.replace(tzinfo=timezone.utc)
if now_utc > exp_dt:
return jsonify({"error": "Verification code has expired"}), 403
users.clear_user_otp(user["id"])
access_token = create_access_token(
identity=str(user["id"]),
expires_delta=datetime.timedelta(hours=12)
)
return jsonify({
"message": "Login successful",
"access_token": access_token
}), 200
@auth_bp.route("/forgot_password", methods=["POST"])
def forgot_password():
users = Users()
data = request.get_json()
email = data.get("email", "").strip().lower()
if not email:
return jsonify({"error": "Email is required"}), 400
user = users.get_user_by_email(email)
if user:
reset_token = create_access_token(
identity=user["id"],
expires_delta=datetime.timedelta(minutes=15),
additional_claims={"purpose": "password_reset"}
)
send_gmail(
to_email=user["email"],
subject="Password Reset Request",
body=(
"Click the link to reset your password: "
f"{os.getenv('FRONTEND_BASE_URL', 'http://127.0.0.1:5100')}/reset_password?token={reset_token}"
)
)
return jsonify({"message": "If this email is registered, a reset link has been sent."}), 200
@auth_bp.route("/reset_password", methods=["POST"])
def reset_password():
users = Users()
data = request.get_json()
token = data.get("token", "")
new_password = data.get("new_password", "")
if not token or not new_password:
return jsonify({"error": "Missing token or new password"}), 400
try:
decoded_token = decode_token(token)
if decoded_token.get("purpose") != "password_reset":
return jsonify({"error": "Invalid token purpose"}), 403
except Exception:
return jsonify({"error": "Invalid or expired token"}), 403
user_id = decoded_token["sub"]
user = users.get_user_by_id(user_id)
if not user:
return jsonify({"error": "User not found"}), 404
password_hash = generate_password_hash(new_password)
users.update_user_password(user_id, password_hash)
return jsonify({"message": "Password has been reset successfully."}), 200
@auth_bp.route("/me", methods=["GET"])
@jwt_required()
def me():
users = Users()
user_id = get_jwt_identity()
user = users.get_user_by_id(user_id)
if not user:
return jsonify({"error": "User not found"}), 404
return jsonify({
"id": user["id"],
"name": user["name"],
"contact_name": user['contact_name'],
"email": user["email"],
"phone": user["phone"],
"register_number": user["register_number"],
"vat":user["vat"],
"address": user["address"],
"logo_filename": user["logo_filename"],
"terms": user["terms"],
"first_order_number": user["first_order_number"],
"created_at": user["created_at"],
"user_role": user["user_role"]
}), 200
# Validate token endpoint
@auth_bp.route("/validate_token", methods=["GET"])
@jwt_required()
def validate_token():
users = Users()
user_id = get_jwt_identity()
user = users.get_user_by_id(user_id)
if not user:
return jsonify({"error": "User not found"}), 404
return jsonify({"message": "Token is valid"}), 200

View File

@@ -0,0 +1,65 @@
from flask import Blueprint, request, jsonify
from models.client import Clients
from flask_jwt_extended import jwt_required, get_jwt_identity
clients_bp = Blueprint("clients", __name__, url_prefix="/clients")
@clients_bp.route("/", methods=["GET"])
@jwt_required()
def list_clients():
clients_db = Clients()
user_id = get_jwt_identity()
clients = clients_db.get_all_by_user(user_id)
return jsonify(clients), 200
@clients_bp.route("/", methods=["POST"])
@jwt_required()
def create_client():
clients_db = Clients()
user_id = get_jwt_identity()
data = request.get_json()
client_id = clients_db.create(
user_id=user_id,
name=data["name"],
address=data["address"],
register_number=data["register_number"],
contact_person=data["contact_person"],
phone=data["phone"],
email=data["email"],
vat = data["vat"]
)
return jsonify({"message": "Client created", "id": client_id}), 201
@clients_bp.route("/<int:client_id>", methods=["PUT"])
@jwt_required()
def update_client(client_id):
clients_db = Clients()
data = request.get_json()
name=data["name"]
address=data["address"]
register_number=data["register_number"]
contact_person=data["contact_person"]
phone=data["phone"]
email=data["email"]
vat = data["vat"]
clients_db.update(client_id, name, address, register_number, contact_person, phone, email, vat)
return jsonify({"message": "Client updated"}), 200
@clients_bp.route("/<int:client_id>", methods=["DELETE"])
@jwt_required()
def delete_client(client_id):
clients_db = Clients()
success = clients_db.delete(client_id)
if not success:
return jsonify({"message": "Client not found or unauthorized"}), 404
return jsonify({"message": "Client deleted"}), 200
@clients_bp.route("/<int:client_id>", methods=["GET"])
@jwt_required()
def get_client(client_id):
clients_db = Clients()
client = clients_db.get_by_id(client_id)
if not client:
return jsonify({"message": "Client not found"}), 404
return jsonify(client), 200

View File

@@ -0,0 +1,73 @@
from flask import Blueprint, request, jsonify
from models.destinations import Destinations
from flask_jwt_extended import jwt_required, get_jwt_identity
from utils.maps import AdressCoordinates
destinations_bp = Blueprint("destinations", __name__, url_prefix="/destinations")
@destinations_bp.route("/", methods=["GET"])
@jwt_required()
def list_destinations():
destinations_db = Destinations()
user_id = get_jwt_identity()
destinations = destinations_db.get_all_by_user(user_id)
return jsonify([dict(d) for d in destinations]), 200
@destinations_bp.route("/", methods=["POST"])
@jwt_required()
def create_destination():
destinations_db = Destinations()
user_id = get_jwt_identity()
data = request.get_json()
destination_id = destinations_db.create(user_id, data.get("name"), data.get("address"))
# coordinates = AdressCoordinates(data.get("address"))
# lat_log = coordinates.open_Maps_by_address()
# if lat_log:
# latitude = lat_log['latitude']
# longitude = lat_log['longitude']
# destinations_db.add_gps_coordinates(destination_id, latitude, longitude)
return jsonify({"id": destination_id, "message": "Destination created"}), 201
@destinations_bp.route("/<int:id>", methods=["PUT"])
@jwt_required()
def update_destination(id):
destinations_db = Destinations()
user_id = get_jwt_identity()
data = request.get_json()
destinations_db.update(id, user_id, data.get("name"), data.get("address"))
coordinates = AdressCoordinates(data.get("address"))
lat_log = coordinates.open_Maps_by_address()
if lat_log:
latitude = lat_log['latitude']
longitude = lat_log['longitude']
destinations_db.add_gps_coordinates(id, latitude, longitude)
return jsonify({"message": "Destination updated"}), 200
@destinations_bp.route("/<int:id>", methods=["DELETE"])
@jwt_required()
def delete_destination(id):
destinations_db = Destinations()
success = destinations_db.delete(id)
if not success:
return jsonify({"message": "Destination not found or unauthorized"}), 404
return "", 204
# New route to update GPS coordinates of a destination
@destinations_bp.route("/<int:id>/coordinates", methods=["PUT"])
@jwt_required()
def update_coordinates(id):
destinations_db = Destinations()
data = request.get_json()
latitude = data.get("latitude")
longitude = data.get("longitude")
if latitude is None or longitude is None:
return jsonify({"message": "Latitude and longitude are required"}), 400
success = destinations_db.add_gps_coordinates(id, latitude, longitude)
if not success:
return jsonify({"message": "Failed to update coordinates"}), 404
return jsonify({"message": "Coordinates updated"}), 200

View File

@@ -0,0 +1,259 @@
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from models.order_out import OrdersOut
from models.user import Users
from models.transporters import Transporters
from datetime import datetime
from utils.pdf import generate_order_pdf
from utils.cancel_order import cancel_order_pdf
import os
from flask import send_from_directory
from utils.email import send_gmail_with_attachment, send_custom_email_with_attachment
orders_bp = Blueprint("orders", __name__, url_prefix="/orders")
@orders_bp.route("/", methods=["POST"])
@jwt_required()
def create_order_route():
user_id = get_jwt_identity()
orders = OrdersOut()
incoming_data = request.json
#here we need to first implement the order pdf
users = Users()
user = users.get_user_by_id(user_id)
logo_filename = user.get('logo_filename')
logo_path = None
if logo_filename:
logo_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), "..", "..", "client", "assets", "images", logo_filename)
)
transporters = Transporters()
transporter = transporters.get_transporter_by_id(incoming_data["transporter_id"])
generate_order_pdf(order=incoming_data, user_data=user, transporter_data=transporter, logo_path=logo_path)
#
#try:
order_data = {
'user_id': user_id,
'client_id': incoming_data["client_id"],
'transporter_id': incoming_data["transporter_id"],
'received_price': incoming_data["received_price"],
'paid_price': incoming_data["paid_price"],
'order_number': incoming_data["order_number"],
'created_at': datetime.now(),
'ldb_quantity': incoming_data["ldb_quantity"],
'kg_quantity': incoming_data["kg_quantity"],
'track_reg_number': incoming_data["track_reg_number"],
'trailer_reg_number': incoming_data["trailer_reg_number"],
'products_description': incoming_data["products_description"],
}
order_id = orders.create_order(order_data)
for address in incoming_data["loading_addresses"]:
data = {
"order_id": order_id,
"destination_id": address['loading_address_id'],
"informatins": address['loading_informatins'],
"point_data": address['loading_date'],
"point_hour": address['loading_hour'],
"point_type": "loading"
}
orders.create_order_point(data)
for address in incoming_data["unloading_addresses"]:
data = {
"order_id": order_id,
"destination_id": address['unloading_address_id'],
"informatins": address['unloading_informatins'],
"point_data": address['unloading_date'],
"point_hour": address['unloading_hour'],
"point_type": "unloading"
}
orders.create_order_point(data)
return jsonify({"message": "Order created", "order_id": order_id}), 201
#except Exception as e:
# return jsonify({"error": str(e)}), 400
@orders_bp.route("/<int:order_id>", methods=["PUT"])
@jwt_required()
def update_order_route(order_id):
orders = OrdersOut()
data = request.json
user_id = get_jwt_identity()
order = orders.get_order_by_id(order_id)
if not order:
return jsonify({"error": "Order not found"}), 404
if str(order["user_id"]) != str(user_id):
return jsonify({"error": "Unauthorized"}), 403
try:
orders.update_order({
"id":data.get("id", order['id']),
"client_id": data.get("client_id", order["client_id"]),
"transporter_id": data.get("transporter_id", order["transporter_id"]),
"received_price": data.get("received_price", order["received_price"]),
"paid_price": data.get("paid_price", order["paid_price"]),
"order_number": data.get("order_number", order["order_number"]),
"ldb_quantity": data.get("ldb_quantity", order["ldb_quantity"]),
"kg_quantity": data.get("kg_quantity", order["kg_quantity"]),
"track_reg_number": data.get("track_reg_number", order["track_reg_number"]),
"trailer_reg_number": data.get("trailer_reg_number", order["trailer_reg_number"]),
"products_description": data.get("products_description", order["products_description"]),
})
orders.delete_points_by_order_id(order_id)
for address in data["loading_addresses"]:
loading_data = {
"order_id": order_id,
"destination_id": address['loading_address_id'],
"informatins": address['loading_informatins'],
"point_data": address['loading_date'],
"point_hour": address['loading_hour'],
"point_type": "loading"
}
orders.create_order_point(loading_data)
for address in data["unloading_addresses"]:
unloading_data = {
"order_id": order_id,
"destination_id": address['unloading_address_id'],
"informatins": address['unloading_informatins'],
"point_data": address['unloading_date'],
"point_hour": address['unloading_hour'],
"point_type": "unloading"
}
orders.create_order_point(unloading_data)
#regenerate pdf:
incoming_data = data
users = Users()
user = users.get_user_by_id(user_id)
transporters = Transporters()
transporter = transporters.get_transporter_by_id(incoming_data["transporter_id"])
logo_filename = user.get('logo_filename')
logo_path = None
if logo_filename:
logo_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), "..", "..", "client", "assets", "images", logo_filename)
)
generate_order_pdf(order=incoming_data, user_data=user, transporter_data=transporter, logo_path=logo_path)
return jsonify({"message": "Order updated", "order_id": order_id}), 200
except Exception as e:
return jsonify({"error": str(e)}), 400
@orders_bp.route("/<int:order_id>", methods=["DELETE"])
@jwt_required()
def delete_order_route(order_id):
orders = OrdersOut()
user_id = get_jwt_identity()
order = orders.get_order_by_id(order_id)
if not order:
return jsonify({"error": "Order not found"}), 404
if order["user_id"] != user_id:
return jsonify({"error": "Unauthorized"}), 403
try:
orders.delete_points_by_order_id(order_id)
orders.delete_order(order_id)
return jsonify({"message": "Order deleted"}), 200
except Exception as e:
return jsonify({"error": str(e)}), 400
@orders_bp.route("/list", methods=["GET"])
@jwt_required()
def list_orders():
orders = OrdersOut()
user_id = get_jwt_identity()
try:
user_orders = orders.get_orders_by_user(user_id)
#result = [{"id": order["id"], "order_number": order["order_number"]} for order in user_orders]
return jsonify(user_orders), 200
except Exception as e:
return jsonify({"error": str(e)}), 400
@orders_bp.route("/<int:order_id>", methods=["GET"])
@jwt_required()
def get_order(order_id):
orders = OrdersOut()
user_id = get_jwt_identity()
order = orders.get_order_by_id(order_id)
points = orders.get_order_points_by_order(order['id'])
loading_points = []
unloading_points = []
for point in points:
if point['point_type'] == 'loading':
loading_points.append(point)
else:
unloading_points.append(point)
order['loading_points'] = loading_points
order['unloading_points'] = unloading_points
if not order:
return jsonify({"error": "Order not found"}), 404
print(f'{order["user_id"]} {user_id}')
print(f'{type(order["user_id"])} {type(user_id)}')
if order["user_id"] != int(user_id):
return jsonify({"error": "Unauthorized"}), 403
return jsonify(order), 200
@orders_bp.route("/pdfs/<path:filename>", methods=["GET"])
#@jwt_required()
def serve_order_pdf(filename):
pdf_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "generated_pdfs"))
print(pdf_folder)
print(filename)
return send_from_directory(pdf_folder, filename, mimetype="application/pdf")
@orders_bp.route("/send-email/gmail", methods=["POST"])
@jwt_required()
def send_email_with_gmail():
data = request.json
try:
to_email = data["to_email"]
subject = data["subject"]
body = data["body"]
filename = data["filename"]
attachment_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "uploads", filename))
send_gmail_with_attachment(to_email, subject, body, attachment_path)
return jsonify({"message": "Email sent successfully using Gmail"}), 200
except Exception as e:
return jsonify({"error": str(e)}), 400
@orders_bp.route("/send-email/custom", methods=["POST"])
@jwt_required()
def send_email_with_custom_smtp():
data = request.json
try:
to_email = data["to_email"]
subject = data["subject"]
body = data["body"]
filename = data["filename"]
smtp_host = data["smtp_host"]
smtp_port = data["smtp_port"]
smtp_user = data["smtp_user"]
smtp_pass = data["smtp_pass"]
attachment_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "uploads", filename))
send_custom_email_with_attachment(to_email, subject, body, attachment_path, smtp_host, smtp_port, smtp_user, smtp_pass)
return jsonify({"message": "Email sent successfully using custom SMTP"}), 200
except Exception as e:
return jsonify({"error": str(e)}), 400
@orders_bp.route("/cancel/<int:order_id>", methods=["DELETE"])
@jwt_required()
def cancel_order(order_id):
try:
orders = OrdersOut()
order = orders.get_order_by_id(order_id)
user_id = get_jwt_identity()
pdf_name = f'order_{user_id}_{order['order_number']}.pdf'
cancel_order_pdf(pdf_name)
orders.cancel_order(order_id)
return jsonify({"message": "The order was successfully canceled!"}), 200
except Exception as e:
return jsonify({"error": str(e)}), 500

View File

@@ -0,0 +1,163 @@
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from models.order_in import OrdersIn
from models.transporters import Transporters
from models.user import Users
from datetime import datetime
orders_in_bp = Blueprint("orders_in", __name__, url_prefix="/orders_in")
@orders_in_bp.route("/", methods=["POST"])
@jwt_required()
def create_order_in_route():
user_id = get_jwt_identity()
orders = OrdersIn()
incoming_data = request.json
try:
order_data = {
'user_id': user_id,
'client_id': incoming_data["client_id"],
'received_price': incoming_data["received_price"],
'order_number': incoming_data["order_number"],
'created_at': datetime.now(),
'ldb_quantity': incoming_data["ldb_quantity"],
'kg_quantity': incoming_data["kg_quantity"],
'track_reg_number': incoming_data["track_reg_number"],
'trailer_reg_number': incoming_data["trailer_reg_number"],
'products_description': incoming_data["products_description"],
}
order_id = orders.create_order(order_data)
for address in incoming_data["loading_addresses"]:
data = {
"order_id": order_id,
"destination_id": address['loading_address_id'],
"informatins": address['loading_informatins'],
"point_data": address['loading_date'],
"point_hour": address['loading_hour'],
"point_type": "loading"
}
orders.create_order_point(data)
for address in incoming_data["unloading_addresses"]:
data = {
"order_id": order_id,
"destination_id": address['unloading_address_id'],
"informatins": address['unloading_informatins'],
"point_data": address['unloading_date'],
"point_hour": address['unloading_hour'],
"point_type": "unloading"
}
orders.create_order_point(data)
return jsonify({"message": "Order in created", "order_id": order_id}), 201
except Exception as e:
return jsonify({"error": str(e)}), 400
@orders_in_bp.route("/<int:order_id>", methods=["PUT"])
@jwt_required()
def update_order_route(order_id):
orders = OrdersIn()
data = request.json
user_id = get_jwt_identity()
order = orders.get_order_by_id(order_id)
if not order:
return jsonify({"error": "Order in not found"}), 404
if str(order["user_id"]) != str(user_id):
return jsonify({"error": "Unauthorized"}), 403
try:
orders.update_order({
"id":data.get("id", order['id']),
"client_id": data.get("client_id", order["client_id"]),
"received_price": data.get("received_price", order["received_price"]),
"order_number": data.get("order_number", order["order_number"]),
"ldb_quantity": data.get("ldb_quantity", order["ldb_quantity"]),
"kg_quantity": data.get("kg_quantity", order["kg_quantity"]),
"track_reg_number": data.get("track_reg_number", order["track_reg_number"]),
"trailer_reg_number": data.get("trailer_reg_number", order["trailer_reg_number"]),
"products_description": data.get("products_description", order["products_description"]),
"user_id":user_id
})
orders.delete_points_by_order_id(order_id)
for address in data["loading_addresses"]:
loading_data = {
"order_id": order_id,
"destination_id": address['loading_address_id'],
"informatins": address['loading_informatins'],
"point_data": address['loading_date'],
"point_hour": address['loading_hour'],
"point_type": "loading"
}
orders.create_order_point(loading_data)
for address in data["unloading_addresses"]:
unloading_data = {
"order_id": order_id,
"destination_id": address['unloading_address_id'],
"informatins": address['unloading_informatins'],
"point_data": address['unloading_date'],
"point_hour": address['unloading_hour'],
"point_type": "unloading"
}
orders.create_order_point(unloading_data)
return jsonify({"message": "Order updated"}), 200
except Exception as e:
return jsonify({"error": str(e)}), 400
@orders_in_bp.route("/<int:order_id>", methods=["DELETE"])
@jwt_required()
def delete_order_route(order_id):
orders = OrdersIn()
user_id = get_jwt_identity()
order = orders.get_order_by_id(order_id)
if not order:
return jsonify({"error": "Order in not found"}), 404
if str(order["user_id"]) != str(user_id):
return jsonify({"error": "Unauthorized"}), 403
try:
orders.delete_points_by_order_id(order_id)
orders.delete_order(order_id)
return jsonify({"message": "Order in deleted"}), 200
except Exception as e:
return jsonify({"error": str(e)}), 400
@orders_in_bp.route("/list", methods=["GET"])
@jwt_required()
def list_orders():
orders = OrdersIn()
user_id = get_jwt_identity()
try:
user_orders = orders.get_orders_by_user(user_id)
#result = [{"id": order["id"], "order_number": order["order_number"]} for order in user_orders]
return jsonify(user_orders), 200
except Exception as e:
return jsonify({"error": str(e)}), 400
@orders_in_bp.route("/<int:order_id>", methods=["GET"])
@jwt_required()
def get_order(order_id):
orders = OrdersIn()
user_id = get_jwt_identity()
order = orders.get_order_by_id(order_id)
points = orders.get_order_points_by_order(order['id'])
loading_points = []
unloading_points = []
for point in points:
if point['point_type'] == 'loading':
loading_points.append(point)
else:
unloading_points.append(point)
order['loading_points'] = loading_points
order['unloading_points'] = unloading_points
if not order:
return jsonify({"error": "Order not found"}), 404
print(f'{order["user_id"]} {user_id}')
print(f'{type(order["user_id"])} {type(user_id)}')
if order["user_id"] != int(user_id):
return jsonify({"error": "Unauthorized"}), 403
return jsonify(order), 200

View File

@@ -0,0 +1,144 @@
import os
from werkzeug.utils import secure_filename
from flask import current_app
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from models.user import Users
profile_bp = Blueprint("profile", __name__)
@profile_bp.route("/", methods=["GET"])
@jwt_required()
def get_profile():
user_id = get_jwt_identity()
users = Users()
user = users.get_user_by_id(user_id) # Plain SQL method returning dict or None
if not user:
return jsonify({"error": "User not found"}), 404
return jsonify({
"id": user["id"],
"name": user["name"],
"contact_name": user["contact_name"],
"email": user["email"],
"address": user["address"],
"register_number": user["register_number"],
"phone": user["phone"],
"logo_filename": user["logo_filename"],
"terms": user["terms"],
"first_order_number": user["first_order_number"],
"user_role": user["user_role"],
"vat":user["vat"]
})
@profile_bp.route("/", methods=["PUT"])
@jwt_required()
def update_profile():
users = Users()
user_id = get_jwt_identity()
user = users.get_user_by_id(user_id)
if not user:
return jsonify({"error": "User not found"}), 404
data = request.get_json()
update_data = {
"name": data.get("name", user["name"]),
"contact_name": data.get("contact_name", user["contact_name"]),
"email": data.get("email", user["email"]),
"address": data.get("address", user["address"]),
"register_number": data.get("register_number", user["register_number"]),
"phone": data.get("phone", user["phone"]),
"logo_filename": data.get("logo_filename", user["logo_filename"]),
"terms": data.get("terms", user["terms"]),
"first_order_number": data.get("first_order_number", user["first_order_number"]),
"user_id": user_id,
"vat":data.get("vat", user["vat"]),
}
users.update_user(update_data)
return jsonify({"message": "Profile updated successfully"})
@profile_bp.route("/logo", methods=["POST"])
@jwt_required()
def upload_logo():
users = Users()
if 'logo' not in request.files:
return jsonify({"error": "Logo file is required"}), 400
file = request.files['logo']
if file.filename == '':
return jsonify({"error": "No selected file"}), 400
filename = secure_filename(file.filename)
upload_dir = os.path.join(current_app.root_path, '..', 'instance', 'logos')
os.makedirs(upload_dir, exist_ok=True)
filepath = os.path.join(upload_dir, filename)
file.save(filepath)
user_id = get_jwt_identity()
user = users.get_user_by_id(user_id)
if not user:
return jsonify({"error": "User not found"}), 404
# Update the logo filename in DB
users.update_user_logo(user_id, {"logo_filename": filename})
return jsonify({"message": "Logo uploaded", "filename": filename}), 200
@profile_bp.route('/email')
@jwt_required()
def get_email_credentials():
user_id = get_jwt_identity()
users = Users()
credentials = users.get_email_credentials(user_id)
if not credentials:
return jsonify({"error": "Credentials not found"}), 404
return jsonify({
'id': credentials['id'],
'user_id': credentials['user_id'],
'smtp_host': credentials['smtp_host'],
'smtp_port': credentials['smtp_port'],
'smtp_user': credentials['smtp_user'],
'created_at': credentials['created_at']
}), 200
@profile_bp.route('/email', methods=["POST"])
@jwt_required()
def insert_email_credentials():
users = Users()
user_id = get_jwt_identity()
data = request.get_json()
if not data:
return jsonify({"error": "Credentials not found"}), 404
smtp_host = data['smtp_host']
smtp_port = data['smtp_port']
smtp_user = data['smtp_user']
users.insert_email_credentials(user_id, smtp_host, smtp_port, smtp_user)
return jsonify({"message": "Credentials inserted successfully"}), 200
@profile_bp.route('/email', methods=["PUT"])
@jwt_required()
def update_email_credentials():
users = Users()
user_id = get_jwt_identity()
data = request.get_json()
if not data:
return jsonify({"error": "Credentials not found"}), 404
smtp_host = data['smtp_host']
smtp_port = data['smtp_port']
smtp_user = data['smtp_user']
users.update_email_credentials(user_id, smtp_host, smtp_port, smtp_user)
return jsonify({"message": "Credentials updated successfully"}), 200

View File

@@ -0,0 +1,42 @@
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from models.order_out import OrdersOut # Your plain SQL model
from datetime import datetime
report_bp = Blueprint("report", __name__, url_prefix="/report")
@report_bp.route("/profit", methods=["GET"])
@jwt_required()
def get_profit_report():
try:
user_id = get_jwt_identity()
# Get filters from query params
date_from = request.args.get("date_from")
date_to = request.args.get("date_to")
client_id = request.args.get("client_id")
transporter_id = request.args.get("transporter_id")
# Use the plain SQL method that returns filtered orders list
filters = {
"user_id": user_id,
"date_from": date_from,
"date_to": date_to,
"client_id": client_id,
"transporter_id": transporter_id
}
orders = OrdersOut.get_filtered_orders(filters) # Implement this method in your model
total_received = sum(float(o.get("price_received", 0) or 0) for o in orders)
total_paid = sum(float(o.get("price_paid", 0) or 0) for o in orders)
profit = total_received - total_paid
return jsonify({
"total_received": total_received,
"total_paid": total_paid,
"profit": profit,
"orders_count": len(orders)
})
except Exception as e:
return jsonify({"error": str(e)}), 500

View File

@@ -0,0 +1,65 @@
from flask import Blueprint, jsonify, request
from flask_jwt_extended import jwt_required, get_jwt_identity
from datetime import datetime, timedelta
from models.subscription import Subscription
from models.user import Users
from datetime import datetime, timedelta
subscription_bp = Blueprint("subscription", __name__, url_prefix="/subscription")
@subscription_bp.route("/", methods=["GET"])
@jwt_required()
def get_subscription():
user_id = get_jwt_identity()
subscription_model = Subscription()
subscriptions = subscription_model.get_by_user_id(user_id)
return jsonify(subscriptions), 200
@subscription_bp.route("/first_2_months", methods=["POST"])
@jwt_required()
def first_2_months_subscription():
user_id = get_jwt_identity()
users_model = Users()
user = users_model.get_user_by_id(user_id)
subscription_model = Subscription()
existing_sub = subscription_model.get_first_2_months_subscription_for_register_number(user["register_number"])
if existing_sub:
return jsonify({"error": "First 2 months subscription already used for this company."}), 400
start_date = datetime.now()
end_date = start_date + timedelta(days=60)
subscription_model.create(user_id, "first_2_months", start_date.isoformat(), end_date.isoformat(), user["register_number"])
return jsonify({"message": "First 2 months subscription created."}), 201
@subscription_bp.route("/one_month", methods=["POST"])
@jwt_required()
def one_month_subscription():
user_id = get_jwt_identity()
start_date = datetime.now()
end_date = start_date + timedelta(days=30)
users_model = Users()
user = users_model.get_user_by_id(user_id)
subscription_model = Subscription()
subscription_model.create(user_id, "monthly", start_date.isoformat(), end_date.isoformat(), user["register_number"])
return jsonify({"message": "1 month subscription created."}), 201
@subscription_bp.route("/one_year", methods=["POST"])
@jwt_required()
def one_year_subscription():
user_id = get_jwt_identity()
start_date = datetime.now()
end_date = start_date + timedelta(days=365)
users_model = Users()
user = users_model.get_user_by_id(user_id)
subscription_model = Subscription()
subscription_model.create(user_id, "yearly", start_date.isoformat(), end_date.isoformat(), user["register_number"])
return jsonify({"message": "1 year subscription created."}), 201

View File

@@ -0,0 +1,74 @@
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from models.transporters import Transporters
transporters_bp = Blueprint("transporters", __name__, url_prefix="/transporters")
@transporters_bp.route("/", methods=["GET"])
@jwt_required()
def list_transporters():
user_id = get_jwt_identity()
transporters_db = Transporters()
transporters = transporters_db.get_all_transporters_by_user(user_id)
return jsonify(transporters), 200
@transporters_bp.route("/", methods=["POST"])
@jwt_required()
def create_transporter():
transporters_db = Transporters()
data = request.get_json()
user_id = get_jwt_identity()
transporter_id = transporters_db.create_transporter(
user_id=user_id,
name=data.get("name"),
address=data.get("address"),
register_number=data.get("register_number"),
contact_person=data.get("contact_person"),
phone=data.get("phone"),
email=data.get("email"),
vat = data.get("vat")
)
transporter = transporters_db.get_transporter_by_id(transporter_id)
return jsonify(transporter), 201
@transporters_bp.route("/<int:transporter_id>", methods=["PUT"])
@jwt_required()
def update_transporter(transporter_id):
transporters_db = Transporters()
user_id = get_jwt_identity()
data = request.get_json()
transporter = transporters_db.get_transporter_by_id(transporter_id)
if not transporter:
return jsonify({"error": "Transporter not found"}), 404
transporters_db.update_transporter(
transporter_id=transporter_id,
name=data.get("name"),
address=data.get("address"),
register_number=data.get("register_number"),
contact_person=data.get("contact_person"),
phone=data.get("phone"),
email=data.get("email"),
vat=data.get("vat")
)
updated_transporter = transporters_db.get_transporter_by_id(transporter_id)
return jsonify(updated_transporter), 200
@transporters_bp.route("/<int:transporter_id>", methods=["DELETE"])
@jwt_required()
def delete_transporter(transporter_id):
transporters_db = Transporters()
user_id = get_jwt_identity()
transporter = transporters_db.get_transporter_by_id(transporter_id)
if not transporter:
return jsonify({"error": "Transporter not found"}), 404
transporters_db.delete_transporter(transporter_id)
return jsonify({"message": "Transporter deleted"}), 200
@transporters_bp.route("/<int:transporter_id>", methods=["GET"])
@jwt_required()
def get_transporter(transporter_id):
transporters_db = Transporters()
transporter = transporters_db.get_transporter_by_id(transporter_id)
if not transporter:
return jsonify({"error": "Transporter not found"}), 404
return jsonify(transporter), 200