05/07 Phase 3: initial codes
This commit is contained in:
@@ -1,7 +1,117 @@
|
||||
"""
|
||||
app/tenant/locations/routes.py
|
||||
Phase 3+ implementation.
|
||||
Location management: list, create, edit, set primary, switch.
|
||||
"""
|
||||
from flask import Blueprint
|
||||
import logging
|
||||
from flask import Blueprint, render_template, redirect, url_for, flash, request, session, g
|
||||
from flask_login import login_required, current_user
|
||||
from app.extensions import db
|
||||
from app.models.salon import Location
|
||||
from app.decorators import require_role, tenant_feature_required, demo_readonly
|
||||
from app.tenant.utils import log_tenant_action, plan_limit_check
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
locations_bp = Blueprint("locations", __name__, url_prefix="/locations")
|
||||
|
||||
|
||||
@locations_bp.route("/")
|
||||
@login_required
|
||||
@require_role("tenant_admin", "tenant_manager")
|
||||
def index():
|
||||
locs = Location.query.filter_by(tenant_id=g.tenant.id).order_by(
|
||||
Location.is_primary.desc(), Location.name).all()
|
||||
return render_template("tenant/locations/index.html", locations=locs)
|
||||
|
||||
|
||||
@locations_bp.route("/switch/<int:location_id>")
|
||||
@login_required
|
||||
@require_role("tenant_admin", "tenant_manager")
|
||||
def switch(location_id):
|
||||
loc = Location.query.filter_by(
|
||||
id=location_id, tenant_id=g.tenant.id, is_active=True).first_or_404()
|
||||
session["active_location_id"] = loc.id
|
||||
logger.info("Location switched: location=%s tenant=%s user=%s",
|
||||
loc.id, g.tenant.id, current_user.get_id())
|
||||
flash(f"Switched to {loc.name}.", "info")
|
||||
return redirect(request.referrer or url_for("dashboard.index"))
|
||||
|
||||
|
||||
@locations_bp.route("/new", methods=["GET", "POST"])
|
||||
@login_required
|
||||
@require_role("tenant_admin")
|
||||
@demo_readonly
|
||||
def create():
|
||||
allowed, err = plan_limit_check("location")
|
||||
if not allowed:
|
||||
flash(err, "warning")
|
||||
return redirect(url_for("locations.index"))
|
||||
|
||||
if request.method == "POST":
|
||||
name = request.form.get("name", "").strip()
|
||||
if not name:
|
||||
return render_template("tenant/locations/form.html",
|
||||
mode="create", error="Name is required.")
|
||||
allowed, err = plan_limit_check("location")
|
||||
if not allowed:
|
||||
return render_template("tenant/locations/form.html",
|
||||
mode="create", error=err)
|
||||
loc = Location(
|
||||
tenant_id=g.tenant.id, name=name,
|
||||
address=request.form.get("address", "").strip() or None,
|
||||
phone=request.form.get("phone", "").strip() or None,
|
||||
email=request.form.get("email", "").strip() or None,
|
||||
timezone=request.form.get("timezone", "America/New_York"),
|
||||
is_active=True, is_primary=False,
|
||||
)
|
||||
db.session.add(loc)
|
||||
db.session.flush()
|
||||
log_tenant_action("location.create", "location", loc.id, {"name": name})
|
||||
db.session.commit()
|
||||
flash(f"Location \'{name}\' created.", "success")
|
||||
return redirect(url_for("locations.index"))
|
||||
return render_template("tenant/locations/form.html", mode="create")
|
||||
|
||||
|
||||
@locations_bp.route("/<int:location_id>/edit", methods=["GET", "POST"])
|
||||
@login_required
|
||||
@require_role("tenant_admin")
|
||||
@demo_readonly
|
||||
def edit(location_id):
|
||||
loc = Location.query.filter_by(
|
||||
id=location_id, tenant_id=g.tenant.id).first_or_404()
|
||||
if request.method == "POST":
|
||||
name = request.form.get("name", "").strip()
|
||||
if not name:
|
||||
return render_template("tenant/locations/form.html",
|
||||
mode="edit", location=loc, error="Name is required.")
|
||||
old_name = loc.name
|
||||
loc.name = name
|
||||
loc.address = request.form.get("address", "").strip() or None
|
||||
loc.phone = request.form.get("phone", "").strip() or None
|
||||
loc.email = request.form.get("email", "").strip() or None
|
||||
loc.timezone = request.form.get("timezone", loc.timezone)
|
||||
loc.is_active = request.form.get("is_active") == "1"
|
||||
if request.form.get("is_primary") == "1" and not loc.is_primary:
|
||||
Location.query.filter_by(tenant_id=g.tenant.id, is_primary=True).update({"is_primary": False})
|
||||
loc.is_primary = True
|
||||
log_tenant_action("location.edit", "location", loc.id,
|
||||
{"old_name": old_name, "new_name": name})
|
||||
db.session.commit()
|
||||
flash(f"Location \'{name}\' updated.", "success")
|
||||
return redirect(url_for("locations.index"))
|
||||
return render_template("tenant/locations/form.html", mode="edit", location=loc)
|
||||
|
||||
|
||||
@locations_bp.route("/<int:location_id>/set-primary", methods=["POST"])
|
||||
@login_required
|
||||
@require_role("tenant_admin")
|
||||
@demo_readonly
|
||||
def set_primary(location_id):
|
||||
loc = Location.query.filter_by(
|
||||
id=location_id, tenant_id=g.tenant.id, is_active=True).first_or_404()
|
||||
Location.query.filter_by(tenant_id=g.tenant.id, is_primary=True).update({"is_primary": False})
|
||||
loc.is_primary = True
|
||||
log_tenant_action("location.set_primary", "location", loc.id)
|
||||
db.session.commit()
|
||||
flash(f"\'{loc.name}\' set as primary.", "success")
|
||||
return redirect(url_for("locations.index"))
|
||||
|
||||
Reference in New Issue
Block a user