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: EcommerceQuery/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/0Headers
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
netpricecomesfromandcostpricecomesfromflags for pricing payload.
Step 5 — Filter Base Options (Context)
Method
POST (node)URL
{api_url}/nodeapi/products/fields/filterbasedongeneraldataBody
{
"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
selectsupplieridto 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=150Body
{
"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
selectsupplieridfrom Step 5. - Update internal
selected_option_datafor 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
- Re-run filterbasedlist for the affected field context (may update
selectsupplierid). - 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
- getVat
- Optionally calculateRules with
rulemode=0(rules) and thenrulemode=1(formula) when configured. - getPrice with accumulated context.
13.1 getVat
Method
POST (node)URL
{api_url}/nodeapi/job/get/vat/percentage/orderitemBody
{ "productid": {product_id} }Response
{ data: vatPercentage, taxlist, vatselected, defaultsalestaxlabel }13.2 calculateRules
Method
POST (node)URL
{api_url}/nodeapi/orderitems/calculate/rulesBody
{
"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/priceBody
{
"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=150Body
{ "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, usesvaluenamefor 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.phpHeaders
Content-Type: application/x-www-form-urlencodedBody
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
- When color changes and provides
pricegroupid, component updates pricegroup field to keep pricing consistent. - If a list field returns no ecommerce options, that control is removed to avoid invalid choices.
- Rules may set values programmatically; UI updates without emitting further value changes to avoid loops.
Open this file at /assets/docs/orderform-steps.html when served by your app.