Orderform Step-by-Step Flow

From first load to Add to Cart. Source: src/app/orderform/orderform.component.ts, src/app/services/api.service.ts

How to Read

Each step shows the exact API method used, URL pattern, headers, request payload, and the expected response shape, followed by how the component uses it and what it triggers next. Replace variables like {api_url}, {product_id}, {recipeId} with real values from runtime.

Step 1 — Resolve Context

Purpose
Resolve api_url, api_key, api_name, site from environment and route params (path-based, query, or token exchange).
Notes
No network call unless token exchange is used (WP endpoint /wp-json/blindmatrix/v1/get_visualizer_data?token={token}), which returns the same fields.
Next
Step 2.

Step 2 — Get Product Data

Method
GET (standard)
URL
{api_url}/api/public/api/getproductsdetails/{product_id}
Headers
Accept: application/json, Content-Type: application/json, companyname: {api_name}, Ecommercekey: {api_key}, platform: Ecommerce
Query/Body
None
Response
{ result: { EcomProductlist: [...], ShutterProductDetails: [...] } }

Used For

  • Set productname, recipeid, category, images (frame/background).
  • Initialize 2D/3D visualizer with default images/models.

Example Response Fragment

{
  "result": {
    "EcomProductlist": [{
      "label": "Roller Blinds",
      "recipeid": 321,
      "pi_backgroundimage": "[\"/path/bg1.png\",\"/path/bg2.png\"]",
      "pi_frameimage": "[\"/path/frame1.png\"]",
      "pi_deafultimage": "{\"defaultimage\":{\"backgrounddefault\":\"bg1.png\",\"framedefault\":\"frame1.png\"}}",
      "pi_category": "4"
    }],
    "ShutterProductDetails": []
  }
}

Step 3 — Setup Visualizer (2D/3D)

Purpose
Initialize ThreeService with canvas/container; select model by productname keywords; or 2D mode with frame + background.
Network
No API request; loads static assets like assets/rollerblinds.glb and image URLs from Step 2.
Next
Step 4.

Step 4 — Get Product Parameters (Field Schema)

Method
GET (node)
URL
{api_url}/nodeapi/products/fields/withdefault/list/{recipeId}/1/0
Headers
Same as Step 2.
Response
[ { data: ProductField[], netpricecomesfrom, costpricecomesfrom } ]

Used For

  • Build reactive form controls per field.
  • Identify special fields: unit (34), width (7/8/11/31), drop (9/10/12/32), qty (14), supplier (17), pricegroup (13).
  • Store netpricecomesfrom and costpricecomesfrom flags for pricing payload.

Step 5 — Filter Base Options (Context)

Method
POST (node)
URL
{api_url}/nodeapi/products/fields/filterbasedongeneraldata
Body
{
  "fieldtypeid": {fabricFieldType},
  "productid": {product_id},
  "pricegroup": {pricegroup},
  "colorid": {colorid},
  "fabricid": {fabricid},
  "unittype": {unittype},
  "customertype": "4",
  ...
}
Response
[ { data: { optionarray: { [fieldid]: ids }, coloridsarray, selectsupplierid, ... } } ]

Used For

  • Derive filter IDs used in Step 6 (getOptionlist).
  • May provide selectsupplierid to auto-set supplier.

Step 6 — Load Option Lists

Method
POST (node)
URL
{api_url}/nodeapi/products/get/fabric/options/list/{recipeId}/{level}/0/{fieldtype}/{fabriccolor}/{fieldid}/?page=1&perpage=150
Body
{
  "customertype": 4,
  "filterids": [/* from Step 5: data.optionarray or coloridsarray */],
  "productionformulalist": [],
  "productid": {product_id}
}
Response
[ { data: [ { optionsvalue: [ { optionid, optionname, optionimage, fieldoptionlinkid, pricegroupid, availableForEcommerce } ] } ] } ]

