# @isa/checkout/data-access

A comprehensive checkout and shopping cart management library for Angular applications supporting multiple order types, reward redemption, and complex multi-step checkout workflows across retail and e-commerce operations.

## Overview

The Checkout Data Access library provides the complete infrastructure for managing shopping carts, reward catalogs, and checkout processes. It handles six distinct order types (in-store pickup, customer pickup, standard shipping, digital shipping, B2B shipping, and digital downloads), reward/loyalty redemption flows, customer/payer data transformation, and multi-phase checkout orchestration with automatic availability validation and destination management.

## Table of Contents

- [Features](#features)
- [Quick Start](#quick-start)
- [Core Concepts](#core-concepts)
- [API Reference](#api-reference)
- [Usage Examples](#usage-examples)
- [Order Types](#order-types)
- [Checkout Flow](#checkout-flow)
- [Reward System](#reward-system)
- [Data Transformation](#data-transformation)
- [Error Handling](#error-handling)
- [Testing](#testing)
- [Architecture Notes](#architecture-notes)

## Features

- **Shopping Cart Management** - Create, update, and manage shopping carts with full CRUD operations
- **Six Order Type Support** - InStore (Rücklage), Pickup (Abholung), Delivery (Versand), DIG-Versand, B2B-Versand, Download
- **Reward Catalog Store** - NgRx Signals store for managing reward items and selections with tab isolation
- **Complete Checkout Orchestration** - 13-step checkout workflow with automatic validation and transformation
- **CRM Data Integration** - Seamless conversion between CRM and checkout-api formats
- **Multi-Domain Adapters** - 8 specialized adapters for cross-domain data transformation
- **Zod Validation** - Runtime schema validation for 58+ schemas
- **Payment Type Determination** - Automatic payment type selection (FREE/CASH/INVOICE) based on order analysis
- **Availability Validation** - Integrated download validation and shipping availability updates
- **Destination Management** - Automatic shipping address updates and logistician assignment
- **Session Persistence** - Reward catalog state persists across browser sessions
- **Request Cancellation** - AbortSignal support for all async operations
- **Comprehensive Error Handling** - Typed CheckoutCompletionError with specific error codes
- **Tab Isolation** - Shopping carts and reward selections scoped per browser tab
- **Business Logic Helpers** - 15+ pure functions for order analysis and validation

## Quick Start

### 1. Shopping Cart Operations

```typescript
import { Component, inject } from '@angular/core';
import { ShoppingCartFacade } from '@isa/checkout/data-access';

@Component({
  selector: 'app-checkout',
  template: '...'
})
export class CheckoutComponent {
  #shoppingCartFacade = inject(ShoppingCartFacade);

  async createCart(): Promise<void> {
    // Create new shopping cart
    const cart = await this.#shoppingCartFacade.createShoppingCart();
    console.log('Cart created:', cart.id);

    // Get shopping cart
    const existingCart = await this.#shoppingCartFacade.getShoppingCart(cart.id!);
    console.log('Cart items:', existingCart?.items?.length);
  }
}
```

### 2. Complete Checkout with CRM Data

```typescript
import { Component, inject } from '@angular/core';
import { ShoppingCartFacade } from '@isa/checkout/data-access';
import { CustomerResource } from '@isa/crm/data-access';

@Component({
  selector: 'app-complete-checkout',
  template: '...'
})
export class CompleteCheckoutComponent {
  #shoppingCartFacade = inject(ShoppingCartFacade);
  #customerResource = inject(CustomerResource);

  async completeCheckout(shoppingCartId: number): Promise<void> {
    // Fetch customer from CRM
    const customer = await this.#customerResource.value();

    if (!customer) {
      throw new Error('Customer not found');
    }

    // Complete checkout with automatic CRM data transformation
    const orders = await this.#shoppingCartFacade.completeWithCrmData({
      shoppingCartId,
      crmCustomer: customer,
      crmShippingAddress: customer.shippingAddresses?.[0]?.data,
      crmPayer: customer.payers?.[0]?.payer?.data,
      notificationChannels: customer.notificationChannels ?? 1,
      specialComment: 'Please handle with care'
    });

    console.log('Orders created:', orders.length);
    orders.forEach(order => {
      console.log(`Order ${order.orderNumber}: ${order.orderType}`);
    });
  }
}
```

### 3. Reward Catalog Management

```typescript
import { Component, inject } from '@angular/core';
import { RewardCatalogStore } from '@isa/checkout/data-access';
import { Item } from '@isa/catalogue/data-access';

@Component({
  selector: 'app-reward-selection',
  template: '...'
})
export class RewardSelectionComponent {
  #rewardCatalogStore = inject(RewardCatalogStore);

  // Access reactive signals
  items = this.#rewardCatalogStore.items;
  selectedItems = this.#rewardCatalogStore.selectedItems;
  hits = this.#rewardCatalogStore.hits;

  selectReward(itemId: number, item: Item): void {
    this.#rewardCatalogStore.selectItem(itemId, item);
  }

  removeReward(itemId: number): void {
    this.#rewardCatalogStore.removeItem(itemId);
  }

  clearAllSelections(): void {
    this.#rewardCatalogStore.clearSelectedItems();
  }
}
```

### 4. Adding Items to Shopping Cart

```typescript
import { ShoppingCartService } from '@isa/checkout/data-access';

@Component({
  selector: 'app-add-to-cart',
  template: '...'
})
export class AddToCartComponent {
  #shoppingCartService = inject(ShoppingCartService);

  async addItemsToCart(shoppingCartId: number): Promise<void> {
    // Check if items can be added first
    const canAddResults = await this.#shoppingCartService.canAddItems({
      shoppingCartId,
      payload: [
        { itemId: 123, quantity: 2 },
        { itemId: 456, quantity: 1 }
      ]
    });

    // Process results
    canAddResults.forEach(result => {
      if (result.canAdd) {
        console.log(`Item ${result.itemId} can be added`);
      } else {
        console.log(`Item ${result.itemId} cannot be added: ${result.reason}`);
      }
    });

    // Add items to cart
    const updatedCart = await this.#shoppingCartService.addItem({
      shoppingCartId,
      items: [
        {
          destination: { target: 2 },
          product: {
            id: 123,
            catalogProductNumber: 'PROD-123',
            description: 'Sample Product'
          },
          availability: {
            price: {
              value: { value: 29.99, currency: 'EUR' },
              vat: { value: 4.78, inPercent: 19 }
            }
          },
          quantity: 2
        }
      ]
    });

    console.log('Updated cart:', updatedCart.items?.length);
  }
}
```

## Core Concepts

### Order Types

The library supports six distinct order types, each with specific characteristics and handling requirements:

#### 1. InStore (Rücklage)
- **Purpose**: In-store reservation for later pickup
- **Characteristics**: Branch-based, no shipping required
- **Payment**: Cash (4)
- **Features**: `{ orderType: 'Rücklage' }`

#### 2. Pickup (Abholung)
- **Purpose**: Customer pickup at branch location
- **Characteristics**: Branch-based, customer collects items
- **Payment**: Cash (4)
- **Features**: `{ orderType: 'Abholung' }`

#### 3. Delivery (Versand)
- **Purpose**: Standard shipping to customer address
- **Characteristics**: Requires shipping address, logistician assignment
- **Payment**: Invoice (128)
- **Features**: `{ orderType: 'Versand' }`

#### 4. Digital Shipping (DIG-Versand)
- **Purpose**: Digital delivery for webshop customers
- **Characteristics**: Requires special availability validation
- **Payment**: Invoice (128)
- **Features**: `{ orderType: 'DIG-Versand' }`

#### 5. B2B Shipping (B2B-Versand)
- **Purpose**: Business-to-business delivery
- **Characteristics**: Requires logistician 2470, default branch
- **Payment**: Invoice (128)
- **Features**: `{ orderType: 'B2B-Versand' }`

#### 6. Download
- **Purpose**: Digital product downloads
- **Characteristics**: Requires download availability validation
- **Payment**: Invoice (128) or Free (2) for loyalty
- **Features**: `{ orderType: 'Download' }`

### Shopping Cart State

```typescript
interface ShoppingCart {
  id?: number;                              // Shopping cart ID
  items?: EntityContainer<ShoppingCartItem>[]; // Cart items with metadata
  createdAt?: string;                       // Creation timestamp
  updatedAt?: string;                       // Last update timestamp
  features?: Record<string, string>;        // Custom features/flags
}

interface ShoppingCartItem {
  id?: number;                              // Item ID in cart
  destination?: Destination;                // Shipping/pickup destination
  product?: Product;                        // Product information
  availability?: OlaAvailability;           // Availability and pricing
  quantity: number;                         // Item quantity
  loyalty?: Loyalty;                        // Loyalty points/rewards
  promotion?: Promotion;                    // Applied promotions
  features?: Record<string, string>;        // Item features (orderType, etc.)
  specialComment?: string;                  // Item-specific instructions
}
```

### Checkout Flow Overview

The checkout completion process consists of 13 coordinated steps:

```
1. Fetch and validate shopping cart
2. Analyze order types (delivery, pickup, download, etc.)
3. Analyze customer type (B2B, online, guest, staff)
4. Determine if payer is required
5. Create or refresh checkout entity
6. Update destinations for customer (if needed)
7. Set special comments on items (if provided)
8. Validate download availabilities
9. Update shipping availabilities (DIG-Versand, B2B-Versand)
10. Set buyer on checkout
11. Set notification channels
12. Set payer (if required)
13. Set payment type (FREE/CASH/INVOICE)
14. Update destination shipping addresses (if delivery)

Result: checkoutId → Pass to OrderCreationFacade for order creation
```

### Payment Type Logic

Payment type is automatically determined based on order analysis:

```typescript
/**
 * Payment type decision tree:
 *
 * IF all items have loyalty.value > 0:
 *   → FREE (2) - Loyalty redemption
 *
 * ELSE IF hasDelivery OR hasDownload OR hasDigDelivery OR hasB2BDelivery:
 *   → INVOICE (128) - Invoicing required
 *
 * ELSE:
 *   → CASH (4) - In-store payment
 */
const PaymentTypes = {
  FREE: 2,      // Loyalty/reward orders
  CASH: 4,      // In-store pickup/take away
  INVOICE: 128  // Delivery and download orders
};
```

### Order Options Analysis

The library analyzes shopping cart items to determine checkout requirements:

```typescript
interface OrderOptionsAnalysis {
  hasTakeAway: boolean;        // Has Rücklage items
  hasPickUp: boolean;          // Has Abholung items
  hasDownload: boolean;        // Has Download items
  hasDelivery: boolean;        // Has Versand items
  hasDigDelivery: boolean;     // Has DIG-Versand items
  hasB2BDelivery: boolean;     // Has B2B-Versand items
  items: ShoppingCartItem[];   // Unwrapped items for processing
}
```

**Business Rules:**
- **Payer Required**: B2B customers OR any delivery/download orders
- **Destination Update Required**: Any delivery or download orders
- **Payment Type**: Determined by order types and loyalty status
- **Shipping Address Required**: Any delivery orders (Versand, DIG-Versand, B2B-Versand)

### Customer Type Analysis

Customer features are analyzed to determine handling requirements:

```typescript
interface CustomerTypeAnalysis {
  isOnline: boolean;          // Webshop customer
  isGuest: boolean;           // Guest account
  isB2B: boolean;             // Business customer
  hasCustomerCard: boolean;   // Loyalty card holder (Pay4More)
  isStaff: boolean;           // Employee/staff member
}
```

**Feature Mapping:**
- `webshop` → `isOnline: true`
- `guest` → `isGuest: true`
- `b2b` → `isB2B: true`
- `p4mUser` → `hasCustomerCard: true`
- `staff` → `isStaff: true`

### Reward System Architecture

The reward catalog store manages reward items and selections with automatic tab isolation:

```typescript
interface RewardCatalogEntity {
  tabId: number;                           // Browser tab ID (isolation)
  items: Item[];                           // Available reward items
  hits: number;                            // Total search results
  selectedItems: Record<number, Item>;     // Selected items by ID
}
```

**Key Features:**
- **Tab Isolation**: Each browser tab has independent reward state
- **Session Persistence**: State survives browser refreshes
- **Orphan Cleanup**: Automatically removes state when tabs close
- **Reactive Signals**: Computed signals for active tab data
- **Dual Shopping Carts**: Separate carts for regular and reward items

## API Reference

### ShoppingCartFacade

Main facade for shopping cart and checkout operations.

#### `createShoppingCart(): Promise<ShoppingCart>`

Creates a new empty shopping cart.

**Returns:** Promise resolving to the created shopping cart

**Example:**
```typescript
const cart = await facade.createShoppingCart();
console.log('Cart ID:', cart.id);
```

#### `getShoppingCart(shoppingCartId, abortSignal?): Promise<ShoppingCart | undefined>`

Fetches an existing shopping cart by ID.

**Parameters:**
- `shoppingCartId: number` - ID of the shopping cart to fetch
- `abortSignal?: AbortSignal` - Optional cancellation signal

**Returns:** Promise resolving to the shopping cart, or undefined if not found

**Throws:**
- `ResponseArgsError` - If API returns an error

**Example:**
```typescript
const cart = await facade.getShoppingCart(123, abortController.signal);
if (cart) {
  console.log('Items:', cart.items?.length);
}
```

#### `removeItem(params): Promise<ShoppingCart>`

Removes an item from the shopping cart (sets quantity to 0).

**Parameters:**
- `params: RemoveShoppingCartItemParams`
  - `shoppingCartId: number` - Shopping cart ID
  - `shoppingCartItemId: number` - Item ID to remove

**Returns:** Promise resolving to updated shopping cart

**Throws:**
- `ZodError` - If params validation fails
- `ResponseArgsError` - If API returns an error

**Example:**
```typescript
const updatedCart = await facade.removeItem({
  shoppingCartId: 123,
  shoppingCartItemId: 456
});
```

#### `updateItem(params): Promise<ShoppingCart>`

Updates a shopping cart item (quantity, special comment, etc.).

**Parameters:**
- `params: UpdateShoppingCartItemParams`
  - `shoppingCartId: number` - Shopping cart ID
  - `shoppingCartItemId: number` - Item ID to update
  - `values: UpdateShoppingCartItemDTO` - Fields to update

**Returns:** Promise resolving to updated shopping cart

**Throws:**
- `ZodError` - If params validation fails
- `ResponseArgsError` - If API returns an error

**Example:**
```typescript
const updatedCart = await facade.updateItem({
  shoppingCartId: 123,
  shoppingCartItemId: 456,
  values: { quantity: 5, specialComment: 'Gift wrap please' }
});
```

#### `complete(params, abortSignal?): Promise<Order[]>`

Completes checkout and creates orders.

**Parameters:**
- `params: CompleteOrderParams`
  - `shoppingCartId: number` - Shopping cart to process
  - `buyer: Buyer` - Buyer information
  - `notificationChannels?: NotificationChannel` - Communication channels
  - `customerFeatures: Record<string, string>` - Customer feature flags
  - `payer?: Payer` - Payer information (required for B2B/delivery/download)
  - `shippingAddress?: ShippingAddress` - Shipping address (required for delivery)
  - `specialComment?: string` - Special instructions
- `abortSignal?: AbortSignal` - Optional cancellation signal

**Returns:** Promise resolving to array of created orders

**Throws:**
- `CheckoutCompletionError` - For validation or business logic failures
- `ResponseArgsError` - For API failures

**Example:**
```typescript
const orders = await facade.complete({
  shoppingCartId: 123,
  buyer: buyerDTO,
  customerFeatures: { webshop: 'webshop', p4mUser: 'p4mUser' },
  notificationChannels: 1,
  payer: payerDTO,
  shippingAddress: addressDTO
}, abortController.signal);

console.log(`Created ${orders.length} orders`);
```

#### `completeWithCrmData(params, abortSignal?): Promise<Order[]>`

Completes checkout with CRM data, automatically transforming customer/payer/address.

**Parameters:**
- `params: CompleteCrmOrderParams`
  - `shoppingCartId: number` - Shopping cart to process
  - `crmCustomer: Customer` - Customer from CRM service
  - `crmPayer?: PayerDTO` - Payer from CRM service (optional)
  - `crmShippingAddress?: ShippingAddressDTO` - Shipping address from CRM (optional)
  - `notificationChannels?: NotificationChannel` - Communication channels
  - `specialComment?: string` - Special instructions
- `abortSignal?: AbortSignal` - Optional cancellation signal

**Returns:** Promise resolving to array of created orders

**Throws:**
- `CheckoutCompletionError` - For validation or business logic failures
- `ResponseArgsError` - For API failures

**Transformation Steps:**
1. Validates input with Zod schema
2. Converts `crmCustomer` to `buyer` using `CustomerAdapter.toBuyer()`
3. Converts `crmShippingAddress` using `ShippingAddressAdapter.fromCrmShippingAddress()`
4. Converts `crmPayer` using `PayerAdapter.toCheckoutFormat()`
5. Extracts customer features using `CustomerAdapter.extractCustomerFeatures()`
6. Delegates to `complete()` with transformed data

**Example:**
```typescript
const customer = await customerResource.value();

const orders = await facade.completeWithCrmData({
  shoppingCartId: 123,
  crmCustomer: customer,
  crmShippingAddress: customer.shippingAddresses[0].data,
  crmPayer: customer.payers[0].payer.data,
  notificationChannels: customer.notificationChannels ?? 1,
  specialComment: 'Rush delivery'
});
```

### Helper Functions

#### Analysis Helpers

##### `analyzeOrderOptions(items): OrderOptionsAnalysis`

Analyzes shopping cart items to determine which order types are present.

**Parameters:**
- `items: EntityContainer<ShoppingCartItem>[]` - Cart items to analyze

**Returns:** Analysis result with boolean flags for each order type

**Example:**
```typescript
const analysis = analyzeOrderOptions(cart.items);
if (analysis.hasDelivery) {
  console.log('Delivery items present - shipping address required');
}
```

##### `analyzeCustomerTypes(features): CustomerTypeAnalysis`

Analyzes customer features to determine customer type characteristics.

**Parameters:**
- `features: Record<string, string>` - Customer feature flags

**Returns:** Analysis result with boolean flags for customer types

##### `shouldSetPayer(options, customer): boolean`

Determines if payer should be set based on order and customer analysis.

**Business Rule:** Payer required when: `isB2B OR hasB2BDelivery OR hasDelivery OR hasDigDelivery OR hasDownload`

##### `needsDestinationUpdate(options): boolean`

Determines if destination update is needed.

**Business Rule:** Update needed when: `hasDownload OR hasDelivery OR hasDigDelivery OR hasB2BDelivery`

##### `determinePaymentType(options): PaymentType`

Determines payment type based on order analysis.

**Business Rules:**
1. If all items have `loyalty.value > 0`: **FREE (2)**
2. Else if has delivery/download orders: **INVOICE (128)**
3. Else: **CASH (4)**

### Adapters

The library provides 8 specialized adapters for cross-domain data transformation:

#### CustomerAdapter

Converts CRM customer data to checkout-api format.

**Static Methods:**
- `toBuyer(customer): Buyer` - Converts customer to buyer
- `toPayerFromCustomer(customer): Payer` - Converts customer to payer (self-paying)
- `toPayerFromAssignedPayer(assignedPayer): Payer | null` - Unwraps AssignedPayer container
- `extractCustomerFeatures(customer): Record<string, string>` - Extracts feature flags

**Key Differences:**
- **Buyer**: Includes `source` field and `dateOfBirth`
- **Payer from Customer**: No `source`, no `dateOfBirth`, sets `payerStatus: 0`
- **Payer from AssignedPayer**: Includes `source` field, unwraps EntityContainer

## Usage Examples

### Complete Multi-Step Checkout Workflow

```typescript
import { Component, inject, signal } from '@angular/core';
import { ShoppingCartFacade, CheckoutCompletionError } from '@isa/checkout/data-access';
import { CustomerResource } from '@isa/crm/data-access';

@Component({
  selector: 'app-checkout-flow',
  template: `
    <div class="checkout">
      <h2>Checkout</h2>
      @if (loading()) { <p>Processing checkout...</p> }
      @if (error()) { <div class="error">{{ error() }}</div> }
      <button (click)="processCheckout()" [disabled]="loading()">
        Complete Checkout
      </button>
    </div>
  `
})
export class CheckoutFlowComponent {
  #shoppingCartFacade = inject(ShoppingCartFacade);
  #customerResource = inject(CustomerResource);

  loading = signal(false);
  error = signal<string | null>(null);
  orders = signal<Order[]>([]);

  shoppingCartId = 123;

  async processCheckout(): Promise<void> {
    this.loading.set(true);
    this.error.set(null);

    try {
      const customer = await this.#customerResource.value();
      if (!customer) throw new Error('Customer not found');

      const createdOrders = await this.#shoppingCartFacade.completeWithCrmData({
        shoppingCartId: this.shoppingCartId,
        crmCustomer: customer,
        crmShippingAddress: customer.shippingAddresses?.[0]?.data,
        crmPayer: customer.payers?.[0]?.payer?.data,
        notificationChannels: customer.notificationChannels ?? 1
      });

      this.orders.set(createdOrders);
    } catch (err) {
      if (err instanceof CheckoutCompletionError) {
        this.error.set(`Checkout failed: ${err.message}`);
      } else {
        this.error.set('An unexpected error occurred');
      }
    } finally {
      this.loading.set(false);
    }
  }
}
```

## Order Types

### Parameter Requirements by Order Type

| Order Type | Features Flag | Payment Type | Payer Required | Shipping Address | Special Handling |
|------------|--------------|--------------|----------------|------------------|------------------|
| **Rücklage** (InStore) | `orderType: 'Rücklage'` | CASH (4) | No | No | In-store reservation |
| **Abholung** (Pickup) | `orderType: 'Abholung'` | CASH (4) | No | No | Customer pickup at branch |
| **Versand** (Delivery) | `orderType: 'Versand'` | INVOICE (128) | Yes | Yes | Standard shipping |
| **DIG-Versand** | `orderType: 'DIG-Versand'` | INVOICE (128) | Yes | Yes | Digital delivery, availability validation |
| **B2B-Versand** | `orderType: 'B2B-Versand'` | INVOICE (128) | Yes | Yes | Logistician 2470, default branch |
| **Download** | `orderType: 'Download'` | INVOICE (128) or FREE (2) | Yes | No | Download validation |

## Checkout Flow

The complete checkout process consists of 13 coordinated steps that validate data, transform cross-domain entities, update availabilities, and prepare the checkout for order creation.

## Reward System

### Dual Shopping Cart Architecture

The reward system uses separate shopping carts:

1. **Regular Shopping Cart** (`shoppingCartId`) - Items purchased with money
2. **Reward Shopping Cart** (`rewardShoppingCartId`) - Items purchased with loyalty points (zero price, loyalty.value set)

## Data Transformation

### CRM to Checkout Transformation

The library provides automatic transformation from CRM domain to checkout-api domain through specialized adapters.

## Error Handling

### CheckoutCompletionError Types

```typescript
type CheckoutCompletionErrorCode =
  | 'SHOPPING_CART_NOT_FOUND'      // Cart with ID doesn't exist
  | 'SHOPPING_CART_EMPTY'          // Cart has no items
  | 'CHECKOUT_NOT_FOUND'           // Checkout entity not found
  | 'INVALID_AVAILABILITY'         // Availability validation failed
  | 'MISSING_BUYER'                // Buyer data not provided
  | 'MISSING_REQUIRED_DATA'        // Required field missing
  | 'CHECKOUT_CONFLICT'            // Order already exists (HTTP 409)
  | 'ORDER_CREATION_FAILED'        // Order creation failed
  | 'DOWNLOAD_UNAVAILABLE'         // Download items not available
  | 'SHIPPING_AVAILABILITY_FAILED'; // Shipping availability update failed
```

## Testing

The library uses **Vitest** with **Angular Testing Utilities** for testing.

### Running Tests

```bash
# Run tests for this library
npx nx test checkout-data-access --skip-nx-cache

# Run tests with coverage
npx nx test checkout-data-access --code-coverage --skip-nx-cache

# Run tests in watch mode
npx nx test checkout-data-access --watch
```

## Architecture Notes

### Current Architecture

```
Components/Features
      ↓
ShoppingCartFacade (orchestration)
      ↓
├─→ ShoppingCartService (cart CRUD)
├─→ CheckoutService (checkout workflow)
├─→ OrderCreationFacade (oms-api)
└─→ Adapters (cross-domain transformation)

Stores (NgRx Signals)
      ↓
RewardCatalogStore (reward state management)
```

### Key Design Decisions

1. **Stateless Checkout Service** - All data passed as parameters for testability
2. **Separation of Checkout and Order Creation** - Clean domain boundaries
3. **Dual Shopping Cart for Rewards** - Payment and pricing isolation
4. **Extensive Adapter Pattern** - 8 adapters for cross-domain transformation
5. **Tab-Isolated Reward Catalog** - NgRx Signals with automatic cleanup

## Dependencies

### Required Libraries

- `@angular/core` - Angular framework
- `@ngrx/signals` - NgRx Signals for state management
- `@generated/swagger/checkout-api` - Generated checkout API client
- `@isa/common/data-access` - Common utilities
- `@isa/core/logging` - Logging service
- `@isa/core/storage` - Session storage
- `@isa/core/tabs` - Tab service
- `@isa/catalogue/data-access` - Availability services
- `@isa/crm/data-access` - Customer types
- `@isa/oms/data-access` - Order creation
- `@isa/remission/data-access` - Branch service
- `zod` - Schema validation
- `rxjs` - Reactive programming

### Path Alias

Import from: `@isa/checkout/data-access`

## License

Internal ISA Frontend library - not for external distribution.
