Add whatsapp feature
This commit is contained in:
@@ -180,6 +180,35 @@ class TenantSettings(Base):
|
||||
"ml_confidence_threshold": 0.80
|
||||
})
|
||||
|
||||
# Notification Settings (Notification Service)
|
||||
notification_settings = Column(JSON, nullable=False, default=lambda: {
|
||||
# WhatsApp Configuration
|
||||
"whatsapp_enabled": False,
|
||||
"whatsapp_phone_number_id": "", # Meta WhatsApp Phone Number ID
|
||||
"whatsapp_access_token": "", # Meta access token (should be encrypted)
|
||||
"whatsapp_business_account_id": "", # Meta Business Account ID
|
||||
"whatsapp_api_version": "v18.0",
|
||||
"whatsapp_default_language": "es",
|
||||
|
||||
# Email Configuration
|
||||
"email_enabled": True,
|
||||
"email_from_address": "",
|
||||
"email_from_name": "",
|
||||
"email_reply_to": "",
|
||||
|
||||
# Notification Preferences
|
||||
"enable_po_notifications": True,
|
||||
"enable_inventory_alerts": True,
|
||||
"enable_production_alerts": True,
|
||||
"enable_forecast_alerts": True,
|
||||
|
||||
# Notification Channels
|
||||
"po_notification_channels": ["email"], # ["email", "whatsapp"]
|
||||
"inventory_alert_channels": ["email"],
|
||||
"production_alert_channels": ["email"],
|
||||
"forecast_alert_channels": ["email"]
|
||||
})
|
||||
|
||||
# Timestamps
|
||||
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc), nullable=False)
|
||||
@@ -321,5 +350,25 @@ class TenantSettings(Base):
|
||||
"enable_ml_insights": True,
|
||||
"ml_insights_auto_trigger": False,
|
||||
"ml_confidence_threshold": 0.80
|
||||
},
|
||||
"notification_settings": {
|
||||
"whatsapp_enabled": False,
|
||||
"whatsapp_phone_number_id": "",
|
||||
"whatsapp_access_token": "",
|
||||
"whatsapp_business_account_id": "",
|
||||
"whatsapp_api_version": "v18.0",
|
||||
"whatsapp_default_language": "es",
|
||||
"email_enabled": True,
|
||||
"email_from_address": "",
|
||||
"email_from_name": "",
|
||||
"email_reply_to": "",
|
||||
"enable_po_notifications": True,
|
||||
"enable_inventory_alerts": True,
|
||||
"enable_production_alerts": True,
|
||||
"enable_forecast_alerts": True,
|
||||
"po_notification_channels": ["email"],
|
||||
"inventory_alert_channels": ["email"],
|
||||
"production_alert_channels": ["email"],
|
||||
"forecast_alert_channels": ["email"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +218,58 @@ class MLInsightsSettings(BaseModel):
|
||||
ml_confidence_threshold: float = Field(0.80, ge=0.0, le=1.0, description="Minimum confidence threshold for ML recommendations")
|
||||
|
||||
|
||||
class NotificationSettings(BaseModel):
|
||||
"""Notification and communication settings"""
|
||||
# WhatsApp Configuration
|
||||
whatsapp_enabled: bool = Field(False, description="Enable WhatsApp notifications for this tenant")
|
||||
whatsapp_phone_number_id: str = Field("", description="Meta WhatsApp Phone Number ID")
|
||||
whatsapp_access_token: str = Field("", description="Meta WhatsApp Access Token (encrypted)")
|
||||
whatsapp_business_account_id: str = Field("", description="Meta WhatsApp Business Account ID")
|
||||
whatsapp_api_version: str = Field("v18.0", description="WhatsApp Cloud API version")
|
||||
whatsapp_default_language: str = Field("es", description="Default language for WhatsApp templates")
|
||||
|
||||
# Email Configuration
|
||||
email_enabled: bool = Field(True, description="Enable email notifications for this tenant")
|
||||
email_from_address: str = Field("", description="Custom from email address (optional)")
|
||||
email_from_name: str = Field("", description="Custom from name (optional)")
|
||||
email_reply_to: str = Field("", description="Reply-to email address (optional)")
|
||||
|
||||
# Notification Preferences
|
||||
enable_po_notifications: bool = Field(True, description="Enable purchase order notifications")
|
||||
enable_inventory_alerts: bool = Field(True, description="Enable inventory alerts")
|
||||
enable_production_alerts: bool = Field(True, description="Enable production alerts")
|
||||
enable_forecast_alerts: bool = Field(True, description="Enable forecast alerts")
|
||||
|
||||
# Notification Channels
|
||||
po_notification_channels: list[str] = Field(["email"], description="Channels for PO notifications (email, whatsapp)")
|
||||
inventory_alert_channels: list[str] = Field(["email"], description="Channels for inventory alerts")
|
||||
production_alert_channels: list[str] = Field(["email"], description="Channels for production alerts")
|
||||
forecast_alert_channels: list[str] = Field(["email"], description="Channels for forecast alerts")
|
||||
|
||||
@validator('po_notification_channels', 'inventory_alert_channels', 'production_alert_channels', 'forecast_alert_channels')
|
||||
def validate_channels(cls, v):
|
||||
"""Validate that channels are valid"""
|
||||
valid_channels = ["email", "whatsapp", "sms", "push"]
|
||||
for channel in v:
|
||||
if channel not in valid_channels:
|
||||
raise ValueError(f"Invalid channel: {channel}. Must be one of {valid_channels}")
|
||||
return v
|
||||
|
||||
@validator('whatsapp_phone_number_id')
|
||||
def validate_phone_number_id(cls, v, values):
|
||||
"""Validate phone number ID is provided if WhatsApp is enabled"""
|
||||
if values.get('whatsapp_enabled') and not v:
|
||||
raise ValueError("whatsapp_phone_number_id is required when WhatsApp is enabled")
|
||||
return v
|
||||
|
||||
@validator('whatsapp_access_token')
|
||||
def validate_access_token(cls, v, values):
|
||||
"""Validate access token is provided if WhatsApp is enabled"""
|
||||
if values.get('whatsapp_enabled') and not v:
|
||||
raise ValueError("whatsapp_access_token is required when WhatsApp is enabled")
|
||||
return v
|
||||
|
||||
|
||||
# ================================================================
|
||||
# REQUEST/RESPONSE SCHEMAS
|
||||
# ================================================================
|
||||
@@ -237,6 +289,7 @@ class TenantSettingsResponse(BaseModel):
|
||||
moq_settings: MOQSettings
|
||||
supplier_selection_settings: SupplierSelectionSettings
|
||||
ml_insights_settings: MLInsightsSettings
|
||||
notification_settings: NotificationSettings
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
@@ -257,6 +310,7 @@ class TenantSettingsUpdate(BaseModel):
|
||||
moq_settings: Optional[MOQSettings] = None
|
||||
supplier_selection_settings: Optional[SupplierSelectionSettings] = None
|
||||
ml_insights_settings: Optional[MLInsightsSettings] = None
|
||||
notification_settings: Optional[NotificationSettings] = None
|
||||
|
||||
|
||||
class CategoryUpdateRequest(BaseModel):
|
||||
|
||||
@@ -23,7 +23,8 @@ from ..schemas.tenant_settings import (
|
||||
ReplenishmentSettings,
|
||||
SafetyStockSettings,
|
||||
MOQSettings,
|
||||
SupplierSelectionSettings
|
||||
SupplierSelectionSettings,
|
||||
NotificationSettings
|
||||
)
|
||||
|
||||
logger = structlog.get_logger()
|
||||
@@ -46,7 +47,8 @@ class TenantSettingsService:
|
||||
"replenishment": ReplenishmentSettings,
|
||||
"safety_stock": SafetyStockSettings,
|
||||
"moq": MOQSettings,
|
||||
"supplier_selection": SupplierSelectionSettings
|
||||
"supplier_selection": SupplierSelectionSettings,
|
||||
"notification": NotificationSettings
|
||||
}
|
||||
|
||||
# Map category names to database column names
|
||||
@@ -60,7 +62,8 @@ class TenantSettingsService:
|
||||
"replenishment": "replenishment_settings",
|
||||
"safety_stock": "safety_stock_settings",
|
||||
"moq": "moq_settings",
|
||||
"supplier_selection": "supplier_selection_settings"
|
||||
"supplier_selection": "supplier_selection_settings",
|
||||
"notification": "notification_settings"
|
||||
}
|
||||
|
||||
def __init__(self, db: AsyncSession):
|
||||
|
||||
Reference in New Issue
Block a user