intrgrating suggestions after betta 1
This commit is contained in:
@@ -5,13 +5,21 @@ from models.user import Users
|
||||
admin_user_bp = Blueprint("admin_user", __name__, url_prefix="/admin/users")
|
||||
|
||||
# Get all users with role "user"
|
||||
@admin_user_bp.route("", methods=["GET"])
|
||||
@admin_user_bp.route("/", methods=["GET"])
|
||||
@jwt_required()
|
||||
def get_all_users():
|
||||
users_model = Users()
|
||||
users = users_model.get_all_users_with_role("user")
|
||||
return jsonify(users), 200
|
||||
|
||||
# Get all users with role "user"
|
||||
@admin_user_bp.route("/company_users", methods=["GET"])
|
||||
@jwt_required()
|
||||
def get_all_company_users():
|
||||
users_model = Users()
|
||||
users = users_model.get_all_users_with_role("company_user")
|
||||
return jsonify(users), 200
|
||||
|
||||
# Get a single user by ID
|
||||
@admin_user_bp.route("/<int:user_id>", methods=["GET"])
|
||||
@jwt_required()
|
||||
@@ -38,3 +46,21 @@ def update_user():
|
||||
users_model.update_user(data)
|
||||
|
||||
return jsonify({"message": "User updated successfully."}), 200
|
||||
|
||||
# Deactivate
|
||||
@admin_user_bp.route("/deactivate", methods=["POST"])
|
||||
@jwt_required()
|
||||
def deactivate_user():
|
||||
if not request.is_json:
|
||||
print("Content-Type received:", request.content_type)
|
||||
return jsonify({"error": "Invalid content type, must be application/json"}), 415
|
||||
|
||||
data = request.get_json()
|
||||
user_id = data.get("user_id")
|
||||
if not user_id:
|
||||
return jsonify({"error": "Missing user_id"}), 400
|
||||
|
||||
users_model = Users()
|
||||
users_model.deactivate_user(user_id)
|
||||
|
||||
return jsonify({"message": "User updated successfully."}), 200
|
||||
@@ -12,6 +12,7 @@ from routes.report import report_bp
|
||||
from admin.subscription import admin_subscription_bp
|
||||
from routes.subscription import subscription_bp
|
||||
from admin.tenants import admin_user_bp
|
||||
from routes.company_user import company_user_bp
|
||||
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from models.subscription import Subscription
|
||||
@@ -69,7 +70,7 @@ app.register_blueprint(report_bp, url_prefix="/report")
|
||||
app.register_blueprint(admin_subscription_bp)
|
||||
app.register_blueprint(subscription_bp)
|
||||
app.register_blueprint(admin_user_bp)
|
||||
|
||||
app.register_blueprint(company_user_bp)
|
||||
|
||||
def update_subscription_statuses_job():
|
||||
print("[Scheduler] Running daily subscription status check...")
|
||||
|
||||
BIN
transportmanager/server/assets/Manual.pdf
Normal file
BIN
transportmanager/server/assets/Manual.pdf
Normal file
Binary file not shown.
81
transportmanager/server/models/company_users.py
Normal file
81
transportmanager/server/models/company_users.py
Normal file
@@ -0,0 +1,81 @@
|
||||
from datetime import datetime
|
||||
from database import get_connection, is_postgres
|
||||
|
||||
class CompanyUsers:
|
||||
def __init__(self):
|
||||
self.ph = "%s" if is_postgres() else "?"
|
||||
|
||||
def access_to_dict(self, row):
|
||||
access = {
|
||||
'id': row[0],
|
||||
'company_user_id': row[1],
|
||||
'clients': row[2],
|
||||
'transporters': row[3],
|
||||
'destinations': row[4],
|
||||
'orders_in': row[5],
|
||||
'orders_out': row[6],
|
||||
'report':row[7],
|
||||
'created_at': row[8]
|
||||
}
|
||||
return access
|
||||
|
||||
def insert_company_user_access(self, access_data):
|
||||
created_at = datetime.now().isoformat()
|
||||
with get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
returning = "RETURNING id" if is_postgres() else ""
|
||||
query = f"""
|
||||
INSERT INTO company_user_access (
|
||||
company_user_id, clients, transporters, destinations, orders_in, orders_out, report, created_at
|
||||
) VALUES ({self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}) {returning}
|
||||
"""
|
||||
cursor.execute(
|
||||
query,
|
||||
(
|
||||
access_data['company_user_id'],
|
||||
access_data['clients'],
|
||||
access_data['transporters'],
|
||||
access_data['destinations'],
|
||||
access_data['orders_in'],
|
||||
access_data['orders_out'],
|
||||
access_data['report'],
|
||||
created_at
|
||||
)
|
||||
)
|
||||
inserted_id = None
|
||||
if is_postgres():
|
||||
inserted_id = cursor.fetchone()[0]
|
||||
else:
|
||||
inserted_id = cursor.lastrowid
|
||||
if hasattr(conn, "commit"):
|
||||
conn.commit()
|
||||
return inserted_id
|
||||
|
||||
def get_access_by_company_user_id(self, company_user_id):
|
||||
with get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(f"SELECT * FROM company_user_access WHERE company_user_id = {self.ph}", (company_user_id,))
|
||||
row = cursor.fetchone()
|
||||
return self.access_to_dict(row) if row else None
|
||||
|
||||
def update_company_user_access(self, data):
|
||||
with get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
f"""
|
||||
UPDATE company_user_access
|
||||
SET clients = {self.ph}, transporters = {self.ph}, destinations = {self.ph}, orders_in = {self.ph}, orders_out = {self.ph}, report = {self.ph}
|
||||
WHERE company_user_id = {self.ph}
|
||||
""",
|
||||
(
|
||||
data['clients'],
|
||||
data['transporters'],
|
||||
data['destinations'],
|
||||
data['orders_in'],
|
||||
data['orders_out'],
|
||||
data['report'],
|
||||
data['company_user_id']
|
||||
)
|
||||
)
|
||||
if hasattr(conn, "commit"):
|
||||
conn.commit()
|
||||
@@ -19,6 +19,8 @@ class OrdersIn:
|
||||
"trailer_reg_number": row[8],
|
||||
"received_price": row[9],
|
||||
"created_at": row[10],
|
||||
"file":row[11],
|
||||
"expenses": row[12],
|
||||
}
|
||||
|
||||
def order_point_to_dict(self, row):
|
||||
@@ -41,8 +43,8 @@ class OrdersIn:
|
||||
f"""
|
||||
INSERT INTO orders_in
|
||||
(user_id, client_id, products_description, received_price, order_number,
|
||||
ldb_quantity, kg_quantity, track_reg_number, trailer_reg_number, created_at)
|
||||
VALUES ({self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}){returning}
|
||||
ldb_quantity, kg_quantity, track_reg_number, trailer_reg_number, created_at, file_name, expenses)
|
||||
VALUES ({self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}){returning}
|
||||
""",
|
||||
(
|
||||
data["user_id"],
|
||||
@@ -55,6 +57,8 @@ class OrdersIn:
|
||||
data["track_reg_number"],
|
||||
data["trailer_reg_number"],
|
||||
created_at,
|
||||
data["file"],
|
||||
data["expenses"]
|
||||
),
|
||||
)
|
||||
new_id = cur.fetchone()[0] if is_postgres() else getattr(cur, "lastrowid", None)
|
||||
@@ -71,7 +75,7 @@ class OrdersIn:
|
||||
user_id = {self.ph}, client_id = {self.ph}, products_description = {self.ph},
|
||||
received_price = {self.ph}, order_number = {self.ph},
|
||||
ldb_quantity = {self.ph}, kg_quantity = {self.ph}, track_reg_number = {self.ph},
|
||||
trailer_reg_number = {self.ph}
|
||||
trailer_reg_number = {self.ph}, file_name = {self.ph}, expenses = {self.ph}
|
||||
WHERE id = {self.ph}
|
||||
""",
|
||||
(
|
||||
@@ -84,6 +88,8 @@ class OrdersIn:
|
||||
data["kg_quantity"],
|
||||
data["track_reg_number"],
|
||||
data["trailer_reg_number"],
|
||||
data['file'],
|
||||
data['expenses'],
|
||||
data["id"],
|
||||
),
|
||||
)
|
||||
|
||||
@@ -22,7 +22,10 @@ class Users:
|
||||
'created_at': row[12],
|
||||
'otp_code': row[13],
|
||||
'otp_expiration': row[14],
|
||||
'user_role': row[15]
|
||||
'user_role': row[15],
|
||||
'company_id': row[16],
|
||||
'active': row[17],
|
||||
'temporary_password': row[18]
|
||||
}
|
||||
return user
|
||||
|
||||
@@ -70,6 +73,28 @@ class Users:
|
||||
if hasattr(conn, "commit"):
|
||||
conn.commit()
|
||||
return inserted_id
|
||||
|
||||
def insert_company_user(self, name, email, password_hash, company_id):
|
||||
created_at = datetime.now().isoformat()
|
||||
company_id = company_id
|
||||
user_role = 'company_user'
|
||||
with get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
returning = "RETURNING id" if is_postgres() else ""
|
||||
query = f"""
|
||||
INSERT INTO users (
|
||||
name, email, password_hash, created_at, user_role, company_id
|
||||
) VALUES ({self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}, {self.ph}) {returning}
|
||||
"""
|
||||
cursor.execute(query, (name, email, password_hash, created_at, user_role, company_id))
|
||||
inserted_id = None
|
||||
if is_postgres():
|
||||
inserted_id = cursor.fetchone()[0]
|
||||
else:
|
||||
inserted_id = cursor.lastrowid
|
||||
if hasattr(conn, "commit"):
|
||||
conn.commit()
|
||||
return inserted_id
|
||||
|
||||
def update_user_otp(self, user_id, otp_code, expiration):
|
||||
with get_connection() as conn:
|
||||
@@ -190,5 +215,33 @@ class Users:
|
||||
""",
|
||||
(smtp_host, smtp_port, smtp_user, user_id)
|
||||
)
|
||||
if hasattr(conn, "commit"):
|
||||
conn.commit()
|
||||
|
||||
def deactivate_user(self, user_id):
|
||||
with get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
f"""
|
||||
UPDATE users
|
||||
SET active = {self.ph}
|
||||
WHERE id = {self.ph}
|
||||
""",
|
||||
(0, user_id)
|
||||
)
|
||||
if hasattr(conn, "commit"):
|
||||
conn.commit()
|
||||
|
||||
def update_temp_pass(self, user_id):
|
||||
with get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
f"""
|
||||
UPDATE users
|
||||
SET temporary_passwrd = {self.ph}
|
||||
WHERE id = {self.ph}
|
||||
""",
|
||||
(0, user_id)
|
||||
)
|
||||
if hasattr(conn, "commit"):
|
||||
conn.commit()
|
||||
@@ -9,6 +9,7 @@ import os
|
||||
from datetime import timezone
|
||||
|
||||
from models.user import Users
|
||||
from utils.welcome_email import WelcomeMessage
|
||||
|
||||
auth_bp = Blueprint("auth", __name__)
|
||||
|
||||
@@ -30,8 +31,10 @@ def register():
|
||||
password_hash = generate_password_hash(password)
|
||||
users.insert_user(name, email, password_hash)
|
||||
|
||||
return jsonify({"message": "User registered successfully!"}), 201
|
||||
welcome_message = WelcomeMessage(name, email)
|
||||
welcome_message.send_email()
|
||||
|
||||
return jsonify({"message": "User registered successfully!"}), 201
|
||||
|
||||
@auth_bp.route("/login", methods=["POST"])
|
||||
def login():
|
||||
@@ -46,6 +49,9 @@ def login():
|
||||
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
|
||||
|
||||
if user["active"] != 1:
|
||||
return jsonify({"error": "Inactive user"}), 401
|
||||
|
||||
otp_code = str(random.randint(100000, 999999))
|
||||
expiration = datetime.datetime.now(timezone.utc) + datetime.timedelta(minutes=10)
|
||||
@@ -188,7 +194,8 @@ def me():
|
||||
"terms": user["terms"],
|
||||
"first_order_number": user["first_order_number"],
|
||||
"created_at": user["created_at"],
|
||||
"user_role": user["user_role"]
|
||||
"user_role": user["user_role"],
|
||||
"temporary_password": user["temporary_password"]
|
||||
}), 200
|
||||
|
||||
|
||||
@@ -201,4 +208,17 @@ def validate_token():
|
||||
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
|
||||
return jsonify({"message": "Token is valid"}), 200
|
||||
|
||||
@auth_bp.route("/temporary_password", methods=["POST"])
|
||||
@jwt_required()
|
||||
def change_passwd():
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return jsonify({"error": "Password not found"}), 404
|
||||
users = Users()
|
||||
user_id = get_jwt_identity()
|
||||
new_password_hash = generate_password_hash(data['password'])
|
||||
users.update_user_password(user_id, new_password_hash)
|
||||
users.update_temp_pass(user_id)
|
||||
return jsonify({"message": "Password has been updated successfully."}), 200
|
||||
@@ -1,5 +1,6 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
from models.client import Clients
|
||||
from models.user import Users
|
||||
|
||||
from flask_jwt_extended import jwt_required, get_jwt_identity
|
||||
|
||||
@@ -10,6 +11,10 @@ clients_bp = Blueprint("clients", __name__, url_prefix="/clients")
|
||||
def list_clients():
|
||||
clients_db = Clients()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
clients = clients_db.get_all_by_user(user_id)
|
||||
return jsonify(clients), 200
|
||||
|
||||
@@ -19,6 +24,10 @@ def create_client():
|
||||
clients_db = Clients()
|
||||
user_id = get_jwt_identity()
|
||||
data = request.get_json()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
client_id = clients_db.create(
|
||||
user_id=user_id,
|
||||
name=data["name"],
|
||||
|
||||
118
transportmanager/server/routes/company_user.py
Normal file
118
transportmanager/server/routes/company_user.py
Normal file
@@ -0,0 +1,118 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
from models.user import Users
|
||||
from utils.welcome_email import WelcomeMessage
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from flask_jwt_extended import jwt_required, get_jwt_identity
|
||||
from models.company_users import CompanyUsers
|
||||
|
||||
company_user_bp = Blueprint("company_user", __name__, url_prefix="/company_user")
|
||||
|
||||
@company_user_bp.route('/access/<int:id>', methods=["GET"])
|
||||
@jwt_required()
|
||||
def get_access(id):
|
||||
company_user_id = id
|
||||
if not company_user_id:
|
||||
return jsonify({"error":"Missing required fields"}), 400
|
||||
|
||||
company_users = CompanyUsers()
|
||||
access = company_users.get_access_by_company_user_id(company_user_id)
|
||||
return jsonify(access)
|
||||
|
||||
@company_user_bp.route("/register_company_user", methods=["POST"])
|
||||
@jwt_required()
|
||||
def register_company_user():
|
||||
users = Users()
|
||||
data = request.get_json()
|
||||
name = data.get("name")
|
||||
email = data.get("email")
|
||||
company_id = data.get("company_id")
|
||||
password = data.get("password")
|
||||
|
||||
if not name or not email or not password or not company_id:
|
||||
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)
|
||||
company_user_id = users.insert_company_user(name, email, password_hash, company_id)
|
||||
|
||||
welcome_message = WelcomeMessage(name, email)
|
||||
welcome_message.send_email()
|
||||
|
||||
return jsonify({"message": "User registered successfully!", "company_user_id":company_user_id}), 201
|
||||
|
||||
@company_user_bp.route('/access', methods=["POST"])
|
||||
@jwt_required()
|
||||
def create_access():
|
||||
data = request.get_json()
|
||||
company_user_id = data.get('company_user_id')
|
||||
orders_in = data.get("orders_in")
|
||||
orders_out = data.get("orders_out")
|
||||
addresses = data.get("addresses")
|
||||
clients = data.get("clients")
|
||||
transporters = data.get("transporters")
|
||||
report = data.get("report")
|
||||
company_users = CompanyUsers()
|
||||
# Use explicit None checks so that False/0 values are allowed
|
||||
if (
|
||||
company_user_id is None or
|
||||
orders_in is None or
|
||||
orders_out is None or
|
||||
addresses is None or
|
||||
clients is None or
|
||||
transporters is None or
|
||||
report is None
|
||||
):
|
||||
return jsonify({"error": "Missing required fields"}), 400
|
||||
|
||||
access_data = {
|
||||
'company_user_id': company_user_id,
|
||||
'clients': clients,
|
||||
'transporters': transporters,
|
||||
'destinations': addresses,
|
||||
'orders_in': orders_in,
|
||||
'orders_out': orders_out,
|
||||
'report': report
|
||||
}
|
||||
company_users.insert_company_user_access(access_data)
|
||||
|
||||
return jsonify({"message": "Company User access inserted!"})
|
||||
|
||||
@company_user_bp.route('/update_access', methods=["PUT"])
|
||||
@jwt_required()
|
||||
def update_access():
|
||||
data = request.get_json()
|
||||
company_user_id = data.get('company_user_id')
|
||||
orders_in = data.get("orders_in")
|
||||
orders_out = data.get("orders_out")
|
||||
addresses = data.get("addresses")
|
||||
clients = data.get("clients")
|
||||
transporters = data.get("transporters")
|
||||
report = data.get("report")
|
||||
company_users = CompanyUsers()
|
||||
# Use explicit None checks so that False/0 values are allowed
|
||||
if (
|
||||
company_user_id is None or
|
||||
orders_in is None or
|
||||
orders_out is None or
|
||||
addresses is None or
|
||||
clients is None or
|
||||
transporters is None or
|
||||
report is None
|
||||
):
|
||||
return jsonify({"error": "Missing required fields"}), 400
|
||||
|
||||
access_data = {
|
||||
'company_user_id': company_user_id,
|
||||
'clients': clients,
|
||||
'transporters': transporters,
|
||||
'destinations': addresses,
|
||||
'orders_in': orders_in,
|
||||
'orders_out': orders_out,
|
||||
'report': report
|
||||
}
|
||||
company_users.update_company_user_access(access_data)
|
||||
|
||||
return jsonify({"message": "Company User access updated!"})
|
||||
@@ -2,6 +2,7 @@ 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
|
||||
from models.user import Users
|
||||
|
||||
destinations_bp = Blueprint("destinations", __name__, url_prefix="/destinations")
|
||||
|
||||
@@ -10,6 +11,10 @@ destinations_bp = Blueprint("destinations", __name__, url_prefix="/destinations"
|
||||
def list_destinations():
|
||||
destinations_db = Destinations()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
destinations = destinations_db.get_all_by_user(user_id)
|
||||
return jsonify([dict(d) for d in destinations]), 200
|
||||
|
||||
@@ -18,6 +23,10 @@ def list_destinations():
|
||||
def create_destination():
|
||||
destinations_db = Destinations()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
data = request.get_json()
|
||||
destination_id = destinations_db.create(user_id, data.get("name"), data.get("address"))
|
||||
# coordinates = AdressCoordinates(data.get("address"))
|
||||
@@ -33,6 +42,10 @@ def create_destination():
|
||||
def update_destination(id):
|
||||
destinations_db = Destinations()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
data = request.get_json()
|
||||
destinations_db.update(id, user_id, data.get("name"), data.get("address"))
|
||||
coordinates = AdressCoordinates(data.get("address"))
|
||||
|
||||
@@ -17,6 +17,10 @@ orders_bp = Blueprint("orders", __name__, url_prefix="/orders")
|
||||
@jwt_required()
|
||||
def create_order_route():
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
orders = OrdersOut()
|
||||
incoming_data = request.json
|
||||
#here we need to first implement the order pdf
|
||||
@@ -83,6 +87,10 @@ def update_order_route(order_id):
|
||||
orders = OrdersOut()
|
||||
data = request.json
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
order = orders.get_order_by_id(order_id)
|
||||
if not order:
|
||||
return jsonify({"error": "Order not found"}), 404
|
||||
@@ -150,6 +158,10 @@ def update_order_route(order_id):
|
||||
def delete_order_route(order_id):
|
||||
orders = OrdersOut()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
order = orders.get_order_by_id(order_id)
|
||||
if not order:
|
||||
return jsonify({"error": "Order not found"}), 404
|
||||
@@ -168,6 +180,10 @@ def delete_order_route(order_id):
|
||||
def list_orders():
|
||||
orders = OrdersOut()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
try:
|
||||
user_orders = orders.get_orders_by_user(user_id)
|
||||
#result = [{"id": order["id"], "order_number": order["order_number"]} for order in user_orders]
|
||||
@@ -180,6 +196,10 @@ def list_orders():
|
||||
def get_order(order_id):
|
||||
orders = OrdersOut()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
order = orders.get_order_by_id(order_id)
|
||||
points = orders.get_order_points_by_order(order['id'])
|
||||
loading_points = []
|
||||
@@ -251,6 +271,10 @@ def cancel_order(order_id):
|
||||
orders = OrdersOut()
|
||||
order = orders.get_order_by_id(order_id)
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
pdf_name = f'order_{user_id}_{order['order_number']}.pdf'
|
||||
cancel_order_pdf(pdf_name)
|
||||
orders.cancel_order(order_id)
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
from flask import Blueprint, request, jsonify, abort
|
||||
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
|
||||
import os
|
||||
from flask import send_from_directory
|
||||
import mimetypes
|
||||
|
||||
orders_in_bp = Blueprint("orders_in", __name__, url_prefix="/orders_in")
|
||||
|
||||
@@ -11,6 +14,10 @@ orders_in_bp = Blueprint("orders_in", __name__, url_prefix="/orders_in")
|
||||
@jwt_required()
|
||||
def create_order_in_route():
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
orders = OrdersIn()
|
||||
incoming_data = request.json
|
||||
try:
|
||||
@@ -25,7 +32,10 @@ def create_order_in_route():
|
||||
'track_reg_number': incoming_data["track_reg_number"],
|
||||
'trailer_reg_number': incoming_data["trailer_reg_number"],
|
||||
'products_description': incoming_data["products_description"],
|
||||
'file': incoming_data['file'],
|
||||
'expenses': incoming_data['expenses']
|
||||
}
|
||||
#print(order_data)
|
||||
order_id = orders.create_order(order_data)
|
||||
|
||||
for address in incoming_data["loading_addresses"]:
|
||||
@@ -60,6 +70,10 @@ def update_order_route(order_id):
|
||||
orders = OrdersIn()
|
||||
data = request.json
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
order = orders.get_order_by_id(order_id)
|
||||
if not order:
|
||||
return jsonify({"error": "Order in not found"}), 404
|
||||
@@ -77,6 +91,8 @@ def update_order_route(order_id):
|
||||
"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"]),
|
||||
'file': data.get("file", order["file"]),
|
||||
'expenses': data.get("expenses", order["expenses"]),
|
||||
"user_id":user_id
|
||||
})
|
||||
|
||||
@@ -113,6 +129,10 @@ def update_order_route(order_id):
|
||||
def delete_order_route(order_id):
|
||||
orders = OrdersIn()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
order = orders.get_order_by_id(order_id)
|
||||
if not order:
|
||||
return jsonify({"error": "Order in not found"}), 404
|
||||
@@ -131,6 +151,10 @@ def delete_order_route(order_id):
|
||||
def list_orders():
|
||||
orders = OrdersIn()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
try:
|
||||
user_orders = orders.get_orders_by_user(user_id)
|
||||
#result = [{"id": order["id"], "order_number": order["order_number"]} for order in user_orders]
|
||||
@@ -143,6 +167,10 @@ def list_orders():
|
||||
def get_order(order_id):
|
||||
orders = OrdersIn()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
order = orders.get_order_by_id(order_id)
|
||||
points = orders.get_order_points_by_order(order['id'])
|
||||
loading_points = []
|
||||
@@ -160,4 +188,26 @@ def get_order(order_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
|
||||
return jsonify(order), 200
|
||||
|
||||
@orders_in_bp.route("/files/<path:filename>", methods=["GET"])
|
||||
#@jwt_required()
|
||||
def serve_order_pdf(filename):
|
||||
try:
|
||||
# Directory containing uploaded client files
|
||||
uploads_dir = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), "..", "..", "client", "uploads")
|
||||
)
|
||||
# Security: prevent path traversal and ensure file exists
|
||||
abs_file_path = os.path.abspath(os.path.join(uploads_dir, filename))
|
||||
if not abs_file_path.startswith(uploads_dir + os.sep):
|
||||
abort(404)
|
||||
if not os.path.isfile(abs_file_path):
|
||||
abort(404)
|
||||
|
||||
guessed_type = mimetypes.guess_type(filename)[0] or "application/octet-stream"
|
||||
# send_from_directory expects the directory and the filename relative to it
|
||||
return send_from_directory(uploads_dir, filename, mimetype=guessed_type, as_attachment=False)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return jsonify({"error": "File not found"}), 404
|
||||
@@ -2,6 +2,7 @@ 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
|
||||
from models.user import Users
|
||||
|
||||
report_bp = Blueprint("report", __name__, url_prefix="/report")
|
||||
|
||||
@@ -10,6 +11,10 @@ report_bp = Blueprint("report", __name__, url_prefix="/report")
|
||||
def get_profit_report():
|
||||
try:
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
# Get filters from query params
|
||||
date_from = request.args.get("date_from")
|
||||
date_to = request.args.get("date_to")
|
||||
|
||||
@@ -11,6 +11,10 @@ subscription_bp = Blueprint("subscription", __name__, url_prefix="/subscription"
|
||||
@jwt_required()
|
||||
def get_subscription():
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
subscription_model = Subscription()
|
||||
subscriptions = subscription_model.get_by_user_id(user_id)
|
||||
return jsonify(subscriptions), 200
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
from flask_jwt_extended import jwt_required, get_jwt_identity
|
||||
from models.transporters import Transporters
|
||||
from models.user import Users
|
||||
|
||||
transporters_bp = Blueprint("transporters", __name__, url_prefix="/transporters")
|
||||
|
||||
@@ -8,6 +9,10 @@ transporters_bp = Blueprint("transporters", __name__, url_prefix="/transporters"
|
||||
@jwt_required()
|
||||
def list_transporters():
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
transporters_db = Transporters()
|
||||
transporters = transporters_db.get_all_transporters_by_user(user_id)
|
||||
return jsonify(transporters), 200
|
||||
@@ -18,6 +23,10 @@ def create_transporter():
|
||||
transporters_db = Transporters()
|
||||
data = request.get_json()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
transporter_id = transporters_db.create_transporter(
|
||||
user_id=user_id,
|
||||
name=data.get("name"),
|
||||
@@ -36,6 +45,10 @@ def create_transporter():
|
||||
def update_transporter(transporter_id):
|
||||
transporters_db = Transporters()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
data = request.get_json()
|
||||
transporter = transporters_db.get_transporter_by_id(transporter_id)
|
||||
if not transporter:
|
||||
@@ -58,6 +71,10 @@ def update_transporter(transporter_id):
|
||||
def delete_transporter(transporter_id):
|
||||
transporters_db = Transporters()
|
||||
user_id = get_jwt_identity()
|
||||
users = Users()
|
||||
user = users.get_user_by_id(user_id)
|
||||
if user['user_role'] == 'company_user':
|
||||
user_id = user['company_id']
|
||||
transporter = transporters_db.get_transporter_by_id(transporter_id)
|
||||
if not transporter:
|
||||
return jsonify({"error": "Transporter not found"}), 404
|
||||
|
||||
@@ -15,7 +15,10 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
otp_code TEXT,
|
||||
otp_expiration TIMESTAMPTZ,
|
||||
user_role TEXT NOT NULL DEFAULT 'user' CHECK (user_role IN ('user', 'admin'))
|
||||
user_role TEXT NOT NULL DEFAULT 'user' CHECK (user_role IN ('user', 'admin', 'company_user')),
|
||||
company_id INTEGER DEFAULT 0,
|
||||
active INTEGER DEFAULT 1,
|
||||
temporary_passwrd INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
-- Clients table
|
||||
@@ -94,6 +97,8 @@ CREATE TABLE IF NOT EXISTS orders_in (
|
||||
trailer_reg_number TEXT,
|
||||
received_price DOUBLE PRECISION,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
file_name TEXT,
|
||||
expenses DOUBLE PRECISION,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(client_id) REFERENCES clients(id) ON DELETE CASCADE
|
||||
);
|
||||
@@ -143,4 +148,17 @@ CREATE TABLE IF NOT EXISTS email (
|
||||
smtp_user TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS company_user_access (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
company_user_id INTEGER NOT NULL,
|
||||
clients INTEGER,
|
||||
transporters INTEGER,
|
||||
destinations INTEGER,
|
||||
orders_in INTEGER,
|
||||
orders_out INTEGER,
|
||||
report INTEGER,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY(company_user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
@@ -82,9 +82,9 @@ def send_gmail(to_email, subject, body):
|
||||
def send_gmail_with_attachment(to_email, subject, body, attachment_path):
|
||||
smtp_host = "smtp.gmail.com"
|
||||
smtp_port = 587
|
||||
smtp_user = os.environ.get("GMAIL_USER")
|
||||
smtp_pass = os.environ.get("GMAIL_PASS")
|
||||
sender_email = smtp_user
|
||||
smtp_user = 'macamete.robert@gmail.com'
|
||||
smtp_pass = 'advx yqlv jkaa czvr'
|
||||
sender_email = 'macamete.robert@gmail.com'
|
||||
|
||||
if not all([smtp_user, smtp_pass]):
|
||||
raise ValueError("GMAIL_USER and GMAIL_PASS must be set in environment variables.")
|
||||
|
||||
31
transportmanager/server/utils/welcome_email.py
Normal file
31
transportmanager/server/utils/welcome_email.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import os
|
||||
from utils.email import send_gmail_with_attachment
|
||||
|
||||
class WelcomeMessage:
|
||||
def __init__(self, name, email):
|
||||
self.name = name
|
||||
self.email = email
|
||||
self.subject = 'Welcome to Order Go - TMS - Your Account is Ready'
|
||||
self.assets_folder = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), "..", "assets")
|
||||
)
|
||||
self.manual = os.path.join(self.assets_folder, "manual.pdf")
|
||||
self.body = f'''
|
||||
|
||||
Dear {self.name},
|
||||
|
||||
We are pleased to welcome you to Order Go - TMS. Thank you for choosing our platform to support your business needs.
|
||||
|
||||
To assist you in getting started, we have attached the User Manual to this email. It provides step-by-step instructions on account setup, feature overview, and best practices for using Order Go - TMS efficiently.
|
||||
|
||||
We recommend reviewing the manual at your convenience to become familiar with the system's capabilities. Should you require any further assistance, our support team is available at support@ordergotms.com.
|
||||
|
||||
We look forward to supporting your success and building a long-term partnership.
|
||||
|
||||
Sincerely,
|
||||
The Order Go - TMS Team
|
||||
|
||||
'''
|
||||
|
||||
def send_email(self):
|
||||
send_gmail_with_attachment(to_email=self.email, subject=self.subject, body=self.body, attachment_path=self.manual)
|
||||
Reference in New Issue
Block a user