140 lines
4.4 KiB
Python
140 lines
4.4 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.database import get_db
|
|
from app.crud import audit as audit_crud
|
|
from app.crud import imported_part as imported_part_crud
|
|
from app.crud import imported_part_config as config_crud
|
|
from app.deps import require_permission
|
|
from app.models.user import User
|
|
from app.schemas.imported_part import (
|
|
ImportedPartConfigRead,
|
|
ImportedPartConfigUpdate,
|
|
ImportedPartRead,
|
|
SyncResult,
|
|
)
|
|
from app.services import odata as odata_service
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("", response_model=list[ImportedPartRead])
|
|
async def list_imported_parts(
|
|
skip: int = 0,
|
|
limit: int = 500,
|
|
db: AsyncSession = Depends(get_db),
|
|
_: User = Depends(require_permission("imported_parts:read")),
|
|
):
|
|
return await imported_part_crud.list_all(db, skip=skip, limit=limit)
|
|
|
|
|
|
@router.get("/config", response_model=ImportedPartConfigRead)
|
|
async def get_config(
|
|
db: AsyncSession = Depends(get_db),
|
|
_: User = Depends(require_permission("imported_parts:write")),
|
|
):
|
|
config = await config_crud.get(db)
|
|
if config is None:
|
|
return ImportedPartConfigRead(odata_url=None, username=None, has_password=False)
|
|
return ImportedPartConfigRead(
|
|
odata_url=config.odata_url,
|
|
username=config.username,
|
|
has_password=bool(config.password),
|
|
)
|
|
|
|
|
|
@router.patch("/config", response_model=ImportedPartConfigRead)
|
|
async def update_config(
|
|
payload: ImportedPartConfigUpdate,
|
|
db: AsyncSession = Depends(get_db),
|
|
actor: User = Depends(require_permission("imported_parts:write")),
|
|
):
|
|
current = await config_crud.get(db)
|
|
# Keep existing password if not provided in the update
|
|
new_password = (
|
|
payload.password
|
|
if payload.password is not None
|
|
else (current.password if current else None)
|
|
)
|
|
config = await config_crud.upsert(
|
|
db,
|
|
odata_url=payload.odata_url,
|
|
username=payload.username,
|
|
password=new_password,
|
|
)
|
|
await audit_crud.log(
|
|
db,
|
|
actor=actor,
|
|
action="update",
|
|
resource_type="ImportedPartConfig",
|
|
resource_id=1,
|
|
description="Updated ImportedPart OData configuration",
|
|
)
|
|
return ImportedPartConfigRead(
|
|
odata_url=config.odata_url,
|
|
username=config.username,
|
|
has_password=bool(config.password),
|
|
)
|
|
|
|
|
|
@router.post("/refresh", response_model=SyncResult)
|
|
async def refresh_imported_parts(
|
|
db: AsyncSession = Depends(get_db),
|
|
actor: User = Depends(require_permission("imported_parts:write")),
|
|
):
|
|
config = await config_crud.get(db)
|
|
if not config or not config.odata_url:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail="OData URL is not configured.",
|
|
)
|
|
records = await odata_service.fetch(
|
|
config.odata_url, config.username, config.password
|
|
)
|
|
created, updated = await imported_part_crud.upsert_bulk(db, records)
|
|
await audit_crud.log(
|
|
db,
|
|
actor=actor,
|
|
action="update",
|
|
resource_type="ImportedPart",
|
|
resource_id=None,
|
|
description=f"OData sync: {created} created, {updated} updated ({len(records)} total records)",
|
|
)
|
|
return SyncResult(created=created, updated=updated, total=len(records))
|
|
|
|
|
|
@router.get("/{inventory_id}", response_model=ImportedPartRead)
|
|
async def get_imported_part(
|
|
inventory_id: str,
|
|
db: AsyncSession = Depends(get_db),
|
|
_: User = Depends(require_permission("imported_parts:read")),
|
|
):
|
|
part = await imported_part_crud.get(db, inventory_id)
|
|
if part is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND, detail="Imported part not found"
|
|
)
|
|
return part
|
|
|
|
|
|
@router.delete("/{inventory_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
async def delete_imported_part(
|
|
inventory_id: str,
|
|
db: AsyncSession = Depends(get_db),
|
|
actor: User = Depends(require_permission("imported_parts:delete")),
|
|
):
|
|
part = await imported_part_crud.get(db, inventory_id)
|
|
if part is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND, detail="Imported part not found"
|
|
)
|
|
await imported_part_crud.delete(db, part)
|
|
await audit_crud.log(
|
|
db,
|
|
actor=actor,
|
|
action="delete",
|
|
resource_type="ImportedPart",
|
|
resource_id=None,
|
|
description=audit_crud.describe_delete("ImportedPart", 0, inventory_id),
|
|
)
|