CRMconnect Azuvio · Docs

Workflow: Catering Order — From Enquiry to Invoice

Modules involved: Catering (Events · Menus · Items · Packages · Staff · Ingredients) · Estimates · Invoices · Projects
Used by: Catering Manager · Chef · Event Coordinator · Finance
Typical duration: Enquiry → Confirmation = 1–7 days · Event = 1 day · Invoicing = immediately after event

Overview

The Catering Management module covers the complete cycle of a catering event: from the initial enquiry, through menu and package configuration, confirmation, event execution with staff assignment, through to estimate generation and invoicing.

Internal cost and margin calculation (ingredient cost vs. selling price) is available, but visible exclusively to users with the special catering_view_costs permission.

Warehouse: The module has its own internal ingredient system (catering_ingredients) with reference stock. It does not integrate with the core Warehouse module — stock decreases do not happen automatically when an event is executed.

There is no automatic approval workflow. Any staff member with the catering_events → edit permission can change the event status to any value, without gate logic.


Flow diagram

[SETUP — admin, one time]
  │
  ├── Event Types (event categories: Wedding, Corporate, Conference, etc.)
  ├── Dietary Types + Allergens (nutritional references per product)
  ├── Menu Categories (hierarchical) + Menu Sections (groups within a menu)
  ├── Ingredients (with avg_cost_per_unit, stock_on_hand, reorder_level)
  ├── Menu Items (with unit_cost, unit_price, dietary types, allergens, ingredients)
  ├── Template Menus (collections of items grouped by sections)
  ├── Packages (fixed bundle with qty_per_guest per item, min/max guests)
  └── Staff Roles (Head Chef, Chef, Server, Bartender, Manager, Driver — 6 seeded by default)
  │
  ↓
[1. ENQUIRY]
  │
  ├── Catering → Events → New Event
  ├── Required fields: event_name, event_type_id, event_start, event_end
  ├── Client: client_id (existing client) OR lead_id (prospect)
  │     ⚠ Estimate/Invoice can only be generated if client_id exists, not lead_id
  ├── guest_count_expected: estimated number of guests
  ├── Venue: venue_name, venue_address
  ├── Optional: create_project=1 → automatically creates a project linked to the event
  └── Initial status: enquiry
  │
  ↓
[2. MENU CONFIGURATION]
  │
  ├── Events → {event} → Menu tab → Assign Menu / Package
  ├── Select template menu OR package
  ├── Pricing mode:
  │     ├── per_person: price × guest_count_expected per item
  │     ├── fixed: fixed total price
  │     └── package: price from package (price_per_person × guests)
  ├── Additional fields: multiplier (markup), weekend_surcharge, notes
  ├── Items from template are copied into catering_event_menu_items
  │     (snapshot with current version of the item + dietary/allergen snapshot JSON)
  └── Any item modifications → recorded in catering_event_menu_history
  │
  ↓
[3. GENERATE ESTIMATE]
  │
  ├── Events → {event} → Generate Estimate button
  ├── Automatically creates a standard Estimate in CRM with lines:
  │     ├── Section headers (qty=0, rate=0)
  │     ├── Item lines: qty = guest_count_expected, rate = unit_price
  │     └── Staff labor lines: qty = hours, rate = hourly_rate
  ├── estimate_id saved on event
  ├── Event status: enquiry → quoted
  └── Estimate can be edited, sent to client, signed
  │
  ↓
[4. CONFIRMATION]
  │
  ├── Client accepts the estimate
  ├── Event status: quoted → confirmed (changed manually by staff)
  └── Optional: staff assignment for event (shift, role, estimated hours)
  │
  ↓
[5. EVENT EXECUTION]
  │
  ├── Event status: confirmed → in_progress
  ├── Assigned staff see their role and shift
  ├── Staff assignment status: pending → confirmed/declined → completed
  └── Internal notes: catering_event_notes (visible_to_client optional)
  │
  ↓
[6. COMPLETION + INVOICING]
  │
  ├── Event status: in_progress → completed
  ├── guest_count_final filled in (actual number of guests)
  ├── Events → {event} → Convert to Invoice button
  │     → calls Estimates_model::convert_to_invoice(estimate_id)
  │     → invoice_id saved on event
  └── Invoice tracked and paid as standard in Invoices
  │
  ↓
[INTERNAL FINANCIALS — optional, visible with catering_view_costs]
  │
  ├── calculate_event_financials(): calculates internal P&L:
  │     ├── menu.total_cost = qty × unit_cost per item
  │     ├── menu.total_revenue = qty × unit_price per item
  │     ├── labor.total_cost = hours × hourly_rate per staff
  │     └── summary: net_profit, profit_margin
  └── Visible ONLY with the catering_view_costs permission

[EVENT INVOICED ✓ · P&L CALCULATED ✓]

Step by step

1. Initial configuration (admin)

Configuration order:

1a. Event Types

Where: Catering → Settings → Event Types → Add

Each type has a background and text color (for the calendar). At least one type is required when creating an event.

1b. Dietary Types and Allergens

Where: Catering → Settings → Dietary Types / Allergens

Nutritional references (gluten-free, vegan, halal, etc.) and allergens (nuts, dairy, etc. — with severity: mild/moderate/severe). Attached to Menu Items.

1c. Menu Categories (hierarchical) and Sections

Where: Catering → Settings → Categories / Sections

Categories are hierarchical (parent_id). Sections group items within a menu (e.g.: "Starters", "Main course", "Dessert").

1d. Ingredients

Where: Catering → Ingredients → Add

