Start integrating the onboarding flow with backend 3
This commit is contained in:
@@ -10,7 +10,7 @@ import structlog
|
||||
import json
|
||||
|
||||
from app.services.data_import_service import DataImportService
|
||||
from shared.auth.decorators import get_current_user_dep, get_current_tenant_id_dep
|
||||
from shared.auth.decorators import get_current_user_dep
|
||||
|
||||
router = APIRouter(tags=["data-import"])
|
||||
logger = structlog.get_logger()
|
||||
@@ -26,14 +26,10 @@ async def validate_json_data(
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
data: Dict[str, Any] = None,
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
import_service: DataImportService = Depends(get_import_service)
|
||||
):
|
||||
"""Validate JSON sales data"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
if not data:
|
||||
raise HTTPException(status_code=400, detail="No data provided")
|
||||
@@ -81,18 +77,21 @@ async def validate_sales_data_universal(
|
||||
data: Optional[Dict[str, Any]] = None,
|
||||
file_format: Optional[str] = Form(None),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
import_service: DataImportService = Depends(get_import_service)
|
||||
):
|
||||
"""Universal validation endpoint for sales data - supports files and JSON"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
# Debug logging at the start
|
||||
logger.info("=== VALIDATION ENDPOINT CALLED ===",
|
||||
tenant_id=tenant_id,
|
||||
file_present=file is not None,
|
||||
file_filename=file.filename if file else None,
|
||||
data_present=data is not None,
|
||||
file_format=file_format)
|
||||
|
||||
# Handle file upload validation
|
||||
if file:
|
||||
logger.info("Validating uploaded file", tenant_id=tenant_id, filename=file.filename)
|
||||
if file and file.filename:
|
||||
logger.info("Processing file upload branch", tenant_id=tenant_id, filename=file.filename)
|
||||
|
||||
# Auto-detect format from filename
|
||||
filename = file.filename.lower()
|
||||
@@ -125,7 +124,7 @@ async def validate_sales_data_universal(
|
||||
|
||||
# Handle JSON data validation
|
||||
elif data:
|
||||
logger.info("Validating JSON data", tenant_id=tenant_id)
|
||||
logger.info("Processing JSON data branch", tenant_id=tenant_id, data_keys=list(data.keys()) if data else [])
|
||||
|
||||
validation_data = data.copy()
|
||||
validation_data["tenant_id"] = str(tenant_id)
|
||||
@@ -133,10 +132,13 @@ async def validate_sales_data_universal(
|
||||
validation_data["data_format"] = "json"
|
||||
|
||||
else:
|
||||
logger.error("No file or data provided", tenant_id=tenant_id, file_present=file is not None, data_present=data is not None)
|
||||
raise HTTPException(status_code=400, detail="No file or data provided for validation")
|
||||
|
||||
# Perform validation
|
||||
logger.info("About to call validate_import_data", validation_data_keys=list(validation_data.keys()), data_size=len(validation_data.get("data", "")))
|
||||
validation_result = await import_service.validate_import_data(validation_data)
|
||||
logger.info("Validation completed", is_valid=validation_result.is_valid, errors_count=len(validation_result.errors))
|
||||
|
||||
logger.info("Validation completed",
|
||||
tenant_id=tenant_id,
|
||||
@@ -161,8 +163,9 @@ async def validate_sales_data_universal(
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to validate sales data", error=str(e), tenant_id=tenant_id)
|
||||
raise HTTPException(status_code=500, detail=f"Failed to validate data: {str(e)}")
|
||||
error_msg = str(e) if e else "Unknown error occurred during validation"
|
||||
logger.error("Failed to validate sales data", error=error_msg, tenant_id=tenant_id, exc_info=True)
|
||||
raise HTTPException(status_code=500, detail=f"Failed to validate data: {error_msg}")
|
||||
|
||||
|
||||
@router.post("/tenants/{tenant_id}/sales/import/validate-csv")
|
||||
@@ -170,7 +173,6 @@ async def validate_csv_data_legacy(
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
file: UploadFile = File(...),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
import_service: DataImportService = Depends(get_import_service)
|
||||
):
|
||||
"""Legacy CSV validation endpoint - redirects to universal validator"""
|
||||
@@ -178,7 +180,6 @@ async def validate_csv_data_legacy(
|
||||
tenant_id=tenant_id,
|
||||
file=file,
|
||||
current_user=current_user,
|
||||
current_tenant=current_tenant,
|
||||
import_service=import_service
|
||||
)
|
||||
|
||||
@@ -191,14 +192,10 @@ async def import_sales_data(
|
||||
file_format: Optional[str] = Form(None),
|
||||
update_existing: bool = Form(False, description="Whether to update existing records"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
import_service: DataImportService = Depends(get_import_service)
|
||||
):
|
||||
"""Enhanced import sales data - supports multiple file formats and JSON"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
# Handle file upload (form data)
|
||||
if file:
|
||||
@@ -302,14 +299,10 @@ async def import_csv_data(
|
||||
file: UploadFile = File(...),
|
||||
update_existing: bool = Form(False, description="Whether to update existing records"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
import_service: DataImportService = Depends(get_import_service)
|
||||
):
|
||||
"""Import CSV sales data file"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
if not file.filename.endswith('.csv'):
|
||||
raise HTTPException(status_code=400, detail="File must be a CSV file")
|
||||
@@ -354,14 +347,10 @@ async def import_csv_data(
|
||||
@router.get("/tenants/{tenant_id}/sales/import/template")
|
||||
async def get_import_template(
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
format: str = "csv",
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep)
|
||||
format: str = "csv"
|
||||
):
|
||||
"""Get sales data import template"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
if format not in ["csv", "json"]:
|
||||
raise HTTPException(status_code=400, detail="Format must be 'csv' or 'json'")
|
||||
|
||||
@@ -16,7 +16,7 @@ from app.schemas.sales import (
|
||||
SalesDataQuery
|
||||
)
|
||||
from app.services.sales_service import SalesService
|
||||
from shared.auth.decorators import get_current_user_dep, get_current_tenant_id_dep
|
||||
from shared.auth.decorators import get_current_user_dep
|
||||
|
||||
router = APIRouter(tags=["sales"])
|
||||
logger = structlog.get_logger()
|
||||
@@ -32,15 +32,10 @@ async def create_sales_record(
|
||||
sales_data: SalesDataCreate,
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
sales_service: SalesService = Depends(get_sales_service)
|
||||
):
|
||||
"""Create a new sales record"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
logger.info(
|
||||
"Creating sales record",
|
||||
product=sales_data.product_name,
|
||||
@@ -82,15 +77,10 @@ async def get_sales_records(
|
||||
offset: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
order_by: str = Query("date", description="Field to order by"),
|
||||
order_direction: str = Query("desc", description="Order direction (asc/desc)"),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
sales_service: SalesService = Depends(get_sales_service)
|
||||
):
|
||||
"""Get sales records for a tenant with filtering and pagination"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
# Build query parameters
|
||||
query_params = SalesDataQuery(
|
||||
start_date=start_date,
|
||||
@@ -124,15 +114,10 @@ async def get_sales_analytics(
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
start_date: Optional[datetime] = Query(None, description="Start date filter"),
|
||||
end_date: Optional[datetime] = Query(None, description="End date filter"),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
sales_service: SalesService = Depends(get_sales_service)
|
||||
):
|
||||
"""Get sales analytics summary for a tenant"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
analytics = await sales_service.get_sales_analytics(tenant_id, start_date, end_date)
|
||||
|
||||
logger.info("Retrieved sales analytics", tenant_id=tenant_id)
|
||||
@@ -149,15 +134,10 @@ async def get_product_sales(
|
||||
inventory_product_id: UUID = Path(..., description="Inventory product ID"),
|
||||
start_date: Optional[datetime] = Query(None, description="Start date filter"),
|
||||
end_date: Optional[datetime] = Query(None, description="End date filter"),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
sales_service: SalesService = Depends(get_sales_service)
|
||||
):
|
||||
"""Get sales records for a specific product"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
records = await sales_service.get_product_sales(tenant_id, inventory_product_id, start_date, end_date)
|
||||
|
||||
logger.info("Retrieved product sales", count=len(records), inventory_product_id=inventory_product_id, tenant_id=tenant_id)
|
||||
@@ -171,15 +151,10 @@ async def get_product_sales(
|
||||
@router.get("/tenants/{tenant_id}/sales/categories", response_model=List[str])
|
||||
async def get_product_categories(
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
sales_service: SalesService = Depends(get_sales_service)
|
||||
):
|
||||
"""Get distinct product categories from sales data"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
categories = await sales_service.get_product_categories(tenant_id)
|
||||
|
||||
return categories
|
||||
@@ -197,15 +172,10 @@ async def get_product_categories(
|
||||
async def get_sales_record(
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
record_id: UUID = Path(..., description="Sales record ID"),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
sales_service: SalesService = Depends(get_sales_service)
|
||||
):
|
||||
"""Get a specific sales record"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
record = await sales_service.get_sales_record(record_id, tenant_id)
|
||||
|
||||
if not record:
|
||||
@@ -225,15 +195,10 @@ async def update_sales_record(
|
||||
update_data: SalesDataUpdate,
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
record_id: UUID = Path(..., description="Sales record ID"),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
sales_service: SalesService = Depends(get_sales_service)
|
||||
):
|
||||
"""Update a sales record"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
updated_record = await sales_service.update_sales_record(record_id, update_data, tenant_id)
|
||||
|
||||
logger.info("Updated sales record", record_id=record_id, tenant_id=tenant_id)
|
||||
@@ -251,15 +216,10 @@ async def update_sales_record(
|
||||
async def delete_sales_record(
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
record_id: UUID = Path(..., description="Sales record ID"),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
sales_service: SalesService = Depends(get_sales_service)
|
||||
):
|
||||
"""Delete a sales record"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
success = await sales_service.delete_sales_record(record_id, tenant_id)
|
||||
|
||||
if not success:
|
||||
@@ -281,15 +241,10 @@ async def validate_sales_record(
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
record_id: UUID = Path(..., description="Sales record ID"),
|
||||
validation_notes: Optional[str] = Query(None, description="Validation notes"),
|
||||
current_tenant: str = Depends(get_current_tenant_id_dep),
|
||||
sales_service: SalesService = Depends(get_sales_service)
|
||||
):
|
||||
"""Mark a sales record as validated"""
|
||||
try:
|
||||
# Verify tenant access
|
||||
if str(tenant_id) != current_tenant:
|
||||
raise HTTPException(status_code=403, detail="Access denied to this tenant")
|
||||
|
||||
validated_record = await sales_service.validate_sales_record(record_id, tenant_id, validation_notes)
|
||||
|
||||
logger.info("Validated sales record", record_id=record_id, tenant_id=tenant_id)
|
||||
|
||||
Reference in New Issue
Block a user