Added service plan. Password change
This commit is contained in:
@@ -86,6 +86,10 @@ def login():
|
||||
if not bcrypt.check_password_hash(user.password_hash, password):
|
||||
return jsonify({"error": "Invalid password"}), 401 # Use a more descriptive error and status code
|
||||
|
||||
# Check if user is active
|
||||
if user.active != 1:
|
||||
return jsonify({"error": "Please contact a manager. Login rejected"}), 401
|
||||
|
||||
# If login is successful, return the correct structure
|
||||
return jsonify({
|
||||
"ok": True,
|
||||
@@ -168,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
|
||||
|
||||
@@ -190,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
|
||||
|
||||
@@ -26,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,
|
||||
@@ -37,6 +38,7 @@ class Auth_User(UserMixin, db.Model):
|
||||
admin,
|
||||
admin_role,
|
||||
confirmed,
|
||||
active=1,
|
||||
):
|
||||
self.username = username
|
||||
self.api_key = api_key
|
||||
@@ -47,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
|
||||
@@ -75,4 +78,4 @@ class AnonymousUser(AnonymousUserMixin):
|
||||
self.username = 'Guest'
|
||||
|
||||
|
||||
login_manager.anonymous_user = AnonymousUser
|
||||
login_manager.anonymous_user = AnonymousUser
|
||||
|
||||
@@ -60,4 +60,26 @@ 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')
|
||||
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)
|
||||
|
||||
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_Plans
|
||||
contract_start_date = ma.DateTime(format='%Y-%m-%d')
|
||||
|
||||
@@ -6,6 +6,7 @@ from flask_login import login_required
|
||||
from app.employees import employees
|
||||
from app import db
|
||||
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"])
|
||||
@@ -13,7 +14,26 @@ from app.classes.stats_employee import Stats_Employee_Oil, Stats_Employee_Office
|
||||
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))
|
||||
@@ -169,7 +189,7 @@ def employee_edit(employee_id):
|
||||
e_type = request.json["employee_type"]
|
||||
e_start_date = request.json["employee_start_date"]
|
||||
e_end_date = request.json["employee_end_date"]
|
||||
|
||||
e_active = request.json.get("active", 1)
|
||||
|
||||
get_employee = db.session \
|
||||
.query(Employee_Employee) \
|
||||
@@ -187,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()
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ from app import db
|
||||
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_Service_schema, Service_Parts, Service_Parts_schema,
|
||||
Service_Plans, Service_Plans_schema
|
||||
)
|
||||
|
||||
|
||||
@@ -173,6 +174,120 @@ def update_service_call(id):
|
||||
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:
|
||||
return jsonify(None), 200
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@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("/delete/<int:id>", methods=["DELETE"])
|
||||
def delete_service_call(id):
|
||||
service_record = Service_Service.query.get_or_404(id)
|
||||
|
||||
Reference in New Issue
Block a user