3PL OS Guide

Multi-customer warehousing with storage billing, customer portals, and per-tenant inventory controls.

Chapter 1 — What 3PL OS Gives You

3PL OS turns a single-customer warehouse into a multi-customer operation. It unlocks customer-scoped inventory, storage billing, customer onboarding, and the customer portal.

What it adds on top of Warehouse OS

CapabilityWhy it matters
Customer master records (M25)Multiple downstream customers, each with their own users, contacts, billing.
Customer-owned inventory (M16)Track who owns what stock — your inventory vs. customer A vs. customer B.
Storage rules + accrual (M30)Daily/monthly storage charges based on volume, units, or flat rate.
Storage agingSee how long stock has been sitting — flag dormant inventory.
Customer-scoped pricing rulesNegotiate different rates per customer.
Customer portal (/console/customer/*)Customers self-serve inventory views, invoices, payment.
Operational documents (M26)Casework, contracts, photos attached to customer records.
Practically pairs with Warehouse OS
Trenvar doesn't strictly enforce that 3PL OS requires Warehouse OS, but a 3PL operation needs warehouse modules to actually function. Almost all 3PL OS tenants have Warehouse OS too.

Default landing path

/console/business/3pl/shipments for company_admin focused on the 3PL view.

Chapter 2 — Roles That Light Up with 3PL OS

RoleWhat they do in 3PL OS
company_adminOwns 3PL config — customer onboarding, storage rules, customer-specific pricing, portal access for customers.
operations_managerManages multi-customer warehouse — segregates inventory, oversees storage accrual.
customer_serviceCustomer-facing — answers customer questions, opens cases, sees customer-owned inventory.
accountingBills customers — service catalog, pricing rules, invoice append, storage accrual review, payments.
customer_admin (portal)Manages users for their own customer org. Places orders, views invoices, pays.
customer_user (portal)Standard portal user. Places orders, views invoices, pays.

Chapter 3 — Onboarding a New Customer

Adding a 3PL customer is a 6-step workflow. This chapter walks each step end-to-end so a new account manager can do it without supervision.

Where
/console/customer-service/customers  ·  /console/business/customers

Walkthrough — onboard customer "Acme Corp" end-to-end

Prerequisites

  • company_admin (full setup) or customer_service (create record only).
  • Signed contract or commitment with the customer.
  • You know: their legal company name, primary contact email + phone, billing address, agreed payment terms.
  • Stripe is connected for tenant (if customer will self-pay).

Step 1 — Create the customer record

  1. Go to /console/customer-service/customers. Header: "Customers". Top-right: Add Customer.
  2. Click Add Customer. Modal opens.
  3. Fill:
    • Display Name → "Acme Corp".
    • Customer Slug → "acme-corp" (lowercase, hyphens, no spaces). Cannot change after save.
    • Statusactive.
    • Industry → optional dropdown ("Apparel", "Electronics", etc.).
    • Portal Module Access → tick the OSes they should see (3pl always; commerce_os if you have it; ground_ops if you do air cargo for them).
    • Primary Contact:
      • Name → "Jane Smith".
      • Email → "jane@acme.com".
      • Phone → "+1-555-0100".
    • Billing Address → street, city, state, zip, country.
    • Tax ID → optional but useful for tax-exempt customers.
  4. Click Create Customer. Toast: "Customer Acme Corp created." The customer record appears in the list with slug acme-corp.

Step 2 — Configure billing profile

  1. From the customer detail, click the Billing tab.
  2. Click Edit Billing Profile. Modal opens.
  3. Fill:
    • Billable → checkbox. Tick it. (Untick for free/internal customers.)
    • Currency → USD / CAD / EUR / etc.
    • Payment Terms → Net 7 / Net 14 / Net 30 / Net 60 / Prepaid.
    • Billing Email → "ap@acme.com" (their accounts-payable inbox).
    • Invoice Email Template → defaults to your tenant's template; override per customer if needed.
    • Stripe Customer ID → click Connect Stripe Customer. Trenvar creates a Stripe customer record using the billing info; the Stripe ID is stored.
    • Tax Exempt → checkbox. Tick if they have a valid exemption certificate. Upload the cert in Documents tab afterwards.
  4. Save.

Step 3 — Set up storage rule(s) for the customer

See Chapter 5 for full walkthrough. In short: go to /console/business/storage/rules, create a rule scoped to this customer, link to their inventory.

Step 4 — Set up pricing rule(s) for the customer

See Chapter 7. In short: go to /console/business/billing/pricing-rules, create a fulfillment pricing rule with Customer = Acme Corp.

Step 5 — Invite portal users

  1. Go to /console/business/settings/users.
  2. Click Add User.
  3. Email → "jane@acme.com".
  4. Display Name → "Jane Smith".
  5. Role → customer_admin (gives her ability to manage other Acme users + Shopify integration).
  6. Linked Customer → "Acme Corp".
  7. Save. Trenvar sends Jane an invite email. She accepts, sets a password, logs in to /console/customer/inventory.
  8. Repeat for any other portal users Acme needs (typically a customer_user or two).

Step 6 — Verify with a test transaction

  1. Have Acme send a small test pre-alert (you can simulate this from /console/ops-manager/pre-alert).
  2. Receive 1 unit of one SKU.
  3. Wait for storage accrual to run (next day).
  4. Open a draft invoice for Acme, click Append Accruals.
  5. Confirm 1 day of storage shows up at the expected rate.
  6. If everything checks out, you're live.
Document everything
Use the Documents tab on the customer record to attach: signed contract, tax exemption cert, special handling instructions, contact list. When the customer churns 3 years later, you'll thank yourself.

Chapter 4 — Customer SKUs and Customer-Owned Inventory

In Warehouse-only mode, all stock is yours. In 3PL OS, every inventory item has an owner_customer_id. This chapter walks through how customer ownership flows through the system.

Walkthrough A — create a SKU owned by a customer

Step-by-step

  1. Go to /console/business/wms/item-master.
  2. Click Create SKU.
  3. Fill the standard fields (see Warehouse OS Chapter 4 for the deep walkthrough).
  4. Critical for 3PL: in the Identification section, find the Owner field. By default it's "Internal" (your own stock). Click the toggle / dropdown and switch to Client.
  5. A Client / Customer dropdown appears. Pick "Acme Corp".
  6. Save. The SKU is now associated with Acme. Acme will see it in their portal inventory; billing will treat it as Acme's stock.

Walkthrough B — receive customer-owned goods

  1. Create the pre-alert (Warehouse OS Chapter 5) but in the Customer field, pick "Acme Corp".
  2. Operator receives normally (Warehouse OS Chapter 6).
  3. Trenvar auto-tags the resulting handling units and inventory items with owner_customer_id = Acme Corp.
  4. Storage accrual starts immediately for Acme (per their storage rule).

Walkthrough C — transfer ownership of inventory

Use case: Acme sells some of their on-hand stock to "Beta Industries". The physical inventory doesn't move — only the ownership.

Step-by-step

  1. Go to /console/ops-manager/inventory.
  2. Find the inventory item to transfer. Click the row.
  3. Detail panel opens. Click Transfer Ownership.
  4. Modal opens:
    • From Owner → pre-filled (Acme Corp). Read-only.
    • To Owner → typeahead. Pick "Beta Industries".
    • Quantity → number. Defaults to all available units. Edit to transfer a partial.
    • Reason → dropdown: Sale between customers / Consignment switch / Bulk reassignment / Other.
    • Notes → optional free text.
  5. Click Submit Transfer. Confirmation: "Transfer 50 units of BLUE-SHIRT-M from Acme Corp to Beta Industries. Continue?"
  6. Confirm. Trenvar:
    • Decrements Acme's owned_units by 50.
    • Increments Beta's owned_units by 50.
    • Writes a single audit event with both sides recorded.
    • Storage accrual immediately switches to Beta's storage rule for those 50 units.

Inventory states under 3PL

StateMeaning
owned_unitsBelongs to a specific customer.
unassigned_unitsNo owner — internal stock.

Chapter 5 — Storage Rules & Accrual

Storage billing now uses a free-form three-layer model: tenants define their own units (BARREL, CBM, LITRE, DRUM, BOX — whatever your contracts call them), and the engine matches SKUs to rules via a shared Unit Code. This chapter walks through the full setup.

Where
/console/business/storage/rules  ·  /console/business/storage/accrual  ·  /console/business/storage/aging

The three-layer model

LayerWhat it does
1. Storage RuleDefines the billing contract: unit code, unit label, quantity source, cadence, unit price, free days, minimum, customer scope.
2. Unit CodeThe shared key (e.g., BARREL, CBM) that links a rule to the SKUs it bills.
3. Item Master / Customer CatalogTells the system which SKU uses which Unit Code via Storage Billing Unit Code on the SKU.
The matching rule
The accrual engine matches a SKU to a storage rule by their shared Unit Code. If a SKU has Storage Billing Unit Code = BARREL, the engine finds the best active BARREL rule for that customer. If the SKU's Unit Code doesn't match any active rule, the SKU isn't billed.

Quantity Source — how each unit is measured

Every storage rule picks one Quantity Source. This tells the engine what to count.

Quantity SourceEngine measuresUse when
Quantity UnitsInventory unit countThe stocked unit count itself is the billable count.
Volume (CBM)Cubic metres of spaceCharge based on space consumed; resolved from inventory volume_cm3 or item dimensions.
Assigned SKU Storage UnitsSKU's own Storage Billing Qty/Unit × stocked unitsYou want a free-form unit like BARREL, LITRE, DRUM, BOX. Tenant decides how many of the unit each stocked item equals.
Handling UnitsTotal HU count in storagePer-container pricing; every HU counts.
PalletsPallet-typed HU countCustomer ships in pallets; you rent floor positions.
Occupied BinsBins with stockBin-rental contracts.
Flat Rental1 per customer per periodSimple monthly retainer.

Walkthrough A — create a Volume (CBM) rule

Step-by-step

  1. Go to /console/business/storage/rules. Top-right: Create Rule.
  2. Click Create Rule. Modal opens.
  3. Fill:
    • Code → "CBM-MONTH" (internal identifier).
    • Name → "CBM Storage" (tenant-facing).
    • Unit CodeCBM. This is the matching key.
    • Unit Label → "CBM" (display name shown to users).
    • Quantity SourceVolume (CBM).
    • CadenceMonthly.
    • Unit Price → 60.00 ($60 per CBM per month).
    • Free Days → optional grace period.
    • Minimum Charge (Period) → optional floor.
    • Customer Scope → blank for tenant default, or pick a downstream client.
  4. Save.

Walkthrough B — create an Assigned SKU Storage Units rule (free-form unit, e.g., BARREL)

Use case: you store liquid in barrels. The contract bills $20 per barrel per month.

Step-by-step

  1. Click Create Rule.
  2. Fill:
    • Code → "BARREL-MONTH".
    • Name → "Barrel Storage".
    • Unit CodeBARREL. (Tenant-defined; can be anything as long as SKU assignments use the same string.)
    • Unit Label → "Barrel".
    • Quantity SourceAssigned SKU Storage Units.
    • Cadence → Monthly.
    • Unit Price → 20.00.
    • Customer Scope → optional.
  3. Save.
  4. Now go to Item Master and assign each barrel-stored SKU to Storage Billing Unit Code = BARREL (Walkthrough D below).

Walkthrough C — create a Pallets rule

  1. Create Rule.
  2. Code → "PALLET-MONTH". Name → "Pallet Storage". Unit Code → PALLET. Unit Label → "Pallet".
  3. Quantity Source → Pallets. Cadence → Monthly. Unit Price → 25.00.
  4. Customer Scope → "Acme Corp" (or blank for default).
  5. Save.

Walkthrough D — assign a SKU to a storage unit (Item Master)

This is how the engine knows whether a SKU bills as BARREL, CBM, PALLET, or anything else.

Step-by-step

  1. Go to /console/business/wms/item-master.
  2. Open a SKU.
  3. Find the Storage Billing section. Set:
    • Storage Billing Unit Code → e.g., BARREL (must match the rule's Unit Code exactly).
    • Storage Billing Qty/Unit → how many of the unit one stocked unit equals:
      • 1 if one stocked unit bills as one barrel.
      • 200 if one stocked unit bills as 200 litres (and the rule's Unit Code is LITRE).
      • Blank when the rule uses Volume (CBM) and quantity comes from dimensions instead.
  4. Save.

Walkthrough E — set a client's General Storage Billing Rule (client-level fallback)

Use case: 3PL Client A is generally billed by CBM on every SKU. Instead of setting Storage Billing Unit Code = CBM on every one of their SKUs, set one client-level fallback. The engine uses the fallback unless a more specific rule overrides.

Step-by-step

  1. Go to Business Console → Customers.
  2. Open the downstream client's record (e.g., 3PL Client A).
  3. Scroll to the Storage Billing section.
  4. Find General Storage Billing Rule. Pick the rule that applies as the client's default — e.g., the client's CBM Storage rule.
  5. Save the customer record.

What this does

  • Sets the client-level fallback storage billing rule.
  • Useful when the client is mostly billed one way (CBM, Pallet, Bin, BARREL — whatever you've defined).
  • Reduces the need to assign storage rules on every SKU individually.
When to use this vs Item Master vs Customer Catalog
See the decision guide at the end of this chapter — it tells you exactly which lever to pull.

Walkthrough F — override a SKU's storage unit for one customer (Customer Catalog)

Use case: SKU "BLUE-LIQUID" defaults to BARREL in Item Master. But for one downstream client (Beta Industries), it should bill as CBM instead — a per-SKU, per-client override.

Create the storage rule first
The Storage Billing Unit Code on the SKU row is a dropdown populated from active storage rules. Operators don't type the code manually. So before doing this walkthrough, make sure the target rule (e.g., CBM) exists and is active in Storage → Rules — otherwise it won't appear in the dropdown.

Step-by-step

  1. Go to Business Console → WMS → Item Master. Switch to the 3PL context tab (the client view).
  2. Find the downstream client SKU row you want to override (filtered by Beta Industries).
  3. Click Edit Rules on that row. A modal opens with the SKU's billing rule fields.
  4. Find the Storage Billing Unit Code dropdown. The list is populated from active storage rules. Pick CBM.
  5. Set Storage Billing Qty / Unit when needed. (For CBM-with-Volume-source, leave blank — quantity resolves from dimensions. For BARREL-with-Assigned-SKU-Storage-Units source, set to 1 or whatever the SKU equals.)
  6. Save the rules. For Beta Industries' inventory of this SKU, the engine now uses CBM. For other customers, it still uses BARREL.
Legacy codes
If a SKU row has an old Storage Billing Unit Code that no longer exists as an active rule (e.g., a unit was renamed), the modal will still show the legacy value as the current setting until you replace it. Replace any legacy values when you spot them — otherwise the engine has nothing to match.

Resolution priority (5 layers)

When the engine bills a stock row, it picks a Unit Code in this order — first match wins:

PrioritySourceWhen to use
1 (highest)Inventory row's explicit storage_rule_id or storage_rule_codeRare one-off operational exceptions only.
2Customer Catalog storage assignment
(WMS → Item Master → 3PL context → Edit Rules)
One downstream client needs a different unit for a specific SKU than the tenant default.
3Client General Storage Billing Rule
(Customers → [client] → General Storage Billing Rule)
The whole downstream client is generally billed by one rule (e.g., everything CBM, everything Pallet).
4Item Master storage assignmentTenant-wide default for the SKU across all clients.
5 (lowest)Auto-match / default tenant ruleImplicit fallback when nothing more specific exists.

Decision guide — where to configure the rule

Configure hereUse whenExample
Customer Details → General Storage Billing RuleThe whole client is generally billed the same way.Client A is mostly CBM. Set their General Storage Billing Rule to the CBM rule and stop fiddling with each SKU.
WMS → Item MasterThe SKU normally bills the same way across all clients.A bulk liquid SKU is usually billed as BARREL for everyone. Set Storage Billing Unit Code = BARREL on the SKU.
WMS → Item Master → 3PL context → Edit RulesOne client needs a different storage unit for one specific SKU than the Item Master default.SKU "BLUE-LIQUID" is BARREL by default but Beta Industries needs it billed as CBM.
Inventory row → storage_rule_id / storage_rule_codeRare one-off operational exception.One specific stock row needs a different rule for one period.
Rule of thumb
Configure as high as you can. If a client is mostly billed one way, set the General Storage Billing Rule on the client and skip per-SKU work entirely. Use Item Master for "this product is always billed this way regardless of client". Use Customer Catalog only for genuine per-client-per-SKU overrides. Use inventory-row overrides almost never.

Worked example — vape 3PL client billed in BARREL + CBM in the same month

3PL Client A stores both liquid (in barrels) and solid (by volume) goods. You set up two rules scoped to Client A:

Rule 1 — Barrel Storage

  • Unit Code = BARREL, Unit Label = "Barrel", Quantity Source = Assigned SKU Storage Units, Cadence = Monthly, Unit Price = $20, Customer Scope = 3PL Client A.

Rule 2 — CBM Storage

  • Unit Code = CBM, Unit Label = "CBM", Quantity Source = Volume (CBM), Cadence = Monthly, Unit Price = $60, Customer Scope = 3PL Client A.

Item Master assignment

  • Liquid SKUs → Storage Billing Unit Code = BARREL, Storage Billing Qty/Unit = 1.
  • Solid SKUs → Storage Billing Unit Code = CBM, Storage Billing Qty/Unit = blank.

Month-end usage

  • 1 barrel-assigned SKU unit in storage.
  • 1 CBM of CBM-assigned product in storage.

Result

  • Barrel storage: 1 × $20 = $20.
  • CBM storage: 1 × $60 = $60.
  • Total: $80.

Same customer. Same month. Two different storage models. No code changes needed.

Data quality requirements per Quantity Source

Quantity SourceRequired upstream data
Quantity UnitsAccurate inventory unit counts (basic).
Volume (CBM)Inventory rows carry volume_cm3, OR Item Master / Customer Catalog has dimensions for CBM resolution.
Assigned SKU Storage UnitsSKU has Storage Billing Unit Code matching the rule's Unit Code, AND Storage Billing Qty/Unit filled in if the billed quantity comes from the SKU assignment.
Handling UnitsHUs accurate; merging consolidations done before period close.
PalletsStock is in pallet-typed HUs; HU type stays accurate.
Occupied BinsOperators put away to actual bins, not generic zones.
Flat RentalActive rule and a billable customer.
All sourcesInventory ownership tagged to the correct downstream customer (owner_customer_id).
Unit Code mismatch = no bill
If a SKU's Storage Billing Unit Code doesn't match any active rule's Unit Code (case-sensitive string match), the engine doesn't bill that SKU. Audit your unit codes if "expected revenue is missing" tickets show up.
If billing looks wrong, check upstream data first
Most "storage billing is wrong" tickets trace back to: missing volume_cm3, mistyped Unit Code, missing Storage Billing Qty/Unit, miscategorized HUs, or untagged ownership — not the rule itself.

Walkthrough C — review today's accrual

  1. Go to /console/business/storage/accrual. Header: "Storage Accrual".
  2. Top: cards summarizing today's run — total accrual amount, customers billed, items processed, exceptions count.
  3. Below: a table of accrual entries, one row per inventory-item-day. Columns: Date, Customer, SKU, Qty, Rate, Charge, Status (pending / appended / adjusted).
  4. Filter by customer / date / status as needed.
  5. Click a row to see the calculation breakdown.

Walkthrough D — manually run accrual for back-fill

The cron normally runs daily at 02:00 UTC. If a day was missed (e.g., system was down), run it manually.

  1. From /console/business/storage/accrual click Run Accrual Manually.
  2. Modal: pick the date range (e.g., 2026-04-30 to 2026-05-02 for a 3-day back-fill).
  3. Click Run. Spinner: "Processing 3 days × 142 inventory items × 12 customers..."
  4. Done. Toast shows count of accrual entries created.

Walkthrough E — adjust an accrual entry

Use case: customer was supposed to have 5 free days but the system charged them — credit the entry.

  1. Find the offending entry in the accrual table.
  2. Click the row. Detail panel.
  3. Click Adjust.
  4. Modal: New Amount (e.g., 0), Reason (dropdown), Notes.
  5. Submit. Audit log captures original vs. adjusted amount.

Walkthrough F — storage aging report

  1. Go to /console/business/storage/aging.
  2. Filter by customer or all.
  3. Table shows each inventory item with: SKU, owner, location, qty, days in storage, total accrual to date.
  4. Sort by days descending to spot dormant inventory.
  5. Click Export CSV to send to the customer for "please tell us what to do with these old units."

Chapter 6 — The Service Catalog

Every invoice line references a service. The catalog is the master list. Set it up once; reuse on every invoice.

Where
/console/business/billing/services

Walkthrough — create a service

Step-by-step

  1. Go to /console/business/billing/services. Header: "Service Catalog". Top-right: Create Service.
  2. Click Create Service. Modal opens.
  3. Fill:
    • Code → "FULFILL-ORDER" (uppercase, hyphens). Auto-derived from name if blank.
    • Name → "Order Fulfillment".
    • Category → dropdown: fulfillment / qc / storage / extra_work / additional_work / shipping_label / other.
    • Unit → text. "order" / "hour" / "day" / "label" / "kg" / "pallet".
    • Default Unit Price → number. The fallback price when no pricing rule matches.
    • Currency → USD / CAD / EUR.
    • Description → optional. Internal notes.
    • Taxable → checkbox. Tick if tax applies (storage and labour usually yes; pure shipping label cost passthrough usually no).
    • Active → on by default.
  4. Click Create Service. Toast: "Service created."

A starter set for a 3PL — copy these in order

CodeNameCategoryUnitDefault PriceTaxable
FULFILL-ORDEROrder Fulfillmentfulfillmentorder$1.50Yes
STORAGE-DAYDaily Storagestorageday$0.35Yes
QC-UNITQC Checkqcunit$0.50Yes
SHIP-LABELShipping Labelshipping_labellabel$0.20No
EXTRA-LABORExtra Handlingextra_workhour$35.00Yes
RECEIVE-PALLETReceivingadditional_workpallet$7.00Yes
Don't archive a service if it's been used
Once a service is on issued invoices, archiving causes UI weirdness on those old invoices ("Service not found"). Untick Active to retire instead — it stays available for old records but doesn't appear in the picker on new invoices.

Chapter 7 — Pricing Rules

Rules tell Trenvar how to turn warehouse activity into invoice lines. Rules can be tenant-wide or scoped to one customer. Fulfillment rules support two pricing models — pick the one that matches your contract.

Where
/console/business/billing/pricing-rules

Source types most relevant in 3PL OS

Source TypeUsed for
fulfillmentPer-order, per-package, per-SKU, per-picked-unit charges. Supports two pricing models (see below).
storageDaily/monthly accrual.
qcQuality-check labour.
extra_work / additional_workOne-off labour (kitting, repacking).
shipping_labelPer-label charges.
manualAdded by hand at invoice time.
otherAnything that doesn't fit the categories above. Use sparingly so reports stay clean.

Fulfillment pricing models

When you pick Source Type = Billing: Fulfillment, you also pick a Pricing Model. There are now two:

Pricing ModelWhat it does
standardThe classic model. Bills per order / package / SKU / picked-unit, with optional weight tiers. This is what every existing rule defaults to.
base_plus_additional_distinct_skuNEW. Bills a flat base amount that includes up to N distinct SKUs per fulfillment, plus an additional charge for every distinct SKU beyond that. Weight tiers are not used in this mode.
Which one fits your contract?
Use standard when you charge per package, per pick, or by weight. Use base_plus_additional_distinct_sku when your contract reads like "we charge $X per order with up to 5 different SKUs included, plus $Y per additional SKU type."

Walkthrough A — Standard model with weight tiers

The classic 3PL fulfillment package pricing flow.

  1. Click Create Rule.
  2. Source Type → "Billing: Fulfillment".
  3. Rule Name → "3PL Fulfillment Package Pricing".
  4. Customer → leave blank for all customers, or pick one for negotiated rate.
  5. Pricing Modelstandard.
  6. Billable Fulfillment Unit → package (or order / sku / picked_unit).
  7. Default Amount → fallback rate.
  8. Weight Basis → Exact package weight (or shipment_total / package_average / none).
  9. Add weight tiers. Each tier has three fields entered in a small grid: upToKg (number, leave blank for "and above"), amount (number), label (text, optional).

The conceptual format upToKg=amount=label is still the easiest way to write tiers down on paper, and matches what you enter in the UI three-field grid:

2=2.75=Up to 2kg
5=4.25=Up to 5kg
10=6.5=Up to 10kg
=9=Over 10kg

Walkthrough B — Base + additional distinct SKU model

Bills one base amount per fulfillment that includes a fixed number of distinct SKUs, plus a per-SKU charge for anything beyond. Useful when you charge for SKU-mix complexity rather than weight.

Step-by-step

  1. Click Create Rule.
  2. Source Type → "Billing: Fulfillment".
  3. Rule Name → e.g. "Base + SKU Pricing".
  4. Customer → optional scope.
  5. Pricing MethodBase + additional distinct SKU.
  6. Base Amount → the starting fulfillment charge (e.g., $1.50).
  7. Included Distinct SKUs → how many distinct SKUs are included in the base amount (e.g., 1).
  8. Additional Distinct SKU Charge → the extra amount for each distinct SKU above the included count (e.g., $0.50).
  9. Save.

The formula

base amount + max(0, distinct SKU count − included distinct SKU count) × additional distinct SKU charge

Worked examples

Rule: Base $1.50, Included 1, Additional $0.50.

  • Order with 1 distinct SKU (3 units of SKU A, all in 1 package) → $1.50 base + 0 extras = $1.50.
  • Order with 2 distinct SKUs (3 units of SKU A + 3 units of SKU B, all in 1 package) → $1.50 + 1 × $0.50 = $2.00.
  • Order with 5 distinct SKUs → $1.50 + 4 × $0.50 = $3.50.

Unit quantities don't affect this method. Three units of one SKU billed the same as one unit of one SKU.

Weight tiers don't apply here
When Pricing Method is Base + additional distinct SKU, the weight-basis and weight-tier fields are hidden and ignored. If you need weight-based pricing, use the standard method.

Walkthrough C — shared-package small SKU setup (multiple small SKUs in one parcel)

Use this when multiple small SKUs are allowed in the same package and should bill as one parcel — not one fee per SKU.

The example

3 small SKUs → operator packs them into 1 package → 1 shipping label → 1 parcel charge on the invoice.

Step 1 — configure SKU packaging rules

  1. Go to /console/business/wms/item-master.
  2. Use the Client view for downstream 3PL customer products, or Internal for your own warehouse stock.
  3. For each SKU that can share a package, set:
    • Fulfillment Billingpackage.
    • Ship Alonefalse.
    • Cannot Mix Groups → leave blank unless you need restrictions.
    • Packaging Group → optional but recommended for similar items (e.g., small-parcel). Helps maintain a consistent packing policy.
  4. Save each SKU.

Step 2 — configure the fulfillment pricing rule

  1. Go to /console/business/billing/pricing-rules. Create or edit a fulfillment rule.
  2. Set:
    • Source Type → fulfillment.
    • Billing Unit → package.
  3. Pick a Weight Basis matching your model:
    • Exact package weight — real parcel weight determines the price.
    • Average package weight — simpler model using the order's mean parcel weight.
    • No weight tiers — every package is the same charge.
  4. Save.

Step 3 — what billing actually does

If the order has 3 SKUs that are all package-billed and not Ship Alone, and the operator packs them into 1 parcel:

  • Shipment has 1 package.
  • Shipping label has 1 parcel.
  • Append bills 1 package charge.

The SKU rules allow sharing; the actual pack and label record determine the count. Invoicing follows the real package count, not the SKU count.

Using Packaging Group

Define groups for SKUs that are usually compatible:

  • SKU A → Packaging Group = small-parcel.
  • SKU B → Packaging Group = small-parcel.
  • SKU C → Packaging Group = small-parcel.

This signals to operators (and any future packing logic) that these items should travel together. For exceptions, use Cannot Mix Groups to block specific combinations without forcing all items into Ship Alone.

Why this is better than Ship Alone for small items
Ship Alone forces every SKU into its own package — fine for bulky goods, expensive for small ones. Shared-package billing lets your customer benefit from real consolidation: they ship one parcel, they're billed for one parcel.

Customer-specific overrides

Two rules: default ($1.50/package, customer blank) + Acme rule ($1.25/package, customer = Acme). Acme uses theirs; everyone else uses default. Customer-specific rules can use a different pricing model than the default — for example, Acme on base_plus_additional_distinct_sku while everyone else stays on standard.

Standard-model gotcha — without parcel weights, you lose money
Exact weight pricing in the standard model requires the linked shipping label to have parcel rows with real weights. If parcel data is missing, Trenvar falls back to the default amount. Train operators to weigh every carton. (This gotcha does not apply to the distinct-SKU model — it doesn't read parcel weights at all.)

Activation

No effective dates. Use the Active toggle. Changes apply only to new invoice lines after the change.

Chapter 8 — Tax Setup

Tax regions tell Trenvar what rate to apply to taxable invoice lines. You define one region per tax jurisdiction you sell into.

Where
/console/business/billing/tax

Walkthrough — create a tax region

Prerequisites

  • company_admin or accounting role with tax.regions.configure.
  • You know the rate, country, and state/province.

Step-by-step

  1. Go to /console/business/billing/tax. Header: "Tax Regions". Top-right: Create Region.
  2. Click Create Region. Modal opens.
  3. Fill:
    • Code → "ON_HST" (uppercase, underscores, unique).
    • Name → "Ontario HST".
    • Country → ISO code dropdown. Pick CA.
    • State / Province → ON.
    • Tax Rate % → 13.0 (just the number, not "13%").
    • Inclusive → off (tax adds on top of price). Tick if your prices already include tax.
    • Effective From → optional date.
    • Effective To → optional date (use to schedule rate changes ahead of time).
    • Description → optional notes.
    • Active → on.
  4. Click Create. Toast: "Tax region ON_HST created."

How it gets applied

When you finalize an invoice (Chapter 9), Trenvar:

  1. Reads the customer's billing address.
  2. Matches country + state to an active tax region.
  3. Applies the rate to every invoice line where the service has Taxable ticked.
  4. Adds a "Tax" summary line to the invoice with the region's name and rate.

Worked example

Acme Corp's billing address is in Ontario, Canada. Their invoice has $1,500 in taxable fulfillment + $500 in non-taxable shipping label costs. Trenvar matches Country=CA + Province=ON to the ON_HST region (13%). Tax line: $1,500 × 13% = $195. Invoice total: $1,500 + $500 + $195 = $2,195.

If a customer doesn't match any region
No tax is applied. The invoice still finalizes — but the line is missing. Add the missing region, then issue a credit memo + new invoice if needed.

Chapter 9 — Invoicing Customers

Invoice lifecycle: Draft → Issued → (Sent) → Paid → (Overdue) → (Void). This chapter walks through every step from draft to paid.

Where
/console/accounting/billing  ·  /console/business/billing/invoices

Walkthrough A — create a draft invoice manually

Prerequisites

  • accounting role with billing.invoices.update (or company_admin).
  • Customer record exists with a billing profile.
  • Service catalog has the relevant services.

What the screen looks like

Go to /console/accounting/billing. Header: "Invoices". Filter pills: All / Draft / Issued / Paid / Overdue / Void. Top-right: Create Invoice.

Step-by-step

  1. Click Create Invoice. New page opens (full-page editor, not modal).
  2. Fill the header:
    • Customer → typeahead. Pick "Acme Corp".
    • Invoice Number → auto-fills based on tenant pattern (e.g., INV-2026-001234). Edit only if you have a strong reason.
    • Currency → defaults from customer billing profile.
    • Invoice Date → defaults to today.
    • Due Date → calculated from customer's payment terms (e.g., today + 30 days).
    • Period From / To → optional. Use for "billing for May 2026".
    • PO Number → optional. Customer's reference.
  3. Lines section appears below. Click Add Line:
    • Service → typeahead from catalog. Pick "Order Fulfillment". Unit auto-fills ("order"); Default Price auto-fills ($1.50).
    • Source Type → manual / fulfillment / storage / shipping_label / etc. Default manual for hand-typed lines.
    • Source Ref → only required for storage / shipping_label (the accrual entry ID or label ID).
    • Quantity → 120.
    • Unit Price → defaults from pricing rule if customer has one, else service default. Editable.
    • Description → optional override of the service description.
    • Taxable → inherited from service. Tickable.
  4. Add more lines as needed.
  5. Click Add Adjustment for any non-line credits/discounts/fees:
    • Type → Discount / Credit / Fee.
    • Amount → number (negative for discount/credit).
    • Description → "Volume discount", "Early-pay credit", etc.
  6. Right sidebar shows running totals: Subtotal, Adjustments, Subtotal after adjustments, Tax (calculated on finalize), Total Due.
  7. Click Save Draft at the bottom. Toast: "Draft saved." Invoice appears in the Drafts filter.

Walkthrough B — append storage accruals (3PL shortcut)

Skip the manual line-typing for storage. Append in one click.

  1. From the draft invoice, click Append Accruals (right sidebar).
  2. Modal: pick the date range to append (defaults to invoice's Period From/To).
  3. Click Append.
  4. Trenvar fetches all unappended storage accrual entries for this customer + window, groups them by storage rule, and adds them as invoice lines (e.g., "30 days × ACME-STD storage @ $0.05 × 142 units = $213.00").
  5. Toast: "8 accrual lines appended." Subtotal updates.

Walkthrough C — append fulfillment work (3PL shortcut)

  1. From the draft, click Append Fulfillment.
  2. Modal: date range, optional filter by carrier or order type.
  3. Click Append.
  4. Trenvar finds all completed, uninvoiced fulfillment orders for this customer + window. For each: reads linked shipping label parcels, applies the customer's fulfillment pricing rule (standard with weight tiers, or base + distinct SKU), creates one or more invoice lines.
  5. Toast: "47 fulfillment orders → 53 invoice lines."

Walkthrough D — finalize and send

  1. Review draft totals. Make any final adjustments.
  2. Click Finalize Invoice (top-right).
  3. Confirmation: "Finalize INV-2026-001234 for Acme Corp ($2,195.00)? Lines will be locked. Tax will be calculated. Invoice number assigned. Email will be sent to ap@acme.com."
  4. Click Confirm Finalize.
  5. Trenvar:
    • Calculates tax (Chapter 8).
    • Locks lines (no more edits).
    • Assigns the next invoice number.
    • Generates PDF.
    • Emails customer's billing email via Resend.
    • Status flips to Issued.
  6. Toast: "Invoice finalized + emailed." The right sidebar now shows: Issued At, Email Status (sent / failed / bounced), Stripe Pay link.

Walkthrough E — re-send invoice email

  1. Open the issued invoice.
  2. Click Send Email in the top-right (now visible because status is Issued, not Draft).
  3. Modal: pre-filled "to" address (billing email), customizable subject + body. Defaults to "Reminder: Invoice INV-2026-001234".
  4. Click Send. Trenvar emails again via Resend. Email status updates.

Walkthrough F — void an invoice

Use case: invoice was issued but contains errors and you need to cancel it cleanly.

  1. Open the issued invoice.
  2. Three-dot menu → Void.
  3. Modal: enter a void reason (mandatory). Pick action: Just void / Void + create credit memo for customer.
  4. Click Void Invoice.
  5. Status flips to Void. Audit log records actor, reason, time. If credit memo selected, a credit-memo invoice is auto-created.

Chapter 10 — Recording Payments

Two paths: Stripe pays you automatically, or you record a payment manually. Both update the invoice status.

Walkthrough A — Stripe automatic (most common)

  1. Customer opens their invoice in the portal (/console/customer/invoices/[invoiceId]).
  2. Customer clicks Pay Now. Stripe Checkout opens.
  3. Customer pays. Stripe POSTs to /api/stripe/webhooks.
  4. Trenvar matches the Stripe charge to the invoice ID, marks the invoice Paid, records paidAt.
  5. Both customer and your accounting team get email confirmations.

You don't do anything during this flow. It's all automatic.

Walkthrough B — manual payment entry (cheque, wire, ACH)

Use case: customer pays you outside Stripe — by cheque, wire transfer, ACH, or in person.

  1. Open the issued invoice in /console/accounting/billing.
  2. Click Record Payment (right sidebar).
  3. Modal:
    • Amount → number. Defaults to outstanding balance.
    • Payment Date → date picker. Defaults to today.
    • Payment Method → dropdown: Cheque / Wire Transfer / ACH / Cash / Other.
    • Reference → free text. "Cheque #1234", "Wire ref ABC-789".
    • Notes → optional.
  4. Click Record Payment.
  5. If the amount equals the full outstanding balance, status flips to Paid. If less, the invoice stays Issued with payments-to-date tracked, and the next-due-amount updates.

Walkthrough C — partial payments

  1. Customer paid $1,000 against a $2,195 invoice.
  2. Open the invoice. Record Payment for $1,000.
  3. Status stays Issued. Right sidebar shows: Total $2,195, Paid $1,000, Outstanding $1,195.
  4. When customer pays the rest, repeat Record Payment for $1,195. Status flips to Paid.

Walkthrough D — refund (Stripe)

  1. Open the paid invoice.
  2. Three-dot menu → Refund Payment.
  3. Modal: refund amount (full or partial), reason, notes.
  4. Click Refund via Stripe.
  5. Trenvar calls Stripe's refund API. Stripe processes (1–2 weeks for the customer to see it back on their card).
  6. Invoice status flips to Issued if fully refunded; new outstanding balance.
  7. If partial refund, an adjustment line is added; original invoice keeps its number.

Chapter 11 — Customer Portal Access

Once a customer has portal users, they sign in at the same login URL but land on a restricted, customer-scoped surface. This chapter walks through what they see and how to give them access.

Walkthrough — invite a customer's portal user

Prerequisites

  • company_admin (you).
  • Customer record exists with portal access toggled on (Chapter 3).
  • You have the user's email + name.

Step-by-step

  1. Go to /console/business/settings/users. Header: "Users".
  2. Click Add User.
  3. Fill:
    • Email → "jane@acme.com".
    • Display Name → "Jane Smith".
    • Role → tick customer_admin (or customer_user for standard access).
    • Linked Customer → "Acme Corp".
  4. Click Save & Send Invite. Trenvar sends Jane an invite email.
  5. Jane clicks the link, sets a password, and lands at her default portal screen (/console/customer/inventory for customer_admin).

What Jane sees in 3PL OS

ScreenShows
/console/customer/inventoryAcme's stock by SKU, lot, location, status (available / awaiting / reserved). She cannot see other customers' stock.
/console/customer/incomingAcme's inbound pre-alerts and shipments. Status updates live.
/console/customer/ordersAcme's fulfillment orders (placed by Acme or by you on Acme's behalf).
/console/customer/invoicesAcme's invoices + Stripe Pay Now button on each Issued invoice.
/console/customer/walletJane's saved Stripe payment methods.

(Catalog, Ship-Now, and B2B Storefront screens require Commerce OS — see that guide.)

Portal role differences

RoleExtras over baseline
customer_adminManages other portal users for own org. Connects Shopify integration. Sees Integrations screen.
customer_userStandard. View, create order, pay. Cannot manage users or integrations.

Walkthrough — customer_admin invites another user from the portal

  1. Jane (customer_admin) signs in.
  2. Clicks Settings (or Users) in the sidebar.
  3. Sees a list of her org's portal users.
  4. Clicks Add User.
  5. Fills: email, display name, role (only customer_user available — she can't create another customer_admin without your approval).
  6. Saves. Trenvar sends invite. Same flow as before.

Walkthrough — customer creates a 3PL receiving order (inbound pre-alert) from the portal

This is how a downstream client tells you "I'm sending you these goods — please be ready to receive them." It creates a pre-alert that lands in your warehouse's receiving queue.

Where
/console/customer/incoming (customer portal)

Prerequisites (customer side)

  • Portal user with role customer_admin or customer_user — both have customer.orders.create.
  • The SKUs they want to send are already in their catalog (you set this up during onboarding).
  • They know the expected arrival date and quantities.

What the screen looks like

Customer signs in; lands at /console/customer/incoming (or clicks Incoming in their sidebar). Header reads "Incoming Shipments" with a subtitle: "Create inbound orders so your 3PL business can schedule receiving before arrival." The page shows their existing pre-alerts as a table (status, prealert code, expected arrival, units expected vs received). Top-right: a New 3PL Receiving Order button (visible only to roles with create permission).

Step-by-step (customer)

  1. Click New 3PL Receiving Order. An editable grid form opens.
  2. Fill the header:
    • Expected Arrival — date or date+time picker.
    • Notes — free text ("Driver Mike Johnson, ETA 9 AM, dock 4").
    • Documents — optional. Attach packing slips, commercial invoices, or any paperwork.
  3. Add expected lines in the grid. For each row:
    • SKU — typeahead (autocompletes from the customer's catalog only — they can't pre-alert SKUs they don't own).
    • Expected Units — number.
    • Expected Volume (CBM) — auto-calculates from SKU dimensions if available; editable.
    • Lot — required if the SKU is lot-controlled.
    • Serial — required if the SKU is serial-controlled.
    • Expiry Date — required if the SKU is expiry-required.
    • Batch No — optional reference.
  4. Add as many lines as needed. Single-unit-per-line SKUs get one row per unit.
  5. Click Submit.
  6. Toast confirms: "3PL receiving order submitted (PA-20260503-001)." The new pre-alert appears in the customer's table with status open.

What the tenant sees

  • The pre-alert immediately appears in the tenant's queue at /console/ops-manager/pre-alert with Source = customer_portal (so ops managers know it came from the customer, not from in-house).
  • Customer field is auto-set to that downstream client.
  • An audit entry is logged with the customer user's UID.
  • The tenant doesn't need to re-enter anything. Receiving (Warehouse OS Chapter 6) runs against this pre-alert as if your ops manager had created it.
Operational tip
Make this the default channel for inbound notifications. It's faster than email, the data is structured (no transcription errors), and you both see the same single source of truth — including documents and notes. Train your customers' admins to do this once and they'll thank you.
If "New 3PL Receiving Order" button is missing
The user's role doesn't have customer.orders.create (e.g., a future read-only role). Have their customer_admin promote them, or their company_admin (you) update the role.

Walkthrough — customer creates a fulfillment order from the portal (3PL OS, no Commerce OS)

This is how a downstream client tells you "ship this to this address" without going through a B2B catalog. Pure 3PL OS — no Commerce OS / no storefront required.

Where
/console/customer/orders (customer portal)

Prerequisites (customer side)

  • Portal user with role customer_admin, customer_user, customer_buyer, or customer_ship_now — all have customer.orders.create.
  • The SKUs they want to ship exist in their catalog and have on-hand inventory.
  • They have the recipient's full address.

What the screen looks like

Customer signs in; clicks Orders in their sidebar. The page lists their existing orders (status pill, financial status, items, date). Top-right: a Create Manual Order button.

Step-by-step (customer)

  1. Click Create Manual Order. Modal form opens.
  2. Fill the header:
    • Order Number — optional. Their internal reference. Leave blank to auto-generate.
    • Notes — optional free text for the warehouse.
  3. Fill the recipient (Ship-To):
    • Recipient Name — required.
    • Phone, Email — recommended (carrier delivery notifications).
    • Address Line 1 — Google Maps autocomplete kicks in as they type. Picking a suggestion auto-fills city, state, zip, country.
    • Address Line 2, City, State/Province, Zip / Postal Code, Country — finish or correct as needed.
  4. Add lines. For each row:
    • SKU — typeahead from their catalog.
    • Requested Units — number. Cannot exceed available inventory for that SKU under their ownership.
    • Lot / Serial — only if the SKU requires them.
  5. Add as many lines as the order needs.
  6. Click Submit Order.
  7. Trenvar generates an idempotency key client-side so duplicate clicks don't create duplicate orders.
  8. Toast confirms: "Order submitted." The new order appears in the customer's list with initial status (depends on Fulfillment Automation setting — see below).

Fulfillment Automation toggle

At the top of the customer's Orders page is a Fulfillment Automation card with two modes:

ModeWhat it does
Always send to 3PLEvery customer-submitted order routes to your warehouse fulfillment queue immediately.
Require my decision firstOrders land in a customer-side review state. Customer approves each one before it reaches your warehouse — useful when they want a human gate.

Customers pick the mode they want. Most pick Always send to 3PL to minimize friction.

What the tenant sees

  • The order lands in your fulfillment queue at /console/business/wms/fulfillment (or the operator's pick queue) with Source = customer_portal.
  • Customer field auto-set to that client.
  • Pick task auto-generated.
  • From here, the operator picks/packs/labels exactly as if the order had been entered by your team — see Warehouse OS Chapters 11–13.
  • Status updates flow back to the customer's portal in real time as the order moves through fulfillment.

Worked example — Acme self-serves an order

  1. Mon 10:00 — Jane (customer_admin at Acme) signs in to /console/customer/orders.
  2. 10:01 — Clicks Create Manual Order.
  3. 10:02 — Order Number = "ACM-PO-2026-512", Notes = "Standard ground service".
  4. 10:03 — Recipient Name = "Beta Industries", picks address from Google Maps autocomplete (12 Industrial Way, Calgary AB).
  5. 10:04 — Adds 2 lines: 12 × SKU-BLUE-SHIRT-M, 8 × SKU-RED-SHIRT-L.
  6. 10:05 — Clicks Submit Order.
  7. 10:05 — Order O-20260503-014 lands in your operator's pick queue (because Acme set automation to "Always send to 3PL").
  8. 10:30 — Operator picks. Status flips to picked; Jane sees it in her portal.
  9. 11:15 — Pack + label complete. Status dispatched. Jane sees the FedEx tracking link.
Buyer role behaviour differs
Users with role customer_buyer (B2B Storefront, requires Commerce OS) don't see the manual-order form — they go through the catalog/cart instead. The Create Manual Order button is hidden for that role. Use customer_user or customer_admin for free-form manual orders.

Chapter 12 — Reports & Exports

Where
/console/accounting/reports  ·  /console/business/billing/exports
ReportWhat it shows
Invoice SettlementInvoices in a date range, by status.
Storage RevenueAccrual aggregated by customer, rule, window.
Tax ReportTax collected by region.
Storage AgingHow long stock has sat per customer.

QuickBooks export

Per-invoice Export to QuickBooks. Maps to QB invoice object via OAuth connection. Status fields track export success and errors.

Chapter 13 — Daily Flow per Role

Accounting's day in 3PL OS

  1. Open invoice queue.
  2. For each customer with billable activity: create draft invoice → Append Accruals → Append Fulfillment → review adjustments → Finalize.
  3. Record any manual payments received.
  4. Run aging report; chase overdue.

Customer service's day

  1. Triage cases.
  2. Look up customer-specific shipments and inventory in response to questions.
  3. Send notices for service updates.

Customer portal user's day

  1. Log in.
  2. Check inventory levels.
  3. Notify the warehouse of incoming goods (pre-alert if enabled).
  4. Place an order if needed.
  5. Pay outstanding invoices.

Appendix A — 3PL OS Console Paths

PathScreen
/console/business/3pl/shipments3PL shipments view
/console/business/customersCustomer list
/console/customer-service/customersCustomer list (CS)
/console/customer-service/customers/[customerId]Customer detail
/console/business/storage/rulesStorage rules
/console/business/storage/accrualStorage accrual runs
/console/business/storage/agingAging report
/console/business/billing/servicesService catalog
/console/business/billing/pricing-rulesPricing rules
/console/business/billing/invoicesInvoices (admin)
/console/business/billing/paymentsPayments
/console/business/billing/exportsExports
/console/business/billing/importsImports
/console/business/billing/taxTax regions
/console/accounting/billingAccounting invoice queue
/console/accounting/billing/[invoiceId]Invoice detail
/console/accounting/storageStorage from accounting view
/console/accounting/storage/agingAging (accounting)
/console/accounting/reportsReports + exports
/console/accounting/customersCustomer list (accounting)
/console/accounting/customers/[customerId]Customer detail (accounting)
/console/customer/inventoryCustomer portal — inventory
/console/customer/incomingCustomer portal — pre-alerts
/console/customer/ordersCustomer portal — orders
/console/customer/invoicesCustomer portal — invoices
/console/customer/invoices/[invoiceId]Invoice detail (portal)
/console/customer/integrationsCustomer portal — integrations
/console/customer/walletCustomer portal — payment methods

Appendix B — 3PL OS Permissions

PermissionHeld by
customers.view, orders.view, invoices.view, payments.viewoperations_manager, customer_service, accounting
storage.rules.readoperations_manager, accounting
storage.accrual.readoperations_manager, accounting
billing.service_catalog.read / configureaccounting
billing.pricing.read / configureaccounting
billing.invoices.list / readoperations_manager, accounting
billing.payments.readoperations_manager, accounting
billing.exports.exportaccounting
billing.imports.read / runaccounting
billing.reconciliation.read / upload / review / approveoperations_manager (read+upload+review); accounting (full incl. approve)
tax.regions.read / configureaccounting
crm.customers.list / read / create / updateoperations_manager (full); customer_service, operator, accounting (read)
cases.listcustomer_service
customer.orders.create / viewcustomer_admin, customer_user
customer.invoices.view, customer.payments.paycustomer_admin, customer_user
customer.integrations.shopify.managecustomer_admin

Appendix C — Glossary

Every 3PL-OS-specific term, in plain English.

3PL receiving order — Customer-portal name for an inbound pre-alert that the customer submits. Same as a tenant-side pre-alert; the form is just on their portal.

Accrual entry — One day of storage charge for one inventory item under one rule. The daily accrual job creates these.

Append — Bulk-add accrual or fulfillment lines onto a draft invoice with one click.

Billing profile — Per-customer billing setup: currency, payment terms, billable on/off, Stripe customer ID, billing email, tax exempt.

Cadence — How often a storage rule charges: Daily or Monthly.

Customer / Client — A downstream company you serve. Your tenant has many customers.

Customer Catalog — Per-customer SKU settings layer. Used to override Item Master defaults for one client.

Customer Scope — A field on storage rules and pricing rules: blank for tenant default, or one customer for a contract-specific rule.

Free Days — Grace period at the start of storage when no charge accrues.

General Storage Billing Rule — Client-level fallback storage rule on the customer record. Used when a whole client is mostly billed one way.

Invoice append — See Append.

Owner / owner_customer_id — Which downstream customer owns a unit of inventory. Tags every receiving event.

Packaging Group — Optional label on a SKU (e.g., "small-parcel") signalling which SKUs are usually compatible to share a package.

Pricing Method — A fulfillment-rule field: Standard (weight tiers) or Base + additional distinct SKU.

Pricing Rule — Tells Trenvar how to turn warehouse activity into invoice lines. Source types include fulfillment, storage, qc, extra_work, shipping_label, manual, other.

Quantity Source — A storage-rule field defining how the unit is measured: Quantity Units, Volume (CBM), Assigned SKU Storage Units, Pallets, Handling Units, Occupied Bins, Flat Rental.

Service Catalog — Master list of billable services (Order Fulfillment, Daily Storage, etc.). Every invoice line references a service.

Stripe Customer — A Stripe-side record that lets the customer self-pay invoices via Stripe Checkout.

Storage Billing Qty/Unit — A SKU field. How many of the storage unit one stocked unit equals (e.g., 1 = one barrel; 200 = 200 litres).

Storage Billing Unit Code — A SKU field. The free-form unit code (e.g., BARREL, CBM) linking the SKU to a storage rule.

Storage Rule — A billing contract: Unit Code, Quantity Source, Cadence, Unit Price, Free Days, Minimum, Customer Scope.

Tax Region — A jurisdiction's tax rate. Defined per country / state with a percentage and inclusive/exclusive flag.

Tenant — Your company. The 3PL operator. Distinct from "customer" (which is a downstream client of yours).

Unit Code — A free-form key on a storage rule (e.g., BARREL, CBM). SKUs reference this code to get billed by that rule.

Unit Label — Display name shown to users (e.g., "Barrel"). The Unit Code is the technical match key; the Unit Label is the human-readable label.

Weight Tiers — Per-fulfillment-rule pricing bands. Format upToKg=amount=label.

Trenvar Support
Email info@trenvar.com  ·  www.trenvar.com

End of 3PL OS Guide  ·  v1.0  ·  May 2026