Used For

  • Populate select-type fields: 3 (list), 5/20/21 (material/color families).
  • Filter out options where availableForEcommerce === 0.
  • Set initial defaults (including from route for fabric/color IDs).

Step 7 — Set Special Field Defaults

  • qty (14) → 1
  • unit (34) / pricegroup (13) / supplier (17) from options or defaults; may use selectsupplierid from Step 5.
  • Update internal selected_option_data for pricing.
  • Next: Step 8.

Step 8 — Get Min/Max Bounds

Method
POST (node)
URL
{api_url}/nodeapi/orderitems/check/widthdrop/minandmax/
Body
{
  "width": "0",
  "drop": "0",
  "unittype": {unittype},
  "mode": "both",
  "pricegroup": {pricegroup},
  "colorid": "{coloridOrEmpty}",
  "fieldtypeid": {fabricFieldType},
  "productid": {product_id}
}
Response
{ data: { widthminmax: {min,max}, dropminmax: {min,max} } }

Used For

  • Set Angular validators for width/drop fields; rerun on color/unit/pricegroup changes.

Step 9 — Get Recipe List (Ancillary)

Method
GET (node)
URL
{api_url}/nodeapi/products/recipe/list/{product_id}
Used For
Ancillary info; not required for pricing/cart.

Step 10 — Get Product Fraction List (Ancillary)

Method
GET (standard)
URL
{api_url}/api/public/api/appSetup/fractionlist/{product_id}
Used For
General fraction metadata; unit-specific fractions in Step 11.

Step 11 — Unit Change → Get Fraction Data

Method
GET (standard)
URL
{api_url}/api/public/api/appSetup/fractionlist/{product_id}/-1/{unittype}
Response
{ result: { inchfractionselected, inchfraction:[{ id, name, decimalvalue }] } }
Used For
Show/hide fraction selects and map fraction display text for width/drop.

Step 12 — Option Change → Filter + Subfields

  1. Re-run filterbasedlist for the affected field context (may update selectsupplierid).
  2. If selected option has subdatacount > 0, call sublist to fetch nested fields:
Method
POST (node)
URL
{api_url}/nodeapi/products/fields/list/0/{recipeId}/{level}/{fieldtype}/{masterparentfieldid}
Body
{
  "supplierid": {supplierid},
  "productid": {product_id},
  "optionid": [{selectedvalue}],
  "subfieldoptionlinkid": [{optionlinkid}],
  "productionformulalist": [],
  "orderitemselectedvalues": { "{masterparentfieldid}": [{selectedvalue}] }
}
Response
[ { data: ProductField[] } ]

For each nested field that is list/material: fetch its options using getOptionlist (Step 6) with updated level.

Update visualizer textures if selections carry optionimage (e.g., color image).

Step 13 — Debounced Price Calculation

  1. getVat
  2. Optionally calculateRules with rulemode=0 (rules) and then rulemode=1 (formula) when configured.
  3. getPrice with accumulated context.

13.1 getVat

Method
POST (node)
URL
{api_url}/nodeapi/job/get/vat/percentage/orderitem
Body
{ "productid": {product_id} }
Response
{ data: vatPercentage, taxlist, vatselected, defaultsalestaxlabel }

13.2 calculateRules

Method
POST (node)
URL
{api_url}/nodeapi/orderitems/calculate/rules
Body
{
  "vatpercentage": {vat},
  "recipeid": {recipeId},
  "productid": {product_id},
  "orderitemdata": [ /* from form via orderitemdata(true) */ ],
  "supplierid": {supplierid},
  "mode": "pricetableprice" | "",
  "width": {width},
  "drop": {drop},
  "pricegroup": [{pricegroup}],
  "optiondata": [ /* selected_option_data */ ],
  "unittype": {unittype},
  "rulemode": 0 | 1,
  "widthfieldtypeid": {widthFieldTypeId},
  "dropfieldtypeid": {dropFieldTypeId},
  "fabricid": {fabricid},
  "colorid": {colorid}
}
Response
  • ruleresults: array of field updates (set option or text values).
  • When rulemode=1: productionmaterialcostprice, productionmaterialnetprice, productionmaterialnetpricewithdiscount.

