feat(backend): add FastAPI backend — procurement, inventory domain, Casdoor auth, PM arrival endpoints
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
"""Application error type + standardized error envelope.
|
||||
|
||||
All errors are returned as: {"error": {"code", "message", "field"}}
|
||||
(contracts: expert-opinion-p0.md «General Shared Contracts»).
|
||||
"""
|
||||
|
||||
|
||||
class AppError(Exception):
|
||||
"""Base error carrying an HTTP status and the contract error envelope."""
|
||||
|
||||
def __init__(self, status_code: int, code: str, message: str, field: str | None = None):
|
||||
super().__init__(message)
|
||||
self.status_code = status_code
|
||||
self.code = code
|
||||
self.message = message
|
||||
self.field = field
|
||||
|
||||
@property
|
||||
def body(self) -> dict:
|
||||
error = {"code": self.code, "message": self.message}
|
||||
if self.field is not None:
|
||||
error["field"] = self.field
|
||||
return {"error": error}
|
||||
|
||||
|
||||
class ValidationError(AppError):
|
||||
"""400 VALIDATION_ERROR — bad input (types, business validation)."""
|
||||
|
||||
def __init__(self, message: str, field: str | None = None):
|
||||
super().__init__(400, "VALIDATION_ERROR", message, field)
|
||||
|
||||
|
||||
class NotFoundError(AppError):
|
||||
"""404 NOT_FOUND."""
|
||||
|
||||
def __init__(self, message: str = "رکورد یافت نشد", field: str | None = None):
|
||||
super().__init__(404, "NOT_FOUND", message, field)
|
||||
|
||||
|
||||
class ConflictError(AppError):
|
||||
"""409 CONFLICT — duplicates, invalid state transitions, protected deletes."""
|
||||
|
||||
def __init__(self, message: str, field: str | None = None):
|
||||
super().__init__(409, "CONFLICT", message, field)
|
||||
|
||||
|
||||
class ForbiddenError(AppError):
|
||||
"""403 FORBIDDEN — role / ownership checks."""
|
||||
|
||||
def __init__(self, message: str, field: str | None = None):
|
||||
super().__init__(403, "FORBIDDEN", message, field)
|
||||
Reference in New Issue
Block a user