CRM Module¶
Purpose¶
Manages customer relationships, sales orders, and the commercial layer of product data. Owns sales order lifecycle from creation through fulfilment, the orderable product catalog (pricing, descriptions, images), customer information, complaint handling, sales quotations, and Handlowiec-facing workflows.
The module serves two distinct user profiles: the office-based Manager/Admin who manages the business from a desktop, and the field-based Sales Rep (Handlowiec) who works primarily on a smartphone. Mobile-first interface design is a core requirement, not an optional enhancement. The Handlowiec is the primary CRM actor — the module is optimised around their daily workflows: creating ZS in under 3 minutes on a phone, checking stock availability before promising a delivery date, and managing customer relationships.
Actors¶
| Actor | Interaction |
|---|---|
| Admin | Full access including pricing, price lists, customer management, territory configuration |
| Manager (Kierownik) | Sales order overview, customer management |
| Sales Rep (Handlowiec) | Primary CRM actor: customers, sales orders, quotations, complaints, mobile dashboard, view prices |
| Worker (Pracownik) | No access |
| QA Specialist | View and manage complaint corrective actions |
| Accountant (Księgowa) | View sales orders and invoicing status |
Use Cases — Customer Management¶
CRM-UC-01: Manage Customer Base¶
Actor: Admin, Manager, Sales Rep (Handlowiec) Phase: 2
Customer card fields: company name, NIP/VAT-EU, address (billing + shipping — multiple shipping addresses allowed), category/segment (free-text tag, e.g., "restaurant", "retail", "wholesale" — used for filtering), territory tag (free-text, used for Handlowiec territory scoping — see BR-CRM-08), notes.
Contact persons: multiple contact persons per customer, each with: name, phone, email, role/title (e.g., "order contact", "accounting", "owner"). Handlowiec uses role to know who to call for orders versus who handles invoice disputes.
Customer notes: free-text timestamped notes per customer (call notes, visit notes, follow-up summaries). Any actor with access to the customer record can add notes. Notes are append-only — not editable after creation.
Follow-up reminder: a single "next follow-up" date field per customer. When the date arrives, the customer appears in the Handlowiec's task list (see CRM-UC-10). Only the assigned Handlowiec (or Admin) can set or clear this date.
Payment status indicator: read-only badge on customer card sourced from the Invoicing module. Values: current / overdue / seriously_overdue. Updated via InvoicePaymentStatusChanged event from Invoicing. Handlowiec sees this before a call so they know whether to raise the topic.
Customer summary stats (on customer card): - Last order date (date of most recent ZS in any non-Cancelled status) - Total order value in the past 12 months (sum of confirmed ZS lines in PLN)
Customer history view: all sales orders (ZS) with values and dates, all shipments (WZ with LOT numbers), all complaints, all quotations (ZO).
Search and filter: by name (partial), NIP (exact), city, segment tag, territory tag, payment status.
Import customers from CSV/Excel (template provided). Export customer list to Excel.
Phase 2 nice-to-have — NIP auto-fill (GUS integration): when Handlowiec types a NIP number into the new-customer form, system calls the GUS (Polish business registry) API and attempts to auto-fill company name, registered address, and VAT status. Auto-fill is a suggestion — the user can override. If the GUS API is unavailable, the form continues to work without auto-fill (graceful degradation).
Business rules: 1. NIP must be unique per tenant — system warns on duplicate but does not block (foreign customers may share VAT-EU format) 2. At least one shipping address required to confirm a sales order 3. Customer cannot be deleted if they have any historical order, shipment, or complaint — can only be marked inactive 4. Customer notes are visible to all actors with customer access, but only the author and Admin can delete a note 5. Follow-up date is visible in CRM-UC-10 (Handlowiec Dashboard) — it does not generate an email; it surfaces in the in-app task list only
Use Cases — Orderable Product Catalog (CRM Item Extension)¶
CRM-UC-02: Manage Product Sales Data¶
Actor: Admin, Manager Phase: 2
For each item in ItemCatalog with type product or resale, CRM owns:
- Selling price (base price in PLN, excl. VAT)
- VAT rate (5% / 8% / 23% — Polish food VAT rates; selection per product)
- Pricing tiers (optional: quantity-based discounts, e.g., >100 units → price × 0.95)
- Product description for customers (rich text, separate from internal item name)
- Product images (up to 10 images, max 10 MB each)
- Orderable flag: true = visible and selectable in ZS; false = hidden from order creation
Business rules:
1. Only Admin can change the base selling price
2. Price change does not retroactively affect already-created ZS documents (ZS snapshots price at creation time)
3. A product can only appear in a ZS if its orderable flag is true AND it is active in ItemCatalog
4. intermediate and ingredient type items are not orderable — they cannot appear in ZS
Use Cases — Sales Orders¶
CRM-UC-03: Create Sales Order (ZS)¶
Actor: Admin, Manager, Sales Rep (Handlowiec) Phase: 2
Sales Order (ZS) fields: customer, required delivery date, shipping address (from customer's saved addresses — selectable from list), line items (product, quantity, agreed price, discount %), order notes (delivery instructions, special requirements), assigned Sales Rep.
Expected delivery date is required. For made-to-order products, system displays an advisory: "standard production lead time: X days" (X is pulled from the product's lead time setting in ItemCatalog or Manufacturing config). Handlowiec sees this before committing to a date with the customer.
Per line item system shows: requested quantity vs available FG stock in Warehouse (live check via query to Warehouse module), displayed as: - Green indicator: stock fully covers requested quantity - Yellow indicator: partial stock available - Red indicator: no stock available
Stock indicators are informational only — they do not trigger stock reservation or production orders. They help Handlowiec set realistic delivery expectations with the customer.
"Save as draft": Handlowiec can save a ZS in Draft status at any point during creation — e.g., start the order at a customer's premises and complete it back in the office. Draft ZSs are visible in the Handlowiec's dashboard (CRM-UC-10).
Mobile-optimised 3-screen creation flow (phone): 1. Screen 1: select customer (search by name or NIP) + set expected delivery date + select delivery address 2. Screen 2: add products — search by name/code or scan EAN barcode; set quantity per line; stock indicator shown per line in real time 3. Screen 3: review summary (customer, lines, total value, delivery date, notes) + confirm or save as draft
ZS statuses: Draft → Confirmed → PartiallyShipped → Shipped → Invoiced | Cancelled
PartiallyShipped: some lines/quantities partially fulfilled; remaining quantity in backorder- Backorder lines appear in new picking list when stock becomes available
Auto-numbered: ZS-YYYY-MM-NNNNN
Business rules:
1. ZS price per line is snapshoted at creation time — base price changes after ZS creation do not affect existing ZS lines
2. System automatically applies the customer's price list at line creation (see CRM-UC-08) — Handlowiec sees the effective price; they cannot override it
3. Discount is applied per line as a percentage; Admin can set maximum allowed discount per product or tenant-wide
4. Only Admin can apply discounts above tenant-defined maximum (requires explicit override)
5. Unshipped lines on a confirmed ZS can be edited (quantity, delivery date) to accommodate stock unavailability or customer negotiation. Shipped lines are immutable.
6. ZS can be cancelled from any status except Shipped or Invoiced
8. ZO-to-ZS conversion (from CRM-UC-09) pre-fills all ZS fields — Handlowiec reviews and confirms
9. Partial shipment allowed — ZS can be partially fulfilled; remaining quantity stays in backorder status until fulfilled or cancelled
CRM-UC-04: Manage Complaints¶
Actor: Admin, Manager, QA Specialist, Sales Rep (Handlowiec) Phase: 2
Create complaint: customer, date, product, LOT number (linked to Traceability), issue description, quantity complained, link to WZ (shipment), "customer communication" field (what was promised to the customer and by when).
Handlowiec complaint creation flow (mobile): Handlowiec receives a complaint from a customer in the field or by phone and creates the record immediately on their phone. The mobile form is optimised for quick entry: customer auto-suggested from Handlowiec's customer list, LOT search available (scan or type), description as free text.
LOT lookup: when Handlowiec enters a LOT number, system queries Traceability for that LOT. If found, the complaint is automatically linked to the LOT record. If not found, LOT field is saved as free text without a traceability link (QA can link it later).
Notifications: Handlowiec who created the complaint receives an in-app notification (and push if mobile-enabled) when the complaint status changes. This allows them to proactively update the customer without having to check the system manually.
Complaint lifecycle: New → InProgress → Resolved → Closed
Corrective action: description, responsible person, deadline, outcome.
Complaint history per customer and per product/LOT. Complaint report for period: count, value, products, customers — export to Excel.
Business rules:
1. LOT field is optional on complaint creation (some customers report issues without LOT info)
2. If LOT is provided and matched in Traceability, complaint is linked — QA can navigate to Traceability's recall screen via a frontend deeplink (LOT pre-filled) to initiate a recall
3. Complaint cannot be closed without a corrective action description
4. "Customer communication" field is required before moving complaint to Resolved — what was communicated to the customer and by when
Use Cases — Price Lists¶
CRM-UC-08: Price List Management¶
Actor: Admin, Sales Rep (Handlowiec — view only) Phase: 2
Tenant-level base price list: all products with orderable = true have a base selling price defined in CRMItemExtension (managed via CRM-UC-02). The base price list is the fallback for all customers who do not have a customer-specific override.
Customer-specific price lists: Admin can create a price override for a specific customer on a specific product. Example: key account "Kowalski sp. z o.o." gets Wheat Bread at 3.20 PLN instead of the base 3.50 PLN. Multiple product overrides can exist per customer.
Discount tiers (quantity-based automatic discounts): defined at tenant level or per product. Example: >100 units → -5%, >500 units → -8%. When Handlowiec adds a line to ZS, if the quantity crosses a tier threshold, the tier discount is applied automatically. Tiers are additive to customer-specific price (i.e., the customer-specific price is the basis for tier calculation, not the base price).
Price list validity: each price list entry (base or customer-specific) can have an optional valid_from / valid_to date range. This enables seasonal pricing and promotional periods. An entry without dates is always active.
Handlowiec view: Handlowiec can view the effective price for any product for any of their customers (the price that will be applied on the next ZS). They cannot edit price lists — this is read-only for Handlowiec.
ZS integration: when a line is added to a ZS, the system resolves the effective price in this order: 1. Customer-specific price for this product (if active and within validity dates) 2. Base price (fallback) Then applies any applicable quantity discount tier on top. Handlowiec sees the resolved effective price on the ZS line.
Business rules:
1. Only Admin can create, edit, or delete price list entries
2. Customer-specific price takes precedence over base price — if both exist and are active, customer-specific wins
3. Expired price list entries (past valid_to date) are not applied — base price fallback is used
4. Price resolved at ZS line creation is snapshotted — subsequent price list changes do not affect existing ZS lines
5. Discount tiers cannot result in a negative price — system enforces a minimum price floor of 0.01 PLN
Use Cases — Sales Quotations¶
CRM-UC-09: Sales Quotation (Oferta / ZO)¶
Actor: Sales Rep (Handlowiec), Admin, Manager Phase: 2
Purpose: a ZO is a non-binding price offer sent to a customer before a confirmed order. Handlowiec creates a ZO during or after a sales conversation; if the customer accepts, the ZO is converted to a ZS with one click.
ZO fields: customer, quotation date, validity date, products (lines: product, quantity, effective price, discount %), delivery terms (free text), notes, assigned Sales Rep.
ZO statuses: Draft → Sent → Accepted → Expired | Rejected
Status transitions:
- Draft → Sent: Handlowiec marks it as sent (either after sending PDF to customer or verbally communicating it)
- Sent → Accepted: Handlowiec marks as accepted when customer confirms
- Sent → Rejected: Handlowiec marks as rejected
- Any status → Expired: automatic transition when today's date passes valid_to date and ZO has not been Accepted or Rejected
ZO to ZS conversion: when a ZO is in Accepted status, Handlowiec clicks "Convert to Order" — system creates a new ZS pre-filled with all ZO data (customer, lines, prices, delivery terms). Handlowiec reviews the pre-filled ZS and confirms. This satisfies the <3-minute ZS creation goal for prepared quotations.
ZO PDF generation: system generates a professional PDF document including: company logo (from tenant settings), customer name and address, quotation number (auto-numbered: ZO-YYYY-MM-NNNNN), products table (product name, quantity, unit price, line total), total value (excl. and incl. VAT), validity date, payment terms, delivery terms. PDF can be downloaded or shared directly from the mobile interface.
ZO history per customer: all past quotations visible on the customer card with status. Win/loss rate is calculated per Handlowiec (count of Accepted / count of Sent+Accepted+Rejected) — visible on the Handlowiec Dashboard.
Business rules:
1. ZO is not a binding document — it does not trigger stock reservation or ZP creation; only ZS confirmation does (BR-CRM-10)
2. An Expired ZO cannot be converted to a ZS without Admin override — Admin can reactivate an expired ZO by extending its validity date
3. Prices on ZO are resolved at ZO creation time using the same price list logic as ZS (CRM-UC-08 effective price resolution)
4. A ZO converted to ZS retains the prices from the ZO — system does not re-resolve prices at conversion time unless the Handlowiec explicitly triggers a refresh
Use Cases — Handlowiec Dashboard¶
CRM-UC-10: Handlowiec Dashboard and Task List¶
Actor: Sales Rep (Handlowiec) Phase: 2
A mobile-first dashboard displayed as the default landing page for Handlowiec after login. Optimised for quick situational awareness: what needs attention today.
Dashboard sections:
- My orders today — ZSs requiring action today:
DraftZSs created by this Handlowiec (reminder to confirm or discard)- ZSs with
expected_delivery_date = todaythat are not yetShipped -
ZSs that are past their
expected_delivery_date(overdue — shown with red indicator) -
Follow-up reminders — customers where "next follow-up" date is today or overdue (past today). Tapping a customer opens their customer card. Handlowiec can mark the follow-up as done (clears the date) or reschedule (sets a new date).
-
Order pipeline — count and total value of Handlowiec's ZSs grouped by status:
Draft/Confirmed/PartiallyShipped/Shipped. Tapping a status opens the filtered ZS list. -
Overdue orders — ZSs past
expected_delivery_datenot yet inShippedor later status. Shown with customer name, product count, days overdue.
Visibility rules: - Handlowiec sees only their own ZSs and customers by default (scoped to assigned territory or "all" depending on tenant configuration — see BR-CRM-08) - Admin and Manager see all ZSs and can filter by assigned Sales Rep - Handlowiec cannot change the visibility scope themselves
Business rules: 1. Dashboard data is near-real-time — refreshed on page load and on push notification receipt; no manual refresh button required on mobile 2. The dashboard does not replace the full ZS list view — Handlowiec can navigate to the full list from the dashboard
Business Rules¶
| # | Rule |
|---|---|
| BR-CRM-01 | ZS price per line is snapshoted at creation time. Base price changes do not affect existing ZS documents. |
| BR-CRM-02 | Only product and resale type items can appear in ZS line items. |
| BR-CRM-03 | Unshipped lines on a confirmed ZS can be edited (quantity, delivery date). Shipped lines are immutable. |
| BR-CRM-04 | Discount above tenant maximum requires Admin override — logged in audit trail. |
| BR-CRM-05 | Sales Rep (Handlowiec) can view and manage only customers and orders within their assigned territory, or all customers if territory is not configured. Territory is a free-text tag on the customer record — it is not a complex permission system. The Admin configures per tenant whether territory scoping is enabled. |
| BR-CRM-06 | Mobile interface must support ZS creation in under 3 minutes for a standard 5-line order. The 3-screen mobile flow in CRM-UC-03 is the primary mechanism to achieve this. |
| BR-CRM-07 | ZO (quotation) is not a binding document. It does not trigger stock reservation or ZP creation. |
| BR-CRM-08 | Stock levels shown during ZS creation are informational only — CRM does not trigger stock reservation or production order creation. |
Out of Scope¶
- Item identity (code, name, type, UOM) → owned by ItemCatalog module
- Production order management → owned by Manufacturing module
- Stock movements and LOT creation → owned by Warehouse module
- Batch genealogy and recall management → owned by Traceability module
- Invoice generation and payment tracking → owned by Invoicing module (CRM reads payment status via event, does not write to Invoicing)
- Courier label printing → Courier integration hands off to Warehouse for label generation (WZ document)
- HACCP / quality compliance → future Quality module (Phase 3)
- Push notification infrastructure → owned by a cross-cutting Notification service; CRM publishes events, it does not send push notifications directly
Open Questions¶
| # | Question | Impact |
|---|---|---|
| OQ-CRM-01 | Resolved. Auto-ZP trigger removed from CRM scope entirely. CRM shows stock levels for informational purposes only. Production orders are created manually in Manufacturing. | Scope — closed |
| OQ-CRM-02 | Resolved. Partial shipment allowed. PartiallyShipped status added. Backorder lines fulfilled when stock available. | Scope — closed |
| OQ-CRM-03 | Resolved. API and webhooks removed from CRM scope. | Scope — closed |
| OQ-CRM-04 | Resolved. Current pricing spec (quantity tiers + customer-specific overrides) is sufficient. No dedicated loyalty tier model needed. | Scope — closed |
| OQ-CRM-05 | Resolved. Manual recall notification only. No auto-email from CRM. Complaint links to Traceability recall screen via frontend deeplink. | Scope — closed |
| OQ-CRM-06 | Resolved. Payment status badge on customer card is sufficient. No push notification for overdue invoices. Badge sourced from Invoicing module via event. | Scope — closed |
| OQ-CRM-07 | Resolved. Sales quotations (ZO) stay in Phase 2. Handlowiec is a Phase 2 user. | Phase — closed |