Designed for seamless movement and everyday technical utility, the new Colourblock Tech Pant in Navy combines high-performance functionality with a sleek, active aesthetic. Featuring a self-fabric waistband fitted with an adjustable plastic buckle closure, it delivers a secure, personalised fit built for active wear. Deep slanted side pockets provide quick-access storage, while a dedicated cargo pocket equipped with an auto-lock zip puller keeps your essentials locked down on the go. Highlighting its technical design, the cargo pocket is stamped with a crisp CLSR tech transfer print, complemented by a contrast panel across the rear yoke and sharp cut-and-sew paneling down the back legs. Finished with a signature Closure mountain logo print on the rear, these pants seamlessly bridge the gap between rugged outdoor performance and modern style.
DATALEADR — COMPLETE JOURNEY + PROFIT CODE
Journey version 3.4 / Profit version 1.0
This file contains all the code. There are no omitted functions.
The two parts run in different Shopify locations. Do not paste this entire
file into theme.liquid or the Customer Events pixel editor.
PART 1: THEME
Replace the existing DataLeadr/mobile-close code with the full script block
in Part 1, before the theme's closing
Details
Description
Size & Fit
Care & Material
Details
Self fabric waistband
Plastic buckle fastening on waistband
Slanted pockets
Cargo pocket with auto lock zip puller
CLSR tech transfer print on cargo pant
Contrast panel at rear yoke
Cut and sew panel at back leg
Rear closure mountain logo transfer print
Description
Designed for seamless movement and everyday technical utility, the new Colourblock Tech Pant in Navy combines high-performance functionality with a sleek, active aesthetic. Featuring a self-fabric waistband fitted with an adjustable plastic buckle closure, it delivers a secure, personalised fit built for active wear. Deep slanted side pockets provide quick-access storage, while a dedicated cargo pocket equipped with an auto-lock zip puller keeps your essentials locked down on the go. Highlighting its technical design, the cargo pocket is stamped with a crisp CLSR tech transfer print, complemented by a contrast panel across the rear yoke and sharp cut-and-sew paneling down the back legs. Finished with a signature Closure mountain logo print on the rear, these pants seamlessly bridge the gap between rugged outdoor performance and modern style.
Size & Fit
Model is wearing: Size Medium
Model's height: 6ft
Care & Material
Machine wash at 30°C.
Poly Bi-Stretch
95% polyester 5% elastane
tag. Install once.
If DataLeadr 3.4 is already installed, keep it and proceed to Part 2.
PART 2: SHOPIFY FLOW
Create the profit workflow using the steps in Part 2. Paste its Input, Output,
Code and mutation-input blocks into their respective Flow fields.
This is needed to read the private Shopify SKU costs and update order details.
The profit calculation uses Shopify costs x quantities and actual order tax.
Estimated delivery expense = the final customer delivery charge, or GBP 4.99
for free delivery. Missing costs produce a review status, not a guessed profit.
Results appear as dl_profit_ fields in Additional details after a successful run.
The profit figures are payment-time snapshots. Payment/fulfilment fees,
packaging, advertising and later refunds/returns are not included.
Costs and policy are saved on the order so later SKU/rate changes do not
recalculate that snapshot. The theme tracker remains independent.
Validation: the supplied code previously passed 49 journey checks and 50 profit
checks using local simulations. The packaged source is unchanged and checked
against those source files. This has not been installed or tested in the shop.
PART 1 — COMPLETE THEME SCRIPT
Copy only between BEGIN and END.
BEGIN THEME SCRIPT
END THEME SCRIPT
PART 2 — SHOPIFY FLOW PROFIT WORKFLOW
1. Apps > Shopify Flow > Create workflow.
Name: DataLeadr — profit at payment
Trigger: Order paid
2. Add a Log output action. In it, choose Add a variable > order > metafield.
Use an unstructured metafield:
Namespace: dataleadr_finance
Key: payment_snapshot
Use the variable/alias name dataleadrProfitSnapshot and select its value.
If Flow assigns a different name, replace dataleadrProfitSnapshot with
that name in the input query, code and log reference below.
Leave the actual namespace and key unchanged.
This registers the metafield as available data for the next action.
Log output:
DataLeadr snapshot already present:
no
3. Add Run code. Replace its three editor fields with the corresponding
COMPLETE blocks below: Input, Output, Code.
4. Add a condition: Run code > shouldWrite equals true.
5. On the TRUE branch, add Send Admin API request.
Select mutation: orderUpdate
Paste the Mutation inputs block below into Mutation inputs.
Use the variable picker to insert Run code > mutationInputs.
Do not add quotes or a json filter; it is already serialized JSON.
6. Add Log output after the API action, and on the FALSE branch:
Use the exact variable name inserted by the picker if it differs.
7. Validate the input fields and cost access in Flow. In a test workflow,
set allowTestOrders: true in the code and use a paid test order.
Check both charged and free shipping, COGS, tax and existing journey fields.
Confirm the API action succeeded and the snapshot metafield was saved.
For production keep allowTestOrders: false, then enable the WORKFLOW.
No workflow has been activated by creating this file.
The code runs after full payment, not just authorisation. It needs permission
to read product costs. The companion detailed setup guide covers errors,
unsupported cases, attribute-write concurrency and future rate changes.
INPUT — copy only the following GraphQL block:
BEGIN FLOW INPUT
{
order {
id
updatedAt
currencyCode
fullyPaid
cancelledAt
test
taxesIncluded
estimatedTaxes
requiresShipping
currentSubtotalLineItemsQuantity
currentSubtotalPriceSet { shopMoney { amount currencyCode } }
currentShippingPriceSet { shopMoney { amount currencyCode } }
currentTotalPriceSet { shopMoney { amount currencyCode } }
currentTotalTaxSet { shopMoney { amount currencyCode } }
currentTotalDutiesSet { shopMoney { amount currencyCode } }
currentTotalAdditionalFeesSet { shopMoney { amount currencyCode } }
totalRefundedSet { shopMoney { amount currencyCode } }
totalTipReceivedSet { shopMoney { amount currencyCode } }
refunds { id }
dataleadrProfitSnapshot { value }
customAttributes { key value }
lineItems {
id
sku
currentQuantity
isGiftCard
variant {
id
inventoryItem {
unitCost { amount currencyCode }
}
}
}
shippingLines {
isRemoved
currentDiscountedPriceSet { shopMoney { amount currencyCode } }
taxLines { priceSet { shopMoney { amount currencyCode } } }
}
fulfillmentOrders {
status
deliveryMethod { methodType }
}
}
}
END FLOW INPUT
OUTPUT — copy only the following schema:
BEGIN FLOW OUTPUT
type Output {
shouldWrite: Boolean!
message: String!
mutationInputs: String!
}
END FLOW OUTPUT
CODE — copy only the following JavaScript:
BEGIN FLOW CODE
/*
* DataLeadr profit 1.0 — Shopify Flow "Run code" action.
* Use the supplied Input, Output and installation instructions.
* This is NOT theme code or a Customer Events pixel.
*
* Saves a payment-time estimate, not a live post-refund profit balance.
* All amounts use GBP shop currency. COGS is used as stored, with no
* invented input VAT adjustment. Customer shipping VAT comes from Shopify.
*/
const POLICY = Object.freeze({
version: "profit-1.0",
shippingVersion: "customer-charge-or-4.99-v1",
currency: "GBP",
freeDeliveryCostMinor: 499,
allowTestOrders: false
});
const PREFIX = "dl_profit_";
const SNAPSHOT_NAMESPACE = "dataleadr_finance";
const SNAPSHOT_KEY = "payment_snapshot";
const BASIS = "Payment snapshot; does not update after later edits, returns or refunds";
const EXCLUSIONS = "Payment fees, packaging, fulfilment fees, advertising and overheads";
function check(condition, message) {
if (!condition) throw new Error(message);
}
function list(value, label) {
check(Array.isArray(value), "Missing " + label);
return value;
}
// Fixed-point parsing avoids floating-point money arithmetic.
// Unit costs may have up to six decimal places; order totals must be pence.
function scaledDecimal(value, precision, label) {
const text = typeof value === "number" && Number.isFinite(value)
? String(value)
: (typeof value === "string" ? value.trim() : "");
const match = /^(\d+)(?:\.(\d+))?$/.exec(text);
check(match, "Missing or invalid amount: " + label);
const fraction = match[2] || "";
check(!/[1-9]/.test(fraction.slice(precision)),
"Unexpected decimal precision: " + label);
const result = Number(match[1]) * (10 ** precision)
+ Number(fraction.slice(0, precision).padEnd(precision, "0"));
check(Number.isSafeInteger(result), "Amount too large: " + label);
return result;
}
function money(value, label, precision = 2) {
check(value && value.currencyCode === POLICY.currency,
"Missing or non-GBP currency: " + label);
return scaledDecimal(value.amount, precision, label);
}
function bag(value, label) {
return money(value && value.shopMoney, label);
}
function optionalBag(value, label) {
check(value !== undefined, "Missing " + label);
return value === null ? 0 : bag(value, label);
}
function add(a, b) {
const sum = a + b;
check(Number.isSafeInteger(sum), "Money total exceeds safe precision");
return sum;
}
function format(minor) {
check(Number.isSafeInteger(minor), "Invalid calculated amount");
const absolute = Math.abs(minor);
return (minor < 0 ? "-" : "") + Math.floor(absolute / 100)
+ "." + String(absolute % 100).padStart(2, "0");
}
function utf8Size(value) {
let bytes = 0;
for (const char of value) {
const point = char.codePointAt(0);
bytes += point <= 0x7f ? 1 : point <= 0x7ff ? 2 : point <= 0xffff ? 3 : 4;
}
return bytes;
}
function noWrite(message) {
return { shouldWrite: false, message, mutationInputs: "{}" };
}
function prepareWrite(order, previous, fields, message, snapshot = null) {
// orderUpdate replaces the whole attribute list. Preserve every non-profit
// attribute read by this action, including DataLeadr journey and other apps.
const attributes = previous
.filter(item => !item.key.startsWith(PREFIX))
.concat(Object.entries(fields).map(([key, value]) => ({
key: PREFIX + key, value: String(value)
})));
if (attributes.length > 250) {
return noWrite("Too many order attributes; no attributes were changed");
}
const input = { id: order.id, customAttributes: attributes };
if (snapshot !== null) {
input.metafields = [{
namespace: SNAPSHOT_NAMESPACE, key: SNAPSHOT_KEY, type: "json",
value: JSON.stringify(snapshot)
}];
}
const result = {
shouldWrite: true,
message,
mutationInputs: JSON.stringify({ input })
};
// Flow has a 50KB output limit. Include JSON's additional string escaping.
if (utf8Size(JSON.stringify(result)) > 45000) {
return noWrite("Order attributes exceed this workflow's output budget; nothing changed");
}
return result;
}
function shippingEstimate(order, paid) {
check(typeof order.requiresShipping === "boolean", "Missing delivery requirement");
if (!order.requiresShipping) {
check(paid === 0, "Shipping charged on a non-shipping order; review needed");
return { cost: 0, basis: "no_delivery" };
}
const fulfillments = list(order.fulfillmentOrders, "fulfillment orders")
.filter(item => item.status !== "CANCELLED");
check(fulfillments.length > 0, "Delivery method not available yet; retry after routing");
const methods = fulfillments.map(item => item.deliveryMethod && item.deliveryMethod.methodType);
check(methods.every(Boolean), "Delivery method missing; review needed");
const carrier = methods.some(method => method === "SHIPPING" || method === "PICKUP_POINT");
const noDelivery = ["PICK_UP", "RETAIL", "NONE"];
check(methods.every(method => noDelivery.includes(method)
|| method === "SHIPPING" || method === "PICKUP_POINT"),
"Local or unknown delivery method needs a separate cost rule");
if (!carrier) {
check(paid === 0, "Collection charge needs a separate cost rule");
return { cost: 0, basis: "collection_or_no_delivery" };
}
// One estimate per order, not per parcel. Paid is the final customer charge,
// including shipping VAT where applicable, after shipping discounts.
return paid > 0
? { cost: paid, basis: "customer_shipping_charge" }
: { cost: POLICY.freeDeliveryCostMinor, basis: "free_delivery_fallback" };
}
function calculate(order) {
check(order.currencyCode === POLICY.currency, "Only GBP shop currency is configured");
check(!order.cancelledAt, "Cancelled order; a payment snapshot cannot be created");
check(order.fullyPaid === true, "Order is not fully paid");
check(typeof order.test === "boolean", "Missing test-order flag");
check(!order.test || POLICY.allowTestOrders, "Test order skipped by configuration");
check(typeof order.taxesIncluded === "boolean", "Missing tax-inclusive flag");
check(order.estimatedTaxes === false, "Tax amounts are missing or still estimated");
check(list(order.refunds, "refunds").length === 0
&& bag(order.totalRefundedSet, "refunded total") === 0,
"Refund already exists; this workflow does not calculate post-refund profit");
check(optionalBag(order.currentTotalDutiesSet, "duties") === 0
&& optionalBag(order.currentTotalAdditionalFeesSet, "additional fees") === 0
&& bag(order.totalTipReceivedSet, "tips") === 0,
"Duties, additional fees or tips require review");
const total = bag(order.currentTotalPriceSet, "order total");
const subtotal = bag(order.currentSubtotalPriceSet, "product subtotal");
const shippingPrice = bag(order.currentShippingPriceSet, "shipping price");
const tax = bag(order.currentTotalTaxSet, "total tax");
// Discounts are already reflected in these current order totals.
// Fail closed on unusual orders rather than counting unmodelled charges.
check(total === add(add(subtotal, shippingPrice), order.taxesIncluded ? 0 : tax),
"Order totals do not reconcile; review discounts, fees or rounding");
const shippingLines = list(order.shippingLines, "shipping lines");
check(shippingLines.every(line => typeof line.isRemoved === "boolean"),
"Missing shipping-line removal flag");
let shippingTax = 0;
let shippingLinesTotal = 0;
for (const line of shippingLines.filter(line => !line.isRemoved)) {
shippingLinesTotal = add(shippingLinesTotal,
bag(line.currentDiscountedPriceSet, "discounted shipping line"));
for (const taxLine of list(line.taxLines, "shipping taxes")) {
shippingTax = add(shippingTax, bag(taxLine.priceSet, "shipping tax"));
}
}
check(shippingLinesTotal === shippingPrice, "Shipping lines do not reconcile");
check(shippingTax <= tax, "Shipping tax exceeds order tax");
const shippingPaid = add(shippingPrice, order.taxesIncluded ? 0 : shippingTax);
const shippingRevenue = shippingPrice - (order.taxesIncluded ? shippingTax : 0);
const productRevenue = subtotal - (order.taxesIncluded ? tax - shippingTax : 0);
check(shippingRevenue >= 0 && productRevenue >= 0, "Tax exceeds sales revenue");
const revenue = total - tax;
check(revenue === add(productRevenue, shippingRevenue), "Revenue does not reconcile");
const lines = list(order.lineItems, "line items");
check(lines.length > 0, "No order line items");
const seen = new Set();
let quantity = 0;
let cogs = 0;
const snapshots = [];
const missing = [];
for (const line of lines) {
check(typeof line.id === "string" && !seen.has(line.id), "Invalid or duplicate line item");
seen.add(line.id);
check(Number.isSafeInteger(line.currentQuantity) && line.currentQuantity >= 0,
"Invalid line-item quantity");
if (line.currentQuantity === 0) continue;
check(line.isGiftCard === false, "Gift-card sales require separate accounting");
quantity = add(quantity, line.currentQuantity);
const unitCost = line.variant && line.variant.inventoryItem
&& line.variant.inventoryItem.unitCost;
if (!unitCost) {
missing.push(line.sku || line.id);
continue;
}
const costMicro = money(unitCost, "COGS for " + (line.sku || line.id), 6);
const lineMicro = costMicro * line.currentQuantity;
check(Number.isSafeInteger(lineMicro) && Number.isSafeInteger(lineMicro + 5000),
"Line cost exceeds safe precision");
const lineCost = Math.floor((lineMicro + 5000) / 10000);
cogs = add(cogs, lineCost);
snapshots.push({
line: line.id,
variant: line.variant.id,
sku: line.sku || "",
quantity: line.currentQuantity,
unitCost: String(unitCost.amount),
total: format(lineCost)
});
}
check(quantity === order.currentSubtotalLineItemsQuantity,
"Line-item quantities do not reconcile; input may be incomplete");
check(missing.length === 0, "Missing COGS for " + missing.slice(0, 10).join(", ")
+ (missing.length > 10 ? " (and more)" : ""));
const shipping = shippingEstimate(order, shippingPaid);
return {
currency: POLICY.currency,
order_total: format(total),
order_tax: format(tax),
revenue_ex_tax: format(revenue),
product_revenue_ex_tax: format(productRevenue),
cogs: format(cogs),
gross_profit: format(productRevenue - cogs),
shipping_paid: format(shippingPaid),
shipping_revenue_ex_tax: format(shippingRevenue),
shipping_cost_estimated: format(shipping.cost),
shipping_cost_basis: shipping.basis,
shipping_policy: POLICY.shippingVersion,
after_shipping_estimated: format(revenue - cogs - shipping.cost),
cogs_snapshot_json: JSON.stringify(snapshots),
exclusions: EXCLUSIONS
};
}
export default function main({ order }) {
check(order && /^gid:\/\/shopify\/Order\/\d+$/.test(order.id), "Missing valid order ID");
const previous = list(order.customAttributes, "existing order attributes");
check(previous.every(item => item && typeof item.key === "string"
&& typeof item.value === "string"), "Incomplete existing attributes; refusing to overwrite");
// Use an admin-side metafield for idempotency. Cart/order attributes alone
// are not a trustworthy completed-calculation marker.
check(order.dataleadrProfitSnapshot !== undefined,
"Snapshot metafield alias is missing; complete the Flow setup first");
if (order.dataleadrProfitSnapshot !== null) {
let saved;
try { saved = JSON.parse(order.dataleadrProfitSnapshot.value); } catch (_) {
throw new Error("Invalid stored profit snapshot; refusing to replace it");
}
check(saved && saved.version === POLICY.version && saved.orderId === order.id
&& saved.fields && saved.fields.status === "estimated_payment_snapshot",
"Unrecognised stored profit snapshot; review before recalculating");
const expected = Object.entries(saved.fields);
const current = previous.filter(item => item.key.startsWith(PREFIX));
const unchanged = current.length === expected.length
&& expected.every(([key, value]) => current.some(item =>
item.key === PREFIX + key && item.value === String(value)));
return unchanged
? noWrite("Existing payment snapshot retained; later costs/rates do not rewrite it")
: prepareWrite(order, previous, saved.fields,
"Restoring saved payment snapshot; no recalculation with today's costs");
}
check(typeof order.updatedAt === "string" && order.updatedAt.length > 0, "Missing order timestamp");
const base = {
version: POLICY.version,
basis: BASIS,
source_order_updated_at: order.updatedAt
};
try {
const figures = calculate(order);
const costSnapshot = JSON.parse(figures.cogs_snapshot_json);
delete figures.cogs_snapshot_json;
const fields = {
...base, status: "estimated_payment_snapshot", ...figures
};
return prepareWrite(order, previous, fields,
"Payment snapshot prepared with estimated shipping expense", {
version: POLICY.version, orderId: order.id,
fields, costs: costSnapshot, freeDeliveryCostMinor: POLICY.freeDeliveryCostMinor
});
} catch (error) {
// No numeric profit is emitted when any required input is unavailable.
return prepareWrite(order, previous, {
...base, status: "needs_review", reason: String(error.message || error).slice(0, 600)
}, "Profit unavailable: " + String(error.message || error).slice(0, 600));
}
}
END FLOW CODE
MUTATION INPUTS — select orderUpdate, then paste:
BEGIN MUTATION INPUTS
END MUTATION INPUTS