Sales Module¶
Sales order management, quote builder, and sales dashboard.
Overview¶
The Sales module provides:
- Sales order list with state tabs
- Deep search across all orders
- Sales dashboard with analytics
- Quote creation from CRM leads
- Quote line editing with sections
- Photo/video gallery with S3 storage
- Activity logging
Routes¶
Sales Order List¶
GET /sales
Lists sales orders with state-based tabs.
| Parameter | Type | Description |
|---|---|---|
| state | string | Filter by state: sale, sent, draft |
States displayed:
| State | Label | Description |
|---|---|---|
sale |
Sales Order | Confirmed orders |
sent |
Quotation Sent | Sent but not confirmed |
draft |
Quotation | Draft quotes |
Search¶
GET /sales/search
Deep search across all sales orders.
| Parameter | Type | Description |
|---|---|---|
| q | string | Search query (order name or customer) |
Order Detail¶
GET /sales/{order_id}
Displays full order details with:
- Order lines grouped by sections
- Customer information
- Activity log
- Photo/video gallery
Sales Dashboard¶
GET /sales/dashboard
Analytics dashboard showing:
- This week's sales (count and total)
- This month's sales
- Last month's sales
- 6-month bar chart
Quote Edit¶
GET /quotes/{quote_id}/edit
Quote builder interface for editing quotes:
- Add/edit sections (rooms)
- Add product lines with dimensions
- Add notes
- Upload photos/videos
- Reorder items via drag-drop
API Endpoints¶
Quote Management¶
Create Quote from Lead¶
GET /crm/lead/{lead_id}/quote/new
Creates a draft quote linked to CRM lead and redirects to edit page.
Add Section¶
POST /api/quotes/{quote_id}/sections
Response:
Add Note¶
POST /api/quotes/{quote_id}/notes
Add Product Line¶
POST /api/quotes/{quote_id}/lines
{
"product_id": 45,
"width": 48.5,
"height": 72,
"quantity": 2,
"location_id": 12,
"motorized": "Motorized",
"mount": "in",
"valance": "standard",
"remote": "YES",
"smart_hub": "NO",
"price_unit": 299.99
}
Update Line¶
PUT /api/quotes/{quote_id}/lines/{line_id}
Delete Line¶
DELETE /api/quotes/{quote_id}/lines/{line_id}
Reorder Lines¶
POST /api/quotes/{quote_id}/reorder
{
"lines": [
{"id": 101, "sequence": 10},
{"id": 102, "sequence": 20},
{"id": 103, "sequence": 30}
]
}
Duplicate Quote¶
POST /api/quotes/{quote_id}/duplicate
Response:
Duplicate Line¶
POST /api/quotes/{quote_id}/lines/{line_id}/duplicate
Send Quote Email¶
POST /api/quotes/{quote_id}/send
Sends quotation email with PDF and portal link.
Response:
Photo/Video Management¶
Upload Photo¶
POST /api/quotes/{quote_id}/photos
Multipart form with file field (image/*).
Response:
{
"success": true,
"attachment_id": 234,
"url": "https://s3.amazonaws.com/...",
"filename": "1702345678_abc12345.jpg",
"s3_path": "bucket/quotes/123/photos/1702345678_abc12345.jpg"
}
Upload Video¶
POST /api/quotes/{quote_id}/videos
Multipart form with file field (video/*).
Delete Attachment¶
DELETE /api/quotes/{quote_id}/attachments/{attachment_id}
Deletes from both S3 and Odoo.
Product Search¶
GET /api/products/search
| Parameter | Type | Description |
|---|---|---|
| q | string | Search term (name or code) |
Response:
{
"success": true,
"products": [
{"id": 45, "name": "Premium Blinds", "default_code": "BL-001", "list_price": 199.99}
]
}
Locations¶
GET /api/locations
Get all item locations for dropdown.
POST /api/locations
Create new location:
Comments¶
POST /api/sales/{order_id}/comment
Dashboard Analytics¶
Date Ranges¶
| Period | Calculation |
|---|---|
| This Week | Monday to today |
| This Month | 1st to today |
| Last Month | 1st to last day of previous month |
Sales Stats Query¶
def get_sales_stats_by_date_range(start_date, end_date):
domain = [
('state', '=', 'sale'), # Only confirmed orders
('date_order', '>=', f'{start_date} 00:00:00'),
('date_order', '<=', f'{end_date} 23:59:59')
]
# Returns count and total_amount
Quote Line Types¶
| display_type | Description |
|---|---|
| (none) | Product line with pricing |
line_section |
Section header (room/floor) |
line_note |
Note/comment line |
Product Line Fields¶
| Field | Type | Description |
|---|---|---|
product_id |
Many2one | Product reference |
width |
Float | Width in inches/mm |
height |
Float | Height in inches/mm |
product_uom_qty |
Float | Quantity |
price_unit |
Float | Unit price |
item_location_id |
Many2one | Room/location |
motorized |
Selection | L, R, Motorized, Cordless |
mount |
Selection | in (Inside), out (Outside) |
valance |
Selection | open, standard, compact_25 |
remote |
Selection | YES, NO |
smart_hub |
Selection | YES, NO |
S3 Photo Storage¶
Photos are stored in S3 with path format:
Videos:
Photos are linked to Odoo via ir.attachment with type='url'.
Send Quote Flow¶
sequenceDiagram
participant User
participant PWA
participant Odoo
participant Email
User->>PWA: Click "Send Quote"
PWA->>Odoo: Find email template
PWA->>Odoo: message_post_with_template()
Odoo->>Odoo: Generate PDF
Odoo->>Email: Send email with PDF
PWA->>Odoo: Update state to 'sent'
PWA-->>User: Success
Activity Attribution¶
Comments are attributed to the logged-in user: