> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/lopiv2/invenicum/llms.txt
> Use this file to discover all available pages before exploring further.

# Loans API

> Track inventory loans, borrowers, and returns

## Overview

The Loans API manages the lending and tracking of inventory items. It supports loan creation, status management, automatic stock adjustments, and return processing. All loan operations are automatically associated with the authenticated user via JWT token.

## Endpoints

### Get All Loans

Retrieves all loans across all containers for the authenticated user (Dashboard view).

```http theme={null}
GET /loans
```

#### Authentication

The backend automatically filters loans by the `userId` extracted from the JWT token.

#### Response

<ResponseField name="data" type="Loan[]">
  Array of loan objects

  <Expandable title="Loan Object">
    <ResponseField name="id" type="integer">
      Unique identifier for the loan
    </ResponseField>

    <ResponseField name="containerId" type="integer">
      ID of the container the item belongs to
    </ResponseField>

    <ResponseField name="inventoryItemId" type="integer">
      ID of the inventory item being loaned
    </ResponseField>

    <ResponseField name="itemName" type="string">
      Name of the loaned item
    </ResponseField>

    <ResponseField name="quantity" type="integer">
      Number of units loaned (default: 1)
    </ResponseField>

    <ResponseField name="borrowerName" type="string" optional>
      Name of the person borrowing the item
    </ResponseField>

    <ResponseField name="borrowerEmail" type="string" optional>
      Email address of the borrower
    </ResponseField>

    <ResponseField name="borrowerPhone" type="string" optional>
      Phone number of the borrower
    </ResponseField>

    <ResponseField name="loanDate" type="string" format="date">
      Date when the loan was created (ISO 8601 date)
    </ResponseField>

    <ResponseField name="expectedReturnDate" type="string" format="date" optional>
      Expected return date (ISO 8601 date)
    </ResponseField>

    <ResponseField name="actualReturnDate" type="string" format="date" optional>
      Actual return date when item was returned (ISO 8601 date)
    </ResponseField>

    <ResponseField name="notes" type="string" optional>
      Additional notes about the loan
    </ResponseField>

    <ResponseField name="status" type="string">
      Current status: 'active' or 'returned'
    </ResponseField>

    <ResponseField name="userId" type="integer">
      ID of the user who created the loan
    </ResponseField>
  </Expandable>
</ResponseField>

#### Example Request

```javascript theme={null}
const response = await fetch('/loans', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN'
  }
});

const loans = await response.json();
```

#### Example Response

```json theme={null}
[
  {
    "id": 1,
    "containerId": 42,
    "inventoryItemId": 15,
    "itemName": "Laptop Dell XPS 15",
    "quantity": 1,
    "borrowerName": "John Doe",
    "borrowerEmail": "john@example.com",
    "borrowerPhone": "+1234567890",
    "loanDate": "2026-03-01",
    "expectedReturnDate": "2026-03-15",
    "actualReturnDate": null,
    "notes": "For presentation at tech conference",
    "status": "active",
    "userId": 7
  }
]
```

***

### Get Container Loans

Retrieves all loans for a specific container.

```http theme={null}
GET /containers/{containerId}/loans
```

#### Path Parameters

<ParamField path="containerId" type="integer" required>
  The ID of the container whose loans to retrieve
</ParamField>

#### Response

<ResponseField name="data" type="Loan[]">
  Array of loan objects (same structure as Get All Loans)
</ResponseField>

#### Example Request

```javascript theme={null}
const response = await fetch('/containers/42/loans', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN'
  }
});

const loans = await response.json();
```

***

### Create Loan

Creates a new loan record and automatically decrements the inventory item stock.

```http theme={null}
POST /containers/{containerId}/loans
```

#### Path Parameters

<ParamField path="containerId" type="integer" required>
  The ID of the container containing the inventory item
</ParamField>

#### Request Body

<ParamField body="inventoryItemId" type="integer" required>
  ID of the inventory item to loan
</ParamField>

<ParamField body="itemName" type="string" required>
  Name of the item being loaned
</ParamField>

<ParamField body="quantity" type="integer" default="1">
  Number of units to loan
</ParamField>

<ParamField body="borrowerName" type="string" optional>
  Name of the person borrowing the item
</ParamField>

<ParamField body="borrowerEmail" type="string" optional>
  Email address of the borrower
</ParamField>

<ParamField body="borrowerPhone" type="string" optional>
  Phone number of the borrower
</ParamField>

<ParamField body="loanDate" type="string" format="date" required>
  Date of the loan (YYYY-MM-DD)
</ParamField>

<ParamField body="expectedReturnDate" type="string" format="date" optional>
  Expected return date (YYYY-MM-DD)
</ParamField>

<ParamField body="notes" type="string" optional>
  Additional notes about the loan
</ParamField>

<ParamField body="status" type="string" default="active">
  Initial status (typically 'active')
</ParamField>

#### Response

<ResponseField name="data" type="Loan">
  The newly created loan object
</ResponseField>

#### Example Request

```javascript theme={null}
const response = await fetch('/containers/42/loans', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    inventoryItemId: 15,
    itemName: 'Laptop Dell XPS 15',
    quantity: 1,
    borrowerName: 'John Doe',
    borrowerEmail: 'john@example.com',
    borrowerPhone: '+1234567890',
    loanDate: '2026-03-01',
    expectedReturnDate: '2026-03-15',
    notes: 'For presentation at tech conference',
    status: 'active'
  })
});

const loan = await response.json();
```

#### Example Response

