Improve the frontend 2

This commit is contained in:
Urtzi Alfaro
2025-10-29 06:58:05 +01:00
parent 858d985c92
commit 36217a2729
98 changed files with 6652 additions and 4230 deletions

View File

@@ -16,6 +16,7 @@ from shared.routing import RouteBuilder
from shared.security import create_audit_logger, AuditSeverity, AuditAction
from app.core.database import get_db
from app.services.orders_service import OrdersService
from app.models import AuditLog
from app.schemas.order_schemas import (
CustomerCreate,
CustomerUpdate,
@@ -23,7 +24,7 @@ from app.schemas.order_schemas import (
)
logger = structlog.get_logger()
audit_logger = create_audit_logger("orders-service")
audit_logger = create_audit_logger("orders-service", AuditLog)
# Create route builder for consistent URL structure
route_builder = RouteBuilder('orders')

View File

@@ -154,7 +154,7 @@ async def update_order_status(
order_id,
tenant_id,
new_status,
user_id=UUID(current_user["sub"]),
user_id=UUID(current_user["user_id"]),
reason=reason
)

View File

@@ -17,6 +17,7 @@ from shared.routing import RouteBuilder
from shared.security import create_audit_logger, AuditSeverity, AuditAction
from app.core.database import get_db
from app.services.orders_service import OrdersService
from app.models import AuditLog
from app.schemas.order_schemas import (
OrderCreate,
OrderUpdate,
@@ -24,7 +25,7 @@ from app.schemas.order_schemas import (
)
logger = structlog.get_logger()
audit_logger = create_audit_logger("orders-service")
audit_logger = create_audit_logger("orders-service", AuditLog)
# Create route builder for consistent URL structure
route_builder = RouteBuilder('orders')
@@ -217,7 +218,7 @@ async def update_order(
db,
db_obj=order,
obj_in=order_data.dict(exclude_unset=True),
updated_by=UUID(current_user["sub"])
updated_by=UUID(current_user["user_id"])
)
# Commit the transaction to persist changes

View File

@@ -10,6 +10,7 @@ from uuid import UUID
import structlog
from shared.config.base import BaseServiceSettings
from shared.utils.tenant_settings_client import TenantSettingsClient
logger = structlog.get_logger()
@@ -18,10 +19,16 @@ class ApprovalRulesService:
"""
Service for evaluating purchase orders against approval rules
Implements smart auto-approval logic based on multiple criteria
Uses tenant-specific settings from the database instead of system-level config
"""
def __init__(self, config: BaseServiceSettings):
def __init__(self, config: BaseServiceSettings, tenant_id: UUID):
self.config = config
self.tenant_id = tenant_id
# Initialize tenant settings client
tenant_service_url = getattr(config, 'TENANT_SERVICE_URL', 'http://tenant-service:8000')
self.tenant_settings_client = TenantSettingsClient(tenant_service_url=tenant_service_url)
async def evaluate_po_for_auto_approval(
self,
@@ -30,39 +37,60 @@ class ApprovalRulesService:
requirements_data: Optional[List[Dict[str, Any]]] = None
) -> Tuple[bool, List[str]]:
"""
Evaluate if a PO should be auto-approved
Evaluate if a PO should be auto-approved using tenant-specific settings
Returns:
Tuple of (should_auto_approve, reasons)
"""
if not self.config.AUTO_APPROVE_ENABLED:
return False, ["Auto-approval is disabled in configuration"]
# Fetch tenant-specific procurement settings
try:
tenant_settings = await self.tenant_settings_client.get_procurement_settings(self.tenant_id)
except Exception as e:
logger.error("Failed to fetch tenant settings, using safe defaults",
tenant_id=str(self.tenant_id),
error=str(e))
# Use safe defaults if settings unavailable
tenant_settings = {
'auto_approve_enabled': False,
'auto_approve_threshold_eur': 500.0,
'auto_approve_min_supplier_score': 0.80,
'require_approval_new_suppliers': True,
'require_approval_critical_items': True
}
# Check if auto-approval is enabled for this tenant
if not tenant_settings.get('auto_approve_enabled', True):
return False, ["Auto-approval is disabled in tenant settings"]
reasons = []
should_approve = True
# Rule 1: Amount threshold check
total_amount = self._calculate_po_total(po_data)
if total_amount > self.config.AUTO_APPROVE_THRESHOLD_EUR:
threshold = Decimal(str(tenant_settings.get('auto_approve_threshold_eur', 500.0)))
if total_amount > threshold:
should_approve = False
reasons.append(
f"PO amount €{total_amount:.2f} exceeds threshold €{self.config.AUTO_APPROVE_THRESHOLD_EUR:.2f}"
f"PO amount €{total_amount:.2f} exceeds threshold €{threshold:.2f}"
)
else:
reasons.append(
f"PO amount €{total_amount:.2f} within threshold €{self.config.AUTO_APPROVE_THRESHOLD_EUR:.2f}"
f"PO amount €{total_amount:.2f} within threshold €{threshold:.2f}"
)
# Rule 2: Supplier trust score check
if supplier_data and self.config.AUTO_APPROVE_TRUSTED_SUPPLIERS:
min_supplier_score = tenant_settings.get('auto_approve_min_supplier_score', 0.80)
if supplier_data:
supplier_score = supplier_data.get('trust_score', 0.0)
is_preferred = supplier_data.get('is_preferred_supplier', False)
auto_approve_enabled = supplier_data.get('auto_approve_enabled', False)
if supplier_score < self.config.AUTO_APPROVE_MIN_SUPPLIER_SCORE:
if supplier_score < min_supplier_score:
should_approve = False
reasons.append(
f"Supplier trust score {supplier_score:.2f} below minimum {self.config.AUTO_APPROVE_MIN_SUPPLIER_SCORE:.2f}"
f"Supplier trust score {supplier_score:.2f} below minimum {min_supplier_score:.2f}"
)
else:
reasons.append(f"Supplier trust score {supplier_score:.2f} meets minimum requirements")
@@ -84,7 +112,9 @@ class ApprovalRulesService:
reasons.append("No supplier data available")
# Rule 3: New supplier check
if supplier_data and self.config.REQUIRE_APPROVAL_NEW_SUPPLIERS:
require_approval_new_suppliers = tenant_settings.get('require_approval_new_suppliers', True)
if supplier_data and require_approval_new_suppliers:
total_pos = supplier_data.get('total_pos_count', 0)
if total_pos < 5:
should_approve = False
@@ -93,7 +123,9 @@ class ApprovalRulesService:
reasons.append(f"Established supplier with {total_pos} previous orders")
# Rule 4: Critical/urgent items check
if requirements_data and self.config.REQUIRE_APPROVAL_CRITICAL_ITEMS:
require_approval_critical_items = tenant_settings.get('require_approval_critical_items', True)
if requirements_data and require_approval_critical_items:
critical_count = sum(
1 for req in requirements_data
if req.get('priority') in ['critical', 'urgent', 'CRITICAL', 'URGENT']

View File

@@ -502,7 +502,7 @@ class ProcurementService:
# Import approval rules service
from app.services.approval_rules_service import ApprovalRulesService
approval_service = ApprovalRulesService(self.config)
approval_service = ApprovalRulesService(self.config, tenant_id)
# Group requirements by supplier
supplier_requirements = {}