sync: Auto-sync from ACG-M-L5090 at 2026-03-10 19:11:00
Synced files: - Quote wizard frontend (all components, hooks, types, config) - API updates (config, models, routers, schemas, services) - Client work (bg-builders, gurushow) - Scripts (BGB Lesley termination, CIPP, Datto, migration) - Temp files (Bardach contacts, VWP investigation, misc) - Credentials and session logs - Email service, PHP API, session logs Machine: ACG-M-L5090 Timestamp: 2026-03-10 19:11:00 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -52,7 +52,7 @@ def list_quotes(
|
||||
status_filter: Optional[str] = Query(
|
||||
default=None,
|
||||
alias="status",
|
||||
description="Filter by status (draft, submitted, reviewing, approved, rejected, expired)"
|
||||
description="Filter by status (draft, submitted, viewed, followed_up, converted, expired)"
|
||||
),
|
||||
search: Optional[str] = Query(
|
||||
default=None,
|
||||
@@ -166,9 +166,9 @@ def get_stats(
|
||||
"quotes_by_status": {
|
||||
"draft": 45,
|
||||
"submitted": 60,
|
||||
"reviewing": 15,
|
||||
"approved": 25,
|
||||
"rejected": 3,
|
||||
"viewed": 15,
|
||||
"followed_up": 10,
|
||||
"converted": 25,
|
||||
"expired": 2
|
||||
},
|
||||
"total_monthly_value": "12500.00",
|
||||
@@ -229,7 +229,6 @@ def get_quote(
|
||||
"company_name": "Acme Corporation",
|
||||
"contact_name": "John Doe",
|
||||
"contact_email": "john@acme.com",
|
||||
"admin_notes": "Follow up scheduled for next week",
|
||||
"ip_address": "192.168.1.100",
|
||||
"user_agent": "Mozilla/5.0...",
|
||||
"items": [...],
|
||||
@@ -254,19 +253,19 @@ def get_quote(
|
||||
items_response.append(QuoteItemResponse(
|
||||
id=item.id,
|
||||
quote_id=item.quote_id,
|
||||
service_name=item.service_name,
|
||||
service_description=item.service_description,
|
||||
category=item.category,
|
||||
billing_frequency=item.billing_frequency,
|
||||
unit_price=item.unit_price,
|
||||
product_code=item.product_code,
|
||||
product_name=item.product_name,
|
||||
description=item.description,
|
||||
quantity=item.quantity,
|
||||
setup_fee=item.setup_fee,
|
||||
is_required=item.is_required,
|
||||
sort_order=item.sort_order,
|
||||
unit_price=item.unit_price,
|
||||
setup_price=item.setup_price,
|
||||
billing_frequency=item.billing_frequency,
|
||||
tier=item.tier,
|
||||
is_recommended=item.is_recommended,
|
||||
line_total=item.line_total,
|
||||
monthly_amount=item.monthly_amount,
|
||||
created_at=item.created_at,
|
||||
updated_at=item.updated_at
|
||||
))
|
||||
|
||||
activities_response = []
|
||||
@@ -275,8 +274,8 @@ def get_quote(
|
||||
id=activity.id,
|
||||
quote_id=activity.quote_id,
|
||||
action=activity.action,
|
||||
description=activity.description,
|
||||
actor=activity.actor,
|
||||
step_name=activity.step_name,
|
||||
details=activity.details,
|
||||
ip_address=activity.ip_address,
|
||||
created_at=activity.created_at
|
||||
))
|
||||
@@ -290,6 +289,8 @@ def get_quote(
|
||||
recipient=notification.recipient,
|
||||
subject=notification.subject,
|
||||
status=notification.status,
|
||||
attempts=notification.attempts,
|
||||
last_attempt_at=notification.last_attempt_at,
|
||||
sent_at=notification.sent_at,
|
||||
error_message=notification.error_message,
|
||||
created_at=notification.created_at
|
||||
@@ -304,11 +305,8 @@ def get_quote(
|
||||
contact_email=quote.contact_email,
|
||||
contact_phone=quote.contact_phone,
|
||||
employee_count=quote.employee_count,
|
||||
notes=quote.notes,
|
||||
admin_notes=quote.admin_notes,
|
||||
monthly_total=quote.monthly_total,
|
||||
setup_total=quote.setup_total,
|
||||
annual_total=quote.annual_total,
|
||||
expires_at=quote.expires_at,
|
||||
submitted_at=quote.submitted_at,
|
||||
ip_address=quote.ip_address,
|
||||
@@ -346,8 +344,8 @@ def update_quote(
|
||||
"""
|
||||
Update a quote's status or admin notes.
|
||||
|
||||
Admins can change the quote status (e.g., from submitted to reviewing
|
||||
or approved) and add internal notes.
|
||||
Admins can change the quote status (e.g., from submitted to viewed
|
||||
or converted) and update expiration.
|
||||
|
||||
**Example Request:**
|
||||
```json
|
||||
@@ -356,8 +354,7 @@ def update_quote(
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"status": "reviewing",
|
||||
"admin_notes": "Assigned to sales team. Follow up scheduled for Monday."
|
||||
"status": "viewed"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -365,8 +362,7 @@ def update_quote(
|
||||
```json
|
||||
{
|
||||
"id": "123e4567-e89b-12d3-a456-426614174000",
|
||||
"status": "reviewing",
|
||||
"admin_notes": "Assigned to sales team. Follow up scheduled for Monday.",
|
||||
"status": "viewed",
|
||||
...
|
||||
}
|
||||
```
|
||||
@@ -382,3 +378,47 @@ def update_quote(
|
||||
)
|
||||
|
||||
return get_quote(quote_id, db, current_user)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/{quote_id}/sync-syncro",
|
||||
summary="Sync quote to SyncroRMM",
|
||||
description="Create or update a lead in SyncroRMM from a submitted quote",
|
||||
status_code=status.HTTP_200_OK,
|
||||
responses={
|
||||
200: {
|
||||
"description": "Sync result",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"example": {
|
||||
"synced": True,
|
||||
"is_existing_customer": False,
|
||||
"syncro_lead_id": "12345",
|
||||
"error": None,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
404: {"description": "Quote not found"},
|
||||
},
|
||||
)
|
||||
async def sync_quote_to_syncro(
|
||||
quote_id: UUID,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
"""
|
||||
Manually trigger a SyncroRMM sync for a quote.
|
||||
|
||||
Checks for an existing customer in Syncro and creates a lead with
|
||||
the quote details. The quote must have a contact email to sync.
|
||||
|
||||
**Example Request:**
|
||||
```
|
||||
POST /api/admin/quotes/123e4567-e89b-12d3-a456-426614174000/sync-syncro
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
"""
|
||||
quote = quote_service.get_quote_by_id(db, quote_id)
|
||||
result = await quote_service.sync_quote_to_syncro(db, quote)
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user