```json theme={null}
{
  "id": 1,
  "containerId": 42,
  "inventoryItemId": 15,
  "itemName": "Laptop Dell XPS 15",
  "quantity": 1,
  "borrowerName": "John Doe",
  "borrowerEmail": "john@example.com",
  "borrowerPhone": "+1234567890",
  "loanDate": "2026-03-01",
  "expectedReturnDate": "2026-03-15",
  "actualReturnDate": null,
  "notes": "For presentation at tech conference",
  "status": "active",
  "userId": 7
}
```

#### Error Responses

<ResponseField name="201" type="success">
  Loan created successfully
</ResponseField>

<ResponseField name="400" type="error">
  Bad request - Insufficient stock or invalid inventory item
</ResponseField>

<ResponseField name="401" type="error">
  Unauthorized - Authentication required
</ResponseField>

***

### Return Loan

Marks a loan as returned and automatically increments the inventory item stock.

```http theme={null}
PUT /containers/{containerId}/loans/{loanId}/return
```

#### Path Parameters

<ParamField path="containerId" type="integer" required>
  The ID of the container
</ParamField>

<ParamField path="loanId" type="integer" required>
  The ID of the loan to mark as returned
</ParamField>

#### Response

<ResponseField name="data" type="Loan">
  The updated loan object with status 'returned' and actualReturnDate populated
</ResponseField>

#### Example Request

```javascript theme={null}
const response = await fetch('/containers/42/loans/1/return', {
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN'
  }
});

const returnedLoan = await response.json();
```

#### Example Response

```json theme={null}
{
  "id": 1,
  "containerId": 42,
  "inventoryItemId": 15,
  "itemName": "Laptop Dell XPS 15",
  "quantity": 1,
  "borrowerName": "John Doe",
  "borrowerEmail": "john@example.com",
  "borrowerPhone": "+1234567890",
  "loanDate": "2026-03-01",
  "expectedReturnDate": "2026-03-15",
  "actualReturnDate": "2026-03-07",
  "notes": "For presentation at tech conference",
  "status": "returned",
  "userId": 7
}
```

#### Error Responses

<ResponseField name="200" type="success">
  Loan returned successfully
</ResponseField>

<ResponseField name="400" type="error">
  Bad request - Loan already returned
</ResponseField>

<ResponseField name="404" type="error">
  Loan not found
</ResponseField>

***

### Delete Loan

Deletes a loan record. Only the loan creator can delete their own loans.

```http theme={null}
DELETE /containers/{containerId}/loans/{loanId}
```

#### Path Parameters

<ParamField path="containerId" type="integer" required>
  The ID of the container
</ParamField>

<ParamField path="loanId" type="integer" required>
  The ID of the loan to delete
</ParamField>

#### Response

Returns status code 200 or 204 on successful deletion.

#### Example Request

```javascript theme={null}
const response = await fetch('/containers/42/loans/1', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN'
  }
});

if (response.ok) {
  console.log('Loan deleted successfully');
}
```

#### Error Responses

<ResponseField name="200" type="success">
  Loan deleted successfully
</ResponseField>

<ResponseField name="204" type="success">
  Loan deleted successfully (no content)
</ResponseField>

<ResponseField name="403" type="error">
  Forbidden - You can only delete your own loans
</ResponseField>

<ResponseField name="404" type="error">
  Loan not found
</ResponseField>

***

### Get Loan Statistics

Retrieves statistical summary of loans for a container.

```http theme={null}
GET /containers/{containerId}/loans-stats
```

#### Path Parameters

<ParamField path="containerId" type="integer" required>
  The ID of the container
</ParamField>

#### Response

<ResponseField name="totalLoans" type="integer">
  Total number of loans (all statuses)
</ResponseField>

<ResponseField name="activeLoans" type="integer">
  Number of currently active loans
</ResponseField>

<ResponseField name="overdueLoans" type="integer">
  Number of active loans past their expected return date
</ResponseField>

<ResponseField name="returnedLoans" type="integer">
  Number of returned loans
</ResponseField>

#### Example Request

```javascript theme={null}
const response = await fetch('/containers/42/loans-stats', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN'
  }
});

const stats = await response.json();
```

#### Example Response

```json theme={null}
{
  "totalLoans": 45,
  "activeLoans": 12,
  "overdueLoans": 3,
  "returnedLoans": 33
}
```

***

## Business Logic Notes

### Automatic Stock Management

* Creating a loan automatically decrements the inventory item's stock by the loan quantity
* Returning a loan (via the return endpoint) automatically increments the stock back
* The backend enforces stock validation - loans cannot exceed available quantity

### User Authentication

* The `userId` field is automatically populated from the JWT token during loan creation
* Users cannot specify their own `userId` in the request body
* Only loan owners can delete their loans

### Status Management

* Loans are created with status 'active'
* The return endpoint sets status to 'returned' and populates `actualReturnDate`
* Status transitions are enforced server-side

### Overdue Detection

* The `isOverdue` computed property returns true if:
  * Status is 'active' AND
  * `expectedReturnDate` exists AND
  * Current date is after `expectedReturnDate`
* Use this for UI indicators and alert generation

### Voucher IDs

* Each loan has a formatted voucher ID: `V-000001`, `V-000042`, etc.
* Generated via `formattedVoucherId` getter: pads loan ID to 6 digits
* Useful for printing and reference

### Date Handling

* All dates are stored and transmitted in ISO 8601 format (YYYY-MM-DD)
* The `toJson()` method automatically formats dates to local timezone
* Client should parse dates using `DateTime.parse()`

### Data Integrity

* Deleting a loan does not automatically restore inventory stock
* Consider implementing soft deletes for audit trails
* Loan history is valuable for analytics and reporting
