gmao/app_new/c4/routes.py

165 lines
7.5 KiB
Python
Raw Normal View History

"""HTTP C4 : contrats photocopieurs et consommables partagés."""
from datetime import date
from flask import Blueprint, flash, redirect, render_template, request, url_for
from flask_login import current_user, login_required
from ..core.authorization import permission_required
from ..core.models import (
Company, Consumable, ConsumableOrder, ConsumableUsage, ContractEquipmentAssignment,
Equipment, EquipmentConsumable, PhotocopierContract, PhotocopierContractPeriod,
)
from ..core.services.c4_service import (
C4DomainError, assign_equipment_to_contract, calculate_contract_usage,
create_consumable_order, create_contract, evaluate_quota_alert, project_contract_usage,
estimate_consumable_lifetime, receive_consumable_order, record_consumable_issue,
)
from ..extensions import db
c4_bp = Blueprint("c4", __name__, template_folder="templates")
def _parse_date(value):
return date.fromisoformat(value) if value else None
@c4_bp.get("/contracts")
@login_required
@permission_required("contract.view")
def contracts():
rows = PhotocopierContract.query.order_by(PhotocopierContract.start_date.desc()).all()
return render_template("c4/contracts.html", contracts=rows)
@c4_bp.get("/equipment/<int:equipment_id>")
@login_required
@permission_required("patrimoine.view")
def equipment_detail(equipment_id):
equipment = Equipment.query.get_or_404(equipment_id)
assignments = ContractEquipmentAssignment.query.filter_by(equipment_id=equipment.id).order_by(ContractEquipmentAssignment.entry_date.desc()).all()
links = EquipmentConsumable.query.filter_by(equipment_id=equipment.id).all()
return render_template("c4/equipment_detail.html", equipment=equipment, assignments=assignments, links=links)
@c4_bp.route("/contracts/new", methods=["GET", "POST"])
@login_required
@permission_required("contract.manage")
def new_contract():
companies = Company.query.order_by(Company.name).all()
if request.method == "POST":
try:
contract = create_contract(
supplier_id=request.form.get("supplier_id", type=int), name=request.form.get("name", "").strip(),
reference=request.form.get("reference") or None, start_date=_parse_date(request.form.get("start_date")),
end_date=_parse_date(request.form.get("end_date")), anniversary_month=request.form.get("anniversary_month", type=int),
anniversary_day=request.form.get("anniversary_day", type=int),
quota_start_date=_parse_date(request.form.get("quota_start_date")), notes=request.form.get("notes"),
)
flash("Contrat photocopieur créé.", "success")
return redirect(url_for("c4.contract_detail", contract_id=contract.id))
except (ValueError, TypeError, C4DomainError) as exc:
db.session.rollback()
flash(str(exc), "danger")
return render_template("c4/contract_form.html", companies=companies)
@c4_bp.get("/contracts/<int:contract_id>")
@login_required
@permission_required("contract.view")
def contract_detail(contract_id):
contract = PhotocopierContract.query.get_or_404(contract_id)
periods = contract.periods
data = {period.id: calculate_contract_usage(period) for period in periods}
projections = {period.id: project_contract_usage(period) for period in periods}
return render_template("c4/contract_detail.html", contract=contract, periods=periods, usage=data, projections=projections)
@c4_bp.post("/contracts/<int:contract_id>/equipment")
@login_required
@permission_required("contract.manage")
def contract_equipment(contract_id):
contract = PhotocopierContract.query.get_or_404(contract_id)
equipment = Equipment.query.get_or_404(request.form.get("equipment_id", type=int))
try:
assign_equipment_to_contract(contract=contract, equipment=equipment, entry_date=_parse_date(request.form.get("entry_date")), exit_date=_parse_date(request.form.get("exit_date")))
flash("Machine rattachée au contrat.", "success")
except (ValueError, C4DomainError) as exc:
db.session.rollback()
flash(str(exc), "danger")
return redirect(url_for("c4.contract_detail", contract_id=contract_id))
@c4_bp.post("/contracts/<int:contract_id>/close")
@login_required
@permission_required("contract.manage")
def close_contract(contract_id):
contract = PhotocopierContract.query.get_or_404(contract_id)
contract.status = "CLOSED"
contract.closed_at = _parse_date(request.form.get("closed_at")) or date.today()
contract.end_date = min(contract.end_date, contract.closed_at)
db.session.commit()
flash("Contrat clos ; son historique est conservé.", "success")
return redirect(url_for("c4.contract_detail", contract_id=contract_id))
@c4_bp.get("/consumables")
@login_required
@permission_required("stock.view")
def consumables():
rows = Consumable.query.filter_by(is_active=True).order_by(Consumable.name).all()
return render_template("c4/consumables.html", consumables=rows)
@c4_bp.get("/consumables/<int:consumable_id>")
@login_required
@permission_required("stock.view")
def consumable_detail(consumable_id):
consumable = Consumable.query.get_or_404(consumable_id)
usages = consumable.usages.order_by(ConsumableUsage.used_at.desc()).limit(100).all()
orders = ConsumableOrder.query.filter_by(consumable_id=consumable.id).order_by(ConsumableOrder.id.desc()).all()
compatible = EquipmentConsumable.query.filter_by(consumable_id=consumable.id).all()
return render_template("c4/consumable_detail.html", consumable=consumable, usages=usages, orders=orders, compatible=compatible)
@c4_bp.post("/consumables/<int:consumable_id>/orders")
@login_required
@permission_required("stock.manage")
def order_consumable(consumable_id):
consumable = Consumable.query.get_or_404(consumable_id)
try:
create_consumable_order(consumable=consumable, quantity=request.form.get("quantity", type=int), supplier_id=request.form.get("supplier_id", type=int), user_id=current_user.id)
flash("Commande créée.", "success")
except (ValueError, C4DomainError) as exc:
db.session.rollback()
flash(str(exc), "danger")
return redirect(url_for("c4.consumable_detail", consumable_id=consumable_id))
@c4_bp.post("/orders/<int:order_id>/receive")
@login_required
@permission_required("stock.receive")
def receive_order(order_id):
order = ConsumableOrder.query.get_or_404(order_id)
try:
receive_consumable_order(order=order, quantity=request.form.get("quantity", type=int), user_id=current_user.id, comment=request.form.get("comment"))
flash("Réception enregistrée ; le stock a été augmenté.", "success")
except (ValueError, C4DomainError) as exc:
db.session.rollback()
flash(str(exc), "danger")
return redirect(url_for("c4.consumable_detail", consumable_id=order.consumable_id))
@c4_bp.post("/consumables/<int:consumable_id>/issue")
@login_required
@permission_required("stock.issue")
def issue_consumable(consumable_id):
consumable = Consumable.query.get_or_404(consumable_id)
equipment = Equipment.query.get_or_404(request.form.get("equipment_id", type=int))
try:
record_consumable_issue(consumable=consumable, equipment=equipment, quantity=request.form.get("quantity", type=int, default=1), user_id=current_user.id, notes=request.form.get("notes"))
flash("Sortie de stock enregistrée.", "success")
except (ValueError, C4DomainError) as exc:
db.session.rollback()
flash(str(exc), "danger")
return redirect(url_for("c4.consumable_detail", consumable_id=consumable_id))