# @isa/remission/shared/return-receipt-actions

Angular standalone components for managing return receipt actions including deletion, continuation, and completion workflows in the remission process.

## Overview

The Remission Shared Return Receipt Actions library provides two specialized action components for managing return receipts in remission workflows. These components handle critical operations like deleting return receipts, continuing remission processes, and completing remission packages ("Wanne"). They integrate with the RemissionStore and RemissionReturnReceiptService to provide state management and API interactions.

## Table of Contents

- [Features](#features)
- [Quick Start](#quick-start)
- [Component API](#component-api)
- [Usage Examples](#usage-examples)
- [Component Details](#component-details)
- [Business Logic](#business-logic)
- [Testing](#testing)
- [Dependencies](#dependencies)

## Features

- **Return Receipt Deletion** - Delete return receipts with validation and state cleanup
- **Remission Continuation** - Continue existing or start new remission workflows
- **Remission Completion** - Complete remission packages with automatic package assignment
- **State Management** - Integration with RemissionStore for current remission tracking
- **Confirmation Dialogs** - User confirmation for destructive and workflow-changing actions
- **Navigation** - Automatic routing to remission list after operations
- **Loading States** - Pending state indicators during async operations
- **Error Handling** - Comprehensive error logging and recovery
- **E2E Testing Attributes** - Complete data-* attributes for automated testing

## Quick Start

### 1. Import Components

```typescript
import {
  RemissionReturnReceiptActionsComponent,
  RemissionReturnReceiptCompleteComponent
} from '@isa/remission/shared/return-receipt-actions';

@Component({
  selector: 'app-return-receipt-card',
  imports: [
    RemissionReturnReceiptActionsComponent,
    RemissionReturnReceiptCompleteComponent
  ],
  template: '...'
})
export class ReturnReceiptCardComponent {}
```

### 2. Use Return Receipt Actions

```typescript
@Component({
  template: `
    <lib-remission-return-receipt-actions
      [remissionReturn]="returnData()"
      [displayDeleteAction]="true"
      (reloadData)="onReloadList()"
    ></lib-remission-return-receipt-actions>
  `
})
export class MyComponent {
  returnData = signal<Return>({ id: 123, receipts: [...] });

  onReloadList() {
    // Refresh the return receipt list
  }
}
```

### 3. Use Complete Button

```typescript
@Component({
  template: `
    <lib-remission-return-receipt-complete
      [returnId]="123"
      [receiptId]="456"
      [itemsLength]="5"
      [hasAssignedPackage]="true"
      (reloadData)="onReloadList()"
    ></lib-remission-return-receipt-complete>
  `
})
export class MyComponent {
  onReloadList() {
    // Refresh the data
  }
}
```

## Component API

### RemissionReturnReceiptActionsComponent

Action buttons for deleting and continuing return receipts.

#### Selector

```html
<lib-remission-return-receipt-actions></lib-remission-return-receipt-actions>
```

#### Inputs

| Input | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `remissionReturn` | `Return` | Yes | - | Return data containing receipts and metadata |
| `displayDeleteAction` | `boolean` | No | `true` | Whether to show the delete button |

#### Outputs

| Output | Type | Description |
|--------|------|-------------|
| `reloadData` | `void` | Emitted when the list needs to be reloaded |

#### Key Methods

**`onDelete(): Promise<void>`**
- Deletes all receipts associated with the return
- Clears RemissionStore state if deleting current remission
- Emits `reloadData` event after successful deletion
- Handles errors with comprehensive logging

**`onContinueRemission(): Promise<void>`**
- Starts a new remission if not already started
- Shows confirmation dialog if different remission is in progress
- Navigates to remission list after starting
- Validates receipt availability before continuing

### RemissionReturnReceiptCompleteComponent

Fixed-position button for completing a remission package ("Wanne").

#### Selector

```html
<lib-remission-return-receipt-complete></lib-remission-return-receipt-complete>
```

#### Inputs

| Input | Type | Required | Description |
|-------|------|----------|-------------|
| `returnId` | `number` | Yes | Return ID (coerced from string) |
| `receiptId` | `number` | Yes | Receipt ID (coerced from string) |
| `itemsLength` | `number` | Yes | Number of items in the receipt |
| `hasAssignedPackage` | `boolean` | Yes | Whether package number is assigned |

#### Outputs

| Output | Type | Description |
|--------|------|-------------|
| `reloadData` | `void` | Emitted when data needs to be reloaded |

#### Key Methods

**`completeRemission(): Promise<void>`**
- Ensures package is assigned (#5289 requirement)
- Completes the return receipt and return
- Shows "Wanne abgeschlossen" dialog with options
- Option 1: Complete return group (Beenden)
- Option 2: Start new receipt in same group (Neue Wanne)
- Emits `reloadData` event after completion

**`completeSingleReturnReceipt(): Promise<Return>`**
- Completes the return receipt via API
- Clears RemissionStore state
- Returns the completed return data

## Usage Examples

### Complete Return Receipt Workflow

```typescript
import {
  RemissionReturnReceiptActionsComponent,
  RemissionReturnReceiptCompleteComponent
} from '@isa/remission/shared/return-receipt-actions';

@Component({
  selector: 'app-remission-receipt-details',
  imports: [
    RemissionReturnReceiptActionsComponent,
    RemissionReturnReceiptCompleteComponent
  ],
  template: `
    <div class="receipt-details">
      <!-- Receipt content -->
      <div class="receipt-items">
        <!-- Item list -->
      </div>

      <!-- Action buttons at top -->
      <lib-remission-return-receipt-actions
        [remissionReturn]="returnData()"
        [displayDeleteAction]="!isCompleted()"
        (reloadData)="handleReload()"
      ></lib-remission-return-receipt-actions>

      <!-- Complete button (fixed position) -->
      @if (!isCompleted()) {
        <lib-remission-return-receipt-complete
          [returnId]="returnId()"
          [receiptId]="receiptId()"
          [itemsLength]="receiptItems().length"
          [hasAssignedPackage]="hasPackage()"
          (reloadData)="handleReload()"
        ></lib-remission-return-receipt-complete>
      }
    </div>
  `
})
export class RemissionReceiptDetailsComponent {
  returnData = signal<Return | undefined>(undefined);
  returnId = signal(0);
  receiptId = signal(0);
  receiptItems = signal<ReceiptItem[]>([]);
  hasPackage = signal(false);

  isCompleted = computed(() => {
    return this.returnData()?.completed ?? false;
  });

  handleReload() {
    // Reload receipt data from API
    this.fetchReceiptData();
  }

  async fetchReceiptData() {
    // Fetch logic
  }
}
```

### Return Receipt List Actions

```typescript
import { RemissionReturnReceiptActionsComponent } from '@isa/remission/shared/return-receipt-actions';

@Component({
  selector: 'app-receipt-list-item',
  imports: [RemissionReturnReceiptActionsComponent],
  template: `
    <div class="receipt-card">
      <div class="receipt-header">
        <span>Receipt #{{ return().receipts[0].number }}</span>
        <span>{{ return().receipts[0].created | date }}</span>
      </div>

      <div class="receipt-body">
        <div>Items: {{ itemCount() }}</div>
        <div>Status: {{ status() }}</div>
      </div>

      <div class="receipt-actions">
        <lib-remission-return-receipt-actions
          [remissionReturn]="return()"
          [displayDeleteAction]="canDelete()"
          (reloadData)="reloadList.emit()"
        ></lib-remission-return-receipt-actions>
      </div>
    </div>
  `
})
export class ReceiptListItemComponent {
  return = input.required<Return>();
  reloadList = output<void>();

  itemCount = computed(() => {
    return this.return().receipts[0]?.data?.items?.length ?? 0;
  });

  status = computed(() => {
    return this.return().completed ? 'Completed' : 'In Progress';
  });

  canDelete = computed(() => {
    return !this.return().completed && this.itemCount() === 0;
  });
}
```

## Component Details

### RemissionReturnReceiptActionsComponent

**Button Layout:**
- **Delete Button** (Secondary, optional):
  - Text: "Löschen"
  - Disabled when `itemQuantity > 0`
  - Calls `onDelete()` method
  - Only shown if `displayDeleteAction` is true

- **Continue Button** (Primary):
  - Text: "Befüllen"
  - Always enabled
  - Calls `onContinueRemission()` method

**Computed Properties:**
```typescript
returnId = computed(() => this.remissionReturn().id);
receiptIds = computed(() => this.remissionReturn().receipts?.map(r => r.id) || []);
firstReceiptId = computed(() => this.receiptIds()[0]);
itemQuantity = computed(() => getReceiptItemQuantityFromReturn(this.remissionReturn()));
isCurrentRemission = computed(() => this.#store.isCurrentRemission({ returnId, receiptId }));
```

**Delete Flow:**
1. Iterate through all receipt IDs
2. For each receipt, check if it's the current remission
3. If current, clear RemissionStore state
4. Call `cancelReturnReceipt` API for each receipt
5. Call `cancelReturn` API for the return
6. Emit `reloadData` event
7. Log errors if any occur

**Continue Flow:**
1. Check if remission is already started
2. If not started:
   - Start remission with first receipt ID
   - Navigate to remission list
3. If different remission in progress:
   - Show confirmation dialog
   - Options: Continue current OR start new
   - If starting new, clear store and start with first receipt
4. Navigate to remission list

### RemissionReturnReceiptCompleteComponent

**Button Appearance:**
- Fixed position (bottom-right corner)
- Large size
- Brand color
- Text: "Wanne abschließen"
- Shows pending state during completion

**Completion Flow:**
1. **Package Assignment Check** (#5289):
   - If no package assigned, open package assignment dialog
   - If dialog canceled, abort completion

2. **Complete Receipt**:
   - Call `completeSingleReturnReceipt()`
   - Clears RemissionStore state

3. **Return Group Handling**:
   - If return has `returnGroup`:
     - Show "Wanne abgeschlossen" dialog
     - Option 1 (Beenden): Complete return group via API
     - Option 2 (Neue Wanne): Start new remission in same group

4. **Emit Reload Event**: Notify parent to refresh data

**Dialog Content:**
```
Title: "Wanne abgeschlossen"
Message: "Legen Sie abschließend den 'Blank Beizettel' in die abgeschlossene Wanne.
         Der Warenbegleitschein wird nach Abschluss der Remission versendet.
         Zum Öffnen eines neuen Warenbegleitscheins setzen Sie die Remission fort."

Buttons:
  - Neue Wanne (Close button)
  - Beenden (Confirm button)
```

## Business Logic

### Package Assignment Requirement (#5289)

Before completing a remission, a package number must be assigned. If not already assigned:
1. Open package assignment dialog
2. User scans or enters package number
3. Package is assigned to the receipt
4. Completion proceeds
5. If user cancels, completion is aborted

### Return Group Workflow

**Return Groups** represent physical containers ("Wannen") for grouped returns:
- Multiple receipts can belong to the same return group
- Completing a receipt offers two options:
  1. **Complete Entire Group**: Finalizes all receipts in the group
  2. **Start New Receipt**: Creates a new receipt in the same group

### State Management Integration

**RemissionStore Interactions:**
```typescript
// Check if current remission
isCurrentRemission({ returnId, receiptId })

// Clear state when deleting or completing
clearState()

// Start remission when continuing
startRemission({ returnId, receiptId })

// Reload return data
reloadReturn()
```

### Confirmation Dialogs

**Delete Confirmation**: Not shown (direct deletion)

**Continue with Different Remission**:
```
Title: "Bereits geöffneter Warenbegleitschein"
Message: "Möchten Sie wirklich einen neuen öffnen, oder möchten Sie zuerst den aktuellen abschließen?"
Close: "Aktuellen bearbeiten"
Confirm: "Neuen öffnen"
```

**Completion Confirmation**:
```
Title: "Wanne abgeschlossen"
Message: "Legen Sie abschließend den 'Blank Beizettel' in die abgeschlossene Wanne..."
Close: "Neue Wanne"
Confirm: "Beenden"
```

## Testing

```bash
# Run tests
npx nx test remission-return-receipt-actions --skip-nx-cache

# Run with coverage
npx nx test remission-return-receipt-actions --code-coverage --skip-nx-cache
```

### Test Examples

```typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { RemissionReturnReceiptActionsComponent } from './remission-return-receipt-actions.component';

describe('RemissionReturnReceiptActionsComponent', () => {
  let component: RemissionReturnReceiptActionsComponent;
  let fixture: ComponentFixture<RemissionReturnReceiptActionsComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [RemissionReturnReceiptActionsComponent]
    }).compileComponents();

    fixture = TestBed.createComponent(RemissionReturnReceiptActionsComponent);
    component = fixture.componentInstance;
  });

  it('should disable delete button when items exist', () => {
    fixture.componentRef.setInput('remissionReturn', {
      id: 123,
      receipts: [{ id: 456, data: { items: [{ id: 1 }] } }]
    });
    fixture.detectChanges();

    const deleteBtn = fixture.nativeElement.querySelector('[data-what="return-receipt-delete-button"]');
    expect(deleteBtn?.disabled).toBe(true);
  });

  it('should emit reloadData after successful deletion', async () => {
    const reloadSpy = vi.fn();
    component.reloadData.subscribe(reloadSpy);

    await component.onDelete();

    expect(reloadSpy).toHaveBeenCalled();
  });
});
```

## Dependencies

- `@angular/core` - Angular framework
- `@angular/router` - Navigation
- `@isa/remission/data-access` - RemissionStore, RemissionReturnReceiptService, Return types
- `@isa/remission/shared/remission-start-dialog` - RemissionStartService
- `@isa/ui/buttons` - Button components
- `@isa/ui/dialog` - Confirmation dialog
- `@isa/core/tabs` - Tab ID injection
- `@isa/core/logging` - Logger service

## Architecture Notes

**State Synchronization**: Both components integrate tightly with RemissionStore to ensure UI state matches backend state.

**Navigation Integration**: Uses Angular Router and tab ID for context-aware navigation within multi-tab environments.

**Error Handling**: Comprehensive error logging with contextual information for debugging.

**User Confirmations**: Critical actions (changing remission, completing groups) require explicit user confirmation.

## License

Internal ISA Frontend library - not for external distribution.
