Spaces:
Running
Running
| from fastapi import APIRouter, Depends, HTTPException, status | |
| from sqlmodel import Session, select | |
| import uuid | |
| import datetime | |
| from app.core.database import get_session | |
| from app.api.deps import get_current_user | |
| from app.models.user import User | |
| from app.models.procedure import Procedure | |
| from app.models.procedure_type import ProcedureType | |
| from app.models.team_procedure_value import TeamProcedureValue | |
| from app.models.membership import Membership | |
| from app.schemas.procedure import ProcedureCreate, ProcedureRead, ProcedureUpdate | |
| router = APIRouter(prefix="/procedures", tags=["Procedures"]) | |
| def create_procedure( | |
| procedure_in: ProcedureCreate, | |
| session: Session = Depends(get_session), | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """ | |
| Cria um novo procedimento ("A Rota de Escrita"). | |
| Aplica as regras de negócio: | |
| - Valida o médico a partir do token (via `get_current_user`). | |
| - Identifica o time associado ao médico (caso não pertença a nenhum, retorna erro 400). | |
| - Congela o valor: busca na tabela de valores de procedimentos do time qual o preço | |
| do procedimento neste exato momento e salva no campo `value_at_time`. | |
| """ | |
| # 1. Identificar o Time: O backend busca a qual team_id esse médico pertence | |
| membership = session.exec(select(Membership).where(Membership.user_id == current_user.id)).first() | |
| if not membership: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail="O médico não pertence a nenhum time." | |
| ) | |
| # 2. Congelar o Valor: O código busca na tabela team_procedure_values qual é o preço daquele procedimento para aquele time específico | |
| team_procedure_value = session.exec( | |
| select(TeamProcedureValue) | |
| .where(TeamProcedureValue.team_id == membership.team_id) | |
| .where(TeamProcedureValue.procedure_type_id == procedure_in.procedure_type_id) | |
| ).first() | |
| # Define o valor do procedimento (usa o custom_value, se não existir mapeamento usa 0 ou dispara erro) | |
| # Por segurança, caso não esteja mapeado, vamos preencher com 0 e o admin depois ajusta, | |
| # Ou podemos rejeitar a criação se não tiver preço. Adotaremos 0 como fallback coerente. | |
| value_at_time = team_procedure_value.custom_value if team_procedure_value else 0 | |
| # 3. Criar a Procedure associando todos os dados | |
| # Se o cliente enviou um doctor_id (via form), usamos ele. Caso contrário, usamos o logado. | |
| final_doctor_id = procedure_in.doctor_id or current_user.id | |
| procedure = Procedure( | |
| **procedure_in.model_dump(exclude={"doctor_id"}), | |
| doctor_id=final_doctor_id, | |
| team_id=membership.team_id, | |
| value_at_time=value_at_time | |
| ) | |
| session.add(procedure) | |
| session.commit() | |
| session.refresh(procedure) | |
| return procedure | |
| def update_procedure( | |
| *, | |
| session: Session = Depends(get_session), | |
| procedure_id: uuid.UUID, | |
| procedure_in: ProcedureUpdate, | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """ | |
| Atualiza um procedimento existente. | |
| Verifica permissões de equipe e atualiza o valor financeiro se o tipo for alterado. | |
| """ | |
| # 1. Buscar o procedimento no banco | |
| db_proc = session.get(Procedure, procedure_id) | |
| if not db_proc: | |
| raise HTTPException(status_code=404, detail="Procedimento não encontrado") | |
| # 2. Verificar se o usuário pertence ao time do procedimento (Segurança) | |
| membership = session.exec( | |
| select(Membership).where( | |
| Membership.user_id == current_user.id, | |
| Membership.team_id == db_proc.team_id | |
| ) | |
| ).first() | |
| if not membership: | |
| raise HTTPException( | |
| status_code=403, | |
| detail="Você não tem permissão para editar procedimentos deste time." | |
| ) | |
| # 3. Preparar os dados para atualização | |
| update_data = procedure_in.model_dump(exclude_unset=True) | |
| # 4. Lógica Especial: Se o tipo de procedimento mudou, precisamos atualizar o valor financeiro | |
| if "procedure_type_id" in update_data: | |
| new_type_id = update_data["procedure_type_id"] | |
| # Busca o valor customizado para o time ou o valor base do catálogo | |
| custom_val_stmt = select(TeamProcedureValue.custom_value).where( | |
| TeamProcedureValue.team_id == db_proc.team_id, | |
| TeamProcedureValue.procedure_type_id == new_type_id | |
| ) | |
| custom_value = session.exec(custom_val_stmt).first() | |
| if custom_value is not None: | |
| db_proc.value_at_time = custom_value | |
| else: | |
| # Se não houver valor customizado, busca o valor base do catálogo | |
| proc_type = session.get(ProcedureType, new_type_id) | |
| if proc_type: | |
| db_proc.value_at_time = proc_type.base_value | |
| # 5. Aplicar os demais campos dinamicamente | |
| for key, value in update_data.items(): | |
| setattr(db_proc, key, value) | |
| # Definir momento da atualização | |
| db_proc.updated_at = datetime.datetime.now(datetime.timezone.utc) | |
| # 6. Salvar e retornar | |
| session.add(db_proc) | |
| session.commit() | |
| session.refresh(db_proc) | |
| return db_proc | |
| def delete_procedure( | |
| *, | |
| session: Session = Depends(get_session), | |
| procedure_id: uuid.UUID, | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """ | |
| Exclui um procedimento permanentemente. | |
| Apenas Administradores do time ou Staff podem realizar esta ação. | |
| """ | |
| # 1. Buscar o procedimento no banco | |
| db_proc = session.get(Procedure, procedure_id) | |
| if not db_proc: | |
| raise HTTPException(status_code=404, detail="Procedimento não encontrado") | |
| # 2. Verificar se o usuário pertence ao time | |
| membership = session.exec( | |
| select(Membership).where( | |
| Membership.user_id == current_user.id, | |
| Membership.team_id == db_proc.team_id | |
| ) | |
| ).first() | |
| if not membership: | |
| raise HTTPException( | |
| status_code=403, | |
| detail="Você não tem permissão para acessar este procedimento." | |
| ) | |
| # NAO USADA PARA O MVP | |
| # 3. Regra de Negócio (RBAC): Apenas Admin ou Staff exclui | |
| # Nota: membership.role define se ele é 'admin' ou 'member' no time. | |
| # current_user.role define se ele é 'staff' no sistema global. | |
| # if membership.role != "admin" and current_user.role != RoleEnum.staff: | |
| # raise HTTPException( | |
| # status_code=403, | |
| # detail="Apenas o administrador da equipe ou staff podem excluir registros." | |
| # ) | |
| # 4. Excluir e salvar (Commit) | |
| session.delete(db_proc) | |
| session.commit() | |
| return {"ok": True} |