revert: restore production to the state before 730d0bd (PM/RBAC work moved to 'pm')

Their three commits (730d0bd, 5a9b543, 387edfb) reached production by push and
auto-deployed. 387edfb expects a users.username column that the live database does
not have, so POST /api/v1/auth/login was returning HTTP 500. Their schema changes
never applied either (projects still has only id, name, description, start_date,
pm_user_id, created_at), so nothing depends on the reverted code.

This commit sets the tree back to exactly a02b3ea — verified with git diff against
it — while keeping history linear: the work itself is preserved on 'pm' at 387edfb.
This commit is contained in:
ZCode
2026-09-26 17:41:07 +00:00
parent 387edfb1ab
commit 253c922280
56 changed files with 753 additions and 1479 deletions
+7 -36
View File
@@ -9,7 +9,6 @@ from fastapi import APIRouter, Depends, Query, Request
from sqlalchemy import exists, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.auth import require_role
from app.db.engine import get_db
from app.models.catalog import (
AttributeDefinition,
@@ -39,7 +38,6 @@ from app.utils.errors import ConflictError, NotFoundError, ValidationError
from app.utils.pagination import paginate, sort_query
router = APIRouter(prefix="/materials", tags=["materials"])
_procurement_writer = require_role("admin", "procurement_manager")
def _coerce_filter_value(data_type: str, raw: str):
@@ -127,10 +125,7 @@ async def list_materials(
@router.post("", status_code=201)
async def create_material(
payload: MaterialCreate,
expand: str | None = None,
db: AsyncSession = Depends(get_db),
_auth=Depends(_procurement_writer),
payload: MaterialCreate, expand: str | None = None, db: AsyncSession = Depends(get_db)
):
material = await material_service.create_material(db, payload)
return {"data": await serialize_material(db, material, parse_expand(expand))}
@@ -145,12 +140,7 @@ async def get_material(material_id, expand: str | None = None, db: AsyncSession
@router.patch("/{material_id}")
async def update_material(
material_id,
payload: MaterialUpdate,
db: AsyncSession = Depends(get_db),
_auth=Depends(_procurement_writer),
):
async def update_material(material_id, payload: MaterialUpdate, db: AsyncSession = Depends(get_db)):
material = await db.get(Material, material_id)
if material is None:
raise NotFoundError("متریال یافت نشد")
@@ -159,11 +149,7 @@ async def update_material(
@router.delete("/{material_id}")
async def delete_material(
material_id,
db: AsyncSession = Depends(get_db),
_auth=Depends(_procurement_writer),
):
async def delete_material(material_id, db: AsyncSession = Depends(get_db)):
material = await db.get(Material, material_id)
if material is None:
raise NotFoundError("متریال یافت نشد")
@@ -262,10 +248,7 @@ async def list_material_units(
@router.post("/{material_id}/units", status_code=201)
async def create_material_unit(
material_id,
payload: MaterialUnitCreate,
db: AsyncSession = Depends(get_db),
_auth=Depends(_procurement_writer),
material_id, payload: MaterialUnitCreate, db: AsyncSession = Depends(get_db)
):
async with db.begin():
await _material_or_404(db, material_id)
@@ -304,11 +287,7 @@ async def create_material_unit(
@router.patch("/{material_id}/units/{mu_id}")
async def update_material_unit(
material_id,
mu_id,
payload: MaterialUnitUpdate,
db: AsyncSession = Depends(get_db),
_auth=Depends(_procurement_writer),
material_id, mu_id, payload: MaterialUnitUpdate, db: AsyncSession = Depends(get_db)
):
async with db.begin():
mu = await db.scalar(
@@ -340,12 +319,7 @@ async def update_material_unit(
@router.delete("/{material_id}/units/{mu_id}")
async def delete_material_unit(
material_id,
mu_id,
db: AsyncSession = Depends(get_db),
_auth=Depends(_procurement_writer),
):
async def delete_material_unit(material_id, mu_id, db: AsyncSession = Depends(get_db)):
mu = await db.scalar(
select(MaterialUnit).where(MaterialUnit.id == mu_id, MaterialUnit.material_id == material_id)
)
@@ -391,10 +365,7 @@ async def get_material_attribute_values(
@router.put("/{material_id}/attribute-values")
async def put_material_attribute_values(
material_id,
payload: MaterialAttributeValuesPut,
db: AsyncSession = Depends(get_db),
_auth=Depends(_procurement_writer),
material_id, payload: MaterialAttributeValuesPut, db: AsyncSession = Depends(get_db)
):
"""FULL replacement of a material's EAV values (empty array deletes all)."""
async with db.begin():