Project

General

Profile

Support #10628 ยป implementation_plan.md

Yalavarthi Thriveni, 08/31/2026 09:13 AM

 

Implementation Plan: Request Update to Quote Auto-Recalculation

This plan establishes a dual-execution pure calculation engine that synchronizes Request updates with linked Quotations headlessly in the backend without requiring UI interaction, while keeping real-time interactive calculations 100% client-side in the frontend (preventing chatty API calls on discount/value changes).


1. System Overview & Realtime Schema Values

Current Flow vs Target Architecture

sequenceDiagram
    autonumber
    participant UI as Frontend Quote / Request UI
    participant RS as Request Service (Backend)
    participant CE as Quote Calculation Engine
    participant QS as Quotation Service (Backend)
    participant DB as MongoDB Database

    Note over UI,CE: Flow 1: Interactive Frontend Quote Creation (0ms Latency)
    UI->>CE: Local in-memory calculation on every keystroke (mathjs)
    UI->>QS: Save Quote with Commercial Snapshot (summaryType, discount, tax, deposit)
    QS->>DB: Persist Quotation & CostBreakdowns

    Note over RS,DB: Flow 2: Headless Request Update (No UI Interaction)
    UI->>RS: PUT /api/v2/request/updaterequest/:requestId (Area/Products/Labor changed)
    RS->>DB: Update Request document
    RS->>QS: Trigger syncLinkedQuotations(updatedRequest)
    QS->>DB: Find active/draft Quotation for requestId
    QS->>CE: Recalculate costBreakdowns, subTotal, tax, discount & totals using Quote's saved commercial rules
    QS->>DB: Save updated Quotation & sync Invoice deposit if applicable
    RS-->>UI: Return updated Request & sync summary

Real-Time Database Schemas Involved

1. RequestSchema (models/MVP@2/request-model.js)

  • requestId: Unique identifier (e.g., R_0001).
  • selectedService[]:
    • serviceId: ObjectId referencing Service.
    • unitType: "area" | "quantity" | "time" | "none".
    • areaInputType: "dimension" | "manual".
    • length, width, area, units: Dimensional measurements.
    • marginType: "percentage" | "amount".
    • marginValue: Number.
    • selectedProductOptions[]:
    • productId: String.
    • productData: Object (contains price, name, etc.).
    • fields: Map/Object of formula parameters (e.g. { "area": "500", "depth": "3" }).
    • selectedEquipment[]:
    • equipmentId: String / ObjectId.
    • equipmentData: Object (cost, rate, hours, quantity).
    • selectedLabor[]:
    • laborId: ObjectId.
    • laborData: Object (payment/rate, hours, quantity).
    • siteVisitStatus: "Completed" | "Scheduled" | "InProgress" | "NoSiteVisit" | "NotScheduled".

2. QuotationSchema (models/EvergreenQuotation/EverGreenQuotation.js)

  • requestId: String linking to Request.
  • quotationNumber: String (e.g., Q_0001).
  • status: "drafted" | "waiting for approval" | "created" | "accepted" | "inProgress" | "completed".
  • Commercial Policy Rules:
    • IsBaseprice: Boolean (true = Base Price Summary, false = Actual Total Summary).
    • discountType: "percentage" | "amount".
    • discountAmount: Number.
    • excludeTax: Boolean (true = tax exempt / excluded, false = standard tax).
    • depositType: "percentage" | "amount".
    • depositPercentage: Number.
    • requiredDeposit: Number.
    • miscellaneousCosts[]: [{ service: ObjectId, cost: Number, remarks: String }].
  • Dynamic Totals:
    • subTotal, actualSubTotal: Number.
    • taxAmount, actualTaxAmount: Number.
    • total, actualTotal: Number.
    • costBreakdowns[]: Array of costBreakdownSchema with per-service products, labor, equipment, and margin rollups.

2. User Review Required

[!IMPORTANT]
Zero Keystroke API Calls Maintained
In the frontend (useNewQuotation.tsx and NewQuotationPage.tsx), all real-time calculations on discount changes, tax toggles, and radio selections remain 100% local in-memory execution via mathjs. No API requests will be triggered on input typing or discount adjustment.