13.3 getPrice

Method
POST (node)
URL
{api_url}/nodeapi/orderitems/calculate/option/price
Body
{
  "productid": {product_id},
  "supplierid": {supplierid},
  "mode": "pricetableprice" | "",
  "width": {width},
  "drop": {drop},
  "pricegroup": [{pricegroup}],
  "customertype": 4,
  "optiondata": [ /* selected options */ ],
  "unittype": {unittype},
  "orderitemqty": 1,
  "overridetype": 1,
  "vatpercentage": {vat},
  "rulescostpricecomesfrom": "{costpricecomesfrom}",
  "rulesnetpricecomesfrom": "{netpricecomesfrom}",
  "fabricfieldtype": {fabricFieldType},
  "widthfieldtypeid": {widthFieldTypeId},
  "dropfieldtypeid": {dropFieldTypeId},
  "colorid": {colorid},
  "fabricid": {fabricid},
  "productionmaterialcostprice": {fromFormula?},
  "productionmaterialnetprice": {fromFormula?},
  "productionmaterialnetpricewithdiscount": {fromFormula?}
}
Response
{ fullpriceobject: { grossprice, ... }, currencysymbol }

Component shows {currencysymbol}{grossprice.toFixed(2)} and stores pricedata = fullpriceobject.

Step 14 — Related Products (Optional)

Method
POST (standard)
URL
{api_url}/api/public/api/fabriclistview/{category_id}/{product_id}/?page=1&perpage=150
Body
{ "related_fabric": {fabricidOrColorid}, "colorid": {colorid}, "productid": {product_id} }
Response
{ result: [...] }

Step 15 — Build Order Payloads

  • orderitemdata(isForRulesCalculation): flattens current fields into array with { id, labelname, value, valueid, type, optionid, optionvalue, optionquantity, ... }. For rules-calculation version, uses valuename for special types (34,17,13) and strips dimensions for free sample when requested.
  • selected_option_data: array of { optionvalue, fieldtypeid, optionqty, fieldoptionlinkid, fieldid } built as user selects options; used by pricing and rule endpoints.

Step 16 — Add to Cart

Method
POST (form-urlencoded)
URL
{site}/wp-content/plugins/blindmatrix-v4-hub/api.php
Headers
Content-Type: application/x-www-form-urlencoded
Body
action=add_to_cart&
product_id={cart_productid}&
form_data={JSON.stringify(orderitemdata(false))}&
cart_product_name={title}&
pricedata={JSON.stringify(fullpriceobject)}&
vatpercentage={vat}&
vatname={vatname}&
currenturl={window.location.href}&
product_name={productname}&
category_id={fabricFieldType}&
visualizer_image={dataUrlOrUrl}
Response
{ success: boolean, message? } → on success, navigate to {site}/cart.

Headers (All JSON APIs)

{
  "Accept": "application/json",
  "Content-Type": "application/json",
  "companyname": "{api_name}",
  "platform": "Ecommerce",
  "Ecommercekey": "{api_key}",
  "activity": "{ \"ipaddress\": \"\", \"location\": \"\", \"devicenameversion\": \"\", \"browsernameversion\": \"\" }"
}

End-to-End Diagram (Short)

Load → getProductData → setupVisualizer
     → getProductParameters
     → (filterbasedlist → getOptionlist)*
     → getminandmax
     → getRecipeList/getFractionList

On change: filterbasedlist → (sublist → getOptionlist)* → textures
           getminandmax (dims bounds)
           getFractionData (unit==inches)
           getVat → [calculateRules] → getPrice

Submit: addToCart → redirect /cart
    

Notes & Tips

Open this file at /assets/docs/orderform-steps.html when served by your app.