Field Description
name Ingredient name
unit Unit of measure
avg_cost_per_unit Average cost per unit
stock_on_hand Available stock (reference — does not decrease automatically)
reorder_level Reorder level (visual alert)
supplier_id Supplier (from catering_suppliers)

1e. Menu Items

Where: Catering → Menu Items → Add

Field Description
item_name Product name
category_id Category
unit_cost Cost per portion (ingredient cost)
unit_price Selling price per portion
default_portion_size Portion size
prep_time_minutes Preparation time

Version control: If unit_cost or unit_price changes, version is automatically incremented. The snapshot at the time of assignment to an event is saved in item_version on catering_event_menu_items.

Add dietary types, allergens, and ingredients (with qty_per_portion) to each item.

1f. Template Menus and Packages

Menus (Catering → Menus → Add): collection of items organized by sections. When assigned to an event, items are copied with a snapshot.

Packages (Catering → Packages → Add):

Field Description
package_name Package name
price_per_person Price per person
min_guests / max_guests Minimum/maximum number of guests
Items Added with qty_per_guest per item

1g. Staff Roles

Where: Catering → Settings → Staff Roles

6 roles seeded by default: Head Chef ($45/h), Chef ($35/h), Server ($25/h), Bartender ($30/h), Manager ($40/h), Driver ($20/h). Add custom roles with default_hourly_rate.


2. Creating an event

Where: /admin/catering_management_module/events → New Event

Key fields:

Field Required Description
event_name Yes Event name
event_type_id Yes Event type
event_start / event_end Yes Start/end date and time
client_id Recommended Existing client (required for estimate/invoice generation)
lead_id Alternative Lead (without the ability to generate financial documents)
guest_count_expected Yes Estimated number of guests (used in per_person pricing calculation)
venue_name / venue_address Yes Event location
dietary_notes / allergen_summary No General dietary notes for the event
create_project No 1 = automatically creates a linked CRM project

3. Event statuses

Status Meaning Transition
enquiry Initial enquiry → quoted on estimate generation
quoted Estimate generated and sent → confirmed on acceptance
confirmed Booking confirmed → in_progress on event date
in_progress Event in progress → completed on finish
completed Event finished → generate invoice
cancelled Cancelled (terminal)
lost Lost (terminal)

All transitions are manual — any staff with catering_events → edit can set any status.


4. Staff assignment for event

Where: Events → {event} → Staff tab → Add Staff

Field Description
staff_id Assigned employee
role Role at the event
shift_start / shift_end Work shift
hours Total hours (automatically calculated from shift_start/end)
hourly_rate Hourly rate (pre-populated from Staff Role)

Assignment statuses: pendingconfirmed / declinedcompleted

Conflict detection: The system automatically checks whether the staff member has an overlapping assignment (check_scheduling_conflicts()) before saving.

Staff notification: notify_all_staff() exists in the code but does not send email — it only logs to the activity log. Notify staff manually.


5. Generate estimate and invoice

Generate estimate: Events → {event} → Generate Estimate button

The created estimate includes:

  • Section headers (for visual organization)
  • Product lines: qty = guest_count_expected, rate = unit_price per item
  • Labor lines: qty = hours, rate = hourly_rate per assigned staff

The estimate appears in /admin/estimates and can be edited, sent, and signed like any standard estimate.

Convert to invoice: Events → {event} → Convert to Invoice button (available after Generate Estimate)

Calls Estimates_model::convert_to_invoice($estimate_id) → standard invoice in /admin/invoices.


6. Internal P&L calculation

Available exclusively with the catering_view_costs permission:

Metric Calculation
menu.total_cost unit_cost × portion_per_guest × guest_count_expected per item
menu.total_revenue unit_price × portion_per_guest × guest_count_expected per item
labor.total_cost hours × hourly_rate per assigned staff
net_profit total_revenue - total_cost - labor_cost
profit_margin net_profit / total_revenue × 100

External expenses (expenses.total_cost) are a placeholder in the code — not implemented. External costs cannot be added directly to the P&L calculation.


Required permissions

Permission Access
catering_events → view/create/edit/delete Event management
catering_menus → view/create/edit/delete Template menus
catering_menu_items → view/create/edit/delete Catering products
catering_packages → view/create/edit/delete Packages
catering_categories → view/create/edit/delete Categories
catering_allergens / catering_dietary_types Nutritional data
catering_view_costs View costs and P&L margins
estimates → create Generate estimate from event
invoices → create Convert to invoice

Gotchas

Problem Cause Solution
Generate Estimate button does not appear client_id missing (event has only lead_id) Convert the lead to a client and update the event with client_id
Price on estimate is wrong unit_price on item changed after assignment Module takes a snapshot on assignment — use Regenerate Estimate to fetch current prices
Staff not appearing in dropdown No Staff Roles configured Add at least one Staff Role
Ingredient stock does not decrease Correct behavior — stock is reference, not transactional Manually deduct from stock_on_hand after the event
P&L not visible Missing catering_view_costs permission Grant the specific permission to the role
Staff notification not working notify_all_staff() does not actually send email Notify staff manually or use standard CRM notifications

Module references

  • Estimates — estimates generated from events
  • Invoices — invoices generated from events
  • Projects — project optionally linked to event
  • Catering — module documentation
Tip

Build reusable menu packages with fixed per-head pricing before any events are booked — attaching a package to an event takes seconds and ensures consistent pricing across similar events without re-entering menus from scratch.

Note

Allergen flags on menu items must be maintained before building menus. Incomplete allergen data on served items is a compliance risk — build and verify the allergen master list before any catering operation goes live with customer-facing menus.