[!WARNING]
Quotation State Locking Policy on Request Update
When a Request is updated:

  1. Draft/Pending Quotes (drafted, created, waiting for approval): Will be automatically recalculated and saved.
  2. Approved Quotes (accepted, completed): Will NOT be automatically altered to protect legal/billing contract integrity; instead, an audit record will log that the underlying Request changed.

3. Proposed Changes

Component 1: Shared Pure Calculation Engine

[NEW] [quoteCalculationEngine.js](file:///c:/thriveni/folder%20f/POS/EGF_POS/evergreen_pos_be/src/utils/quoteCalculationEngine.js)

A pure mathematical calculation module in Node.js (utilizing mathjs) that mirrors the frontend logic:

  • calculateProductQuantityAndCost(service, productOption, productCatalog): Evaluates formula using mathjs against fields (e.g. (area * depth) / 324).
  • calculateResourceCosts(service, laborMap, assetMap): Calculates labor and equipment totals.
  • getServiceMarginAmount(service, subtotal): Computes percentage or flat amount margin.
  • calculateQuotationFromRequest(request, existingQuotation, catalogData):
    • Computes basePriceSubtotal and actualTotalSubtotal.
    • Determines active subtotal based on existingQuotation.IsBaseprice.
    • Applies discountType and discount rate.
    • Applies taxPercentage (or $0$ if excludeTax === true).
    • Computes finalTotal, requiredDeposit, and updates costBreakdowns[].

Component 2: Backend Request & Quotation Services

[MODIFY] [request.service.js](file:///c:/thriveni/folder%20f/POS/EGF_POS/evergreen_pos_be/src/services/nursery/request.service.js)

  • In exports.updateRequest:
    • After Request.findByIdAndUpdate saves the updated request, add a hook call to quotationService.syncQuotationsForRequest(dbName, updatedRequest, id).
    • Ensures changes to area, dimensions, selected products, labor, and equipment immediately cascade to linked non-finalized quotations.

[MODIFY] [quotation.service.js](file:///c:/thriveni/folder%20f/POS/EGF_POS/evergreen_pos_be/src/services/quotation.service.js)

  • Implement exports.syncQuotationsForRequest(dbName, requestDoc, userId):
    • Finds all non-finalized quotations where requestId === requestDoc.requestId and isDeleted !== true.
    • Resolves required Service, Product, Asset, and Labor catalogs for the new service items.
    • Calls calculateQuotationFromRequest(...).
    • Writes new totals (subTotal, taxAmount, total, actualTotal, costBreakdowns) to the quotation.
    • Appends an audit entry in actionHistory stating: "Quotation automatically recalculated due to Request update".
    • If linked invoice exists (invoiceId), calls persistInvoiceWithDepositSync.

Component 3: Frontend Quotation Persistence & Local Engine Alignment

[MODIFY] [NewQuotationPage.tsx](file:///c:/thriveni/folder%20f/POS/EGF_POS/evergreen_pos_fe/src/pages/Quotes/createQuote/NewQuotationPage.tsx)

  • Ensure the payload sent to /Quotation/create-quotation or /Quotation/update-quotation explicitly saves the full commercial snapshot:
    • IsBaseprice: summaryType === 'basePrice'
    • discountType: "percentage" | "amount"
    • discount: numeric value
    • excludeTax: boolean
    • depositType: "percentage" | "amount"
    • depositPercentage: numeric value
    • miscellaneousCosts: array of service misc items
  • Keep the in-memory mathjs calculation reactive in React state with zero latency.

4. Verification Plan

Automated / Manual Verification

  1. Formula & Calculation Verification:
    • Create a Request with Service unit area = 500 sqft, Product with formula (area * depth) / 324 with depth = 3.
    • Create a Quote with 10% discount and 8% tax.
  2. Headless Request Update Test:
    • Update the Request area from 500 to 1000 sqft via PUT /api/v2/request/updaterequest/:requestId.
    • Fetch the Quotation via GET /api/v1/Quotation/getQuotationById/:id without touching the UI.
    • Verify that:
      • Product quantity doubled in costBreakdowns[0].products[0].quantity.
      • subTotal, discountAmount, taxAmount, and total are accurately updated.
      • actionHistory contains the automatic recalculation entry.
  3. Frontend UI Interaction Test:
    • Open the Quote creation page and type discount values (1, 5, 10, 15).
    • Monitor Network DevTools tab: Ensure 0 network API requests are fired while typing.
    (1-1/1)