> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pipeline.software/llms.txt
> Use this file to discover all available pages before exploring further.

# DTO Reference

> skuIdMap pattern and DTO shapes used by bridge methods.

## skuIdMap Pattern

For `quoting_extension` tools that work with known SKU codes, the recommended pattern is:

1. At tool init, call `products.list()` and build a local `{ [sku]: productId }` lookup.
2. Your tool's internal logic works with human-readable SKU codes (from a pricing spreadsheet,
   config object, or product catalogue).
3. When building lines for `quotes.addLines`, look up each SKU in `skuIdMap` and pass both
   `productCode` (the SKU string) and `productId` (the GUID). This triggers task template
   injection on the host.
4. Fall back gracefully: if a SKU is not found in `skuIdMap`, send the line without `productId`.
   The line still appears in the quote as free-form text — no task injection, but no error.

```javascript theme={null}
let skuIdMap = {};

async function initBridge() {
  // Load all products and index by SKU (uppercased for case-insensitive lookup)
  const productResult = await window.pipeline.products.list({ page: 1, pageSize: 500 });
  const products = (productResult && productResult.items) ? productResult.items : [];
  products.forEach(function(p) {
    if (p.sku && p.id) {
      skuIdMap[p.sku.toUpperCase()] = p.id;
    }
  });
}

// Later, when building a line:
function resolveProduct(skuCode) {
  return {
    productCode: skuCode,
    productId: skuIdMap[skuCode.toUpperCase()] || null  // null = no task injection (still sends)
  };
}
```

## DTO Shapes

```typescript theme={null}
// BridgeContextDto
interface BridgeContextDto {
  userName: string;
  userEmail: string;
  userRole: string;       // e.g. "H_Admin", "H_Field"
  tenantName: string;
  tenantId: string;
  cultureCode: string;   // e.g. "en-NZ"
}

// BridgeCustomerDto
interface BridgeCustomerDto {
  id: string;            // GUID
  name: string;
  email: string;
  phone: string;
}

// BridgeProductDto
interface BridgeProductDto {
  id: string;            // GUID
  sku: string;           // Human-readable product code (Stock_SKU.SKU)
  name: string;
  price: number;         // Retail sell price (Stock_SKU.Sell)
  unit: string;          // UOM token
}

// BridgeTaskTemplateDto (from taskTemplates.list)
interface BridgeTaskTemplateDto {
  id: string;            // GUID — pass as LinkedItemId on a "task" line
  code: string;          // Stable code (e.g. "T_DEFAULT_INSTALLATION_TASK")
  name: string;
}

// BridgeCostItemDto (from costItems.list)
interface BridgeCostItemDto {
  id: string;            // GUID — pass as LinkedItemId on a "cost" line
  code: string;          // Stable code (e.g. "COS-TRAVEL-TIME")
  name: string;
  type: string;          // T_Type token (e.g. "T_FINANCIAL", "T_TRAVEL")
}

// BridgeQuoteDto
interface BridgeQuoteDto {
  id: string;            // GUID
  ref: string;
  customerName: string;
  total: number;
  status: string;
  date: string;          // ISO 8601 datetime
}

// BridgeJobDto
interface BridgeJobDto {
  id: string;            // GUID
  ref: string;           // Human-readable job reference (e.g. "JOB-0042")
  customerName: string;
  customerIdGuid: string; // GUID
  status: string;
}

// BridgePagedResult<T>
interface BridgePagedResult<T> {
  items: T[];
  totalCount: number;
  page: number;
  pageSize: number;
}

// BridgeCreateQuoteRequest
interface BridgeCreateQuoteRequest {
  jobId?: string;
  customerName?: string;
  customerEmail?: string;
  customerPhone?: string;
  upsertByEmail: boolean;
  title?: string;
  quoteRef?: string;
  lines: BridgeQuoteLineRequest[];
}

// BridgeQuoteLineRequest (for quotes.create)
interface BridgeQuoteLineRequest {
  description?: string;
  productCode?: string;
  qty: number;
  unitPrice: number;
  taxRate: number;
}

// BridgeCreateQuoteResult
interface BridgeCreateQuoteResult {
  id: string;
  ref: string;
  total: number;
  url?: string;          // Relative deep-link to the created quote, if available
}

// BridgeAddLineDto (for quotes.addLines — quoting_extension only)
interface BridgeAddLineDto {
  description?: string;
  productCode?: string;
  qty: number;
  unitPrice: number;
  costPrice?: number;       // When set: BUY=costPrice, SELL=unitPrice. When omitted: BUY=SELL=unitPrice
  taxRate: number;
  location?: string;        // Maps to FreeTextField2
  specification?: string;   // Maps to FreeTextField
  unit?: string;            // "T_ITEM" | "T_SQUARE_METRE" | "T_LINEAR_METRE"
  groupKey?: string;        // Lines sharing the same groupKey get the same QuoteLine.GroupId

  // -- Line linking (preferred over productId) --
  lineType?: string;        // "product" | "task" | "cost"  (defaults to "product")
  linkedItemId?: string;    // GUID into Stock_SKU / G_Task_Templates / COB_Items based on lineType.
                            // Replaces productId for new tools. Validation: rejects the whole batch
                            // if the GUID does not resolve to an active row in the indicated table.

  // -- Categorical grouping --
  section?: string;         // Free-text section label (e.g. "Blinds", "Installation", "Extras").
                            // Persisted on QuoteLine.Section. Host UI groups lines by section.
                            // Max 100 chars; trimmed; null/empty renders under "Ungrouped".

  // -- Deprecated (still supported) --
  /** @deprecated Use linkedItemId with lineType="product" instead. Retained for back-compat
   *  with Ziptrak v2.1.2 and earlier. New tools should not set this field. */
  productId?: string;
}
```

### Three line kinds (lineType)

| `lineType`            | `linkedItemId` resolves to | Behaviour                                                                                                                  |
| --------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `"product"` (default) | `Stock_SKU.IdGuid`         | If the linked SKU has a task sequence configured, the host auto-injects its task template lines (e.g. installation tasks). |
| `"task"`              | `G_Task_Templates.IdGuid`  | The line is the task itself. No auto-injection. Use for explicit installation, removal, configuration tasks.               |
| `"cost"`              | `COB_Items.IdGuid`         | The line is a cost-of-business item (shipping, travel, disposal, site visit, etc.). No auto-injection.                     |

When `lineType` is omitted (or set to `"product"`) and `linkedItemId` is null, the host falls back to the legacy `productId` field — keeping Ziptrak v2.1.2 and earlier extensions working unchanged.

### Section grouping

Quote lines are visually grouped by `section` in both the operator's quote editor and the customer-facing quote preview. Use a small set of stable labels per tool — e.g. for an indoor blinds extension: `"Blinds"`, `"Motorisation"`, `"Installation"`, `"Removal"`, `"Extras"`. Lines with no `section` render in a trailing "Ungrouped" block.
