# Distribution Keys API

Distribution keys define how shared building costs are split among tenants. Each key specifies a calculation method — by surface area, number of occupants, metered consumption, equal shares, or a custom formula.

## Quick Example

```bash
curl -X POST https://api.faireplace.com/api/charges/distributions \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Répartition au prorata de la surface",
    "calculation_type": "SURFACE",
    "parameters": {
      "surface_field": "habitable_area",
      "include_annexes": false
    }
  }'
```

---

## Distribution Key Model

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | UUID | auto | Unique identifier |
| `name` | string | yes | Human-readable name |
| `calculation_type` | CalculationType | yes | How costs are calculated — see enum below |
| `formula` | string | conditional | Custom formula (required for `FORMULE_PERSONNALISEE`) |
| `parameters` | JSONB | no | Configuration parameters for the calculation |
| `validation_rules` | JSONB | no | Rules to validate inputs before calculation |
| `created_at` | datetime | auto | Creation timestamp |
| `updated_at` | datetime | auto | Last update timestamp |

---

## Calculation Types

| Value | Description | Typical Use |
|-------|-------------|-------------|
| `SURFACE` | Pro rata by habitable surface area (m²) | General charges, common area maintenance |
| `OCCUPANT` | Pro rata by number of occupants | Water consumption, waste collection |
| `CONSOMMATION_MESUREE` | Based on individual meter readings | Heating with individual meters, hot water |
| `NOMBRE_EQUIPEMENTS` | Based on equipment count per unit | Radiator count for heating charges |
| `MILLIEME` | By co-ownership shares (tantièmes/millièmes) | Co-ownership charges (copropriété) |
| `PARTS_EGALES` | Equal split among all tenants | Shared antenna, intercom maintenance |
| `FORMULE_PERSONNALISEE` | Custom formula defined by the manager | Complex or hybrid distribution rules |

### Predefined System Keys

The API provides 6 predefined distribution keys that cannot be deleted:

| System Key | Calculation Type | Description |
|------------|-----------------|-------------|
| Surface habitable | `SURFACE` | Split by habitable area |
| Nombre d'occupants | `OCCUPANT` | Split by occupant count |
| Tantièmes | `MILLIEME` | Split by co-ownership shares |
| Parts égales | `PARTS_EGALES` | Equal split |
| Compteur individuel | `CONSOMMATION_MESUREE` | Based on meter readings |
| Nombre de radiateurs | `NOMBRE_EQUIPEMENTS` | Based on radiator count |

System keys can be used directly when creating [place services](/properties/services) or [lease charges](/leases/charges).

---

## Endpoints

### List Distribution Keys

**GET** `/api/charges/distributions`

Returns all distribution keys (system + custom).

**Response:** `200 OK`
```json
[
  {
    "id": "770e8400-e29b-41d4-a716-446655440001",
    "name": "Surface habitable",
    "calculation_type": "SURFACE",
    "formula": null,
    "parameters": {
      "surface_field": "habitable_area",
      "include_annexes": false
    },
    "validation_rules": null,
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:00:00Z"
  },
  {
    "id": "770e8400-e29b-41d4-a716-446655440002",
    "name": "Nombre d'occupants",
    "calculation_type": "OCCUPANT",
    "formula": null,
    "parameters": {},
    "validation_rules": null,
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:00:00Z"
  }
]
```

### Create Distribution Key

**POST** `/api/charges/distributions`

Create a custom distribution key.

**Request Body:**
```json
{
  "name": "Répartition chauffage hybride",
  "calculation_type": "FORMULE_PERSONNALISEE",
  "formula": "(surface * 0.6) + (occupants * 0.4)",
  "parameters": {
    "surface_weight": 0.6,
    "occupant_weight": 0.4
  },
  "validation_rules": {
    "min_surface": 9,
    "max_occupants": 20
  }
}
```

**Response:** `201 Created`
Returns the created distribution key.

### Get Distribution Key

**GET** `/api/charges/distributions/{id}`

**Path Parameters:**
- `id` (UUID): The distribution key ID

**Response:** `200 OK`
Returns the distribution key object.

### Update Distribution Key

**PUT** `/api/charges/distributions/{id}`

Update a custom distribution key. System keys cannot be updated — returns `403 Forbidden`.

**Path Parameters:**
- `id` (UUID): The distribution key ID

**Request Body:**
```json
{
  "name": "Répartition chauffage hybride (v2)",
  "formula": "(surface * 0.7) + (occupants * 0.3)",
  "parameters": {
    "surface_weight": 0.7,
    "occupant_weight": 0.3
  }
}
```

**Response:** `200 OK`
Returns the updated distribution key.

### Delete Distribution Key

**DELETE** `/api/charges/distributions/{id}`

Delete a custom distribution key. System keys cannot be deleted — returns `403 Forbidden`. Keys referenced by active services or charges return `409 Conflict`.

**Path Parameters:**
- `id` (UUID): The distribution key ID

**Response:** `204 No Content`

### Calculate Distribution

**POST** `/api/charges/distributions/{id}/calculate`

Run the distribution calculation for a given set of inputs. Returns the share for each unit/tenant.

**Path Parameters:**
- `id` (UUID): The distribution key ID

**Request Body:**
```json
{
  "place_id": "550e8400-e29b-41d4-a716-446655440000",
  "total_amount": 12000.00,
  "calculation_date": "2024-01-01"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `place_id` | UUID | yes | ID of the place for which to calculate the distribution |
| `total_amount` | decimal | yes | Total amount to distribute |
| `calculation_date` | date | no | Calculation date |
| `parameters` | object | no | Additional parameters for the calculation |

**Response:** `200 OK`
```json
{
  "distribution_key_id": "770e8400-e29b-41d4-a716-446655440001",
  "total_amount": 12000.00,
  "distributions": [
    {
      "unit_id": "550e8400-e29b-41d4-a716-446655440001",
      "unit_name": "Apt 301",
      "amount": 4000.00,
      "percentage": 33.33,
      "calculation_details": "Surface: 45m² / 135m² total"
    },
    {
      "unit_id": "550e8400-e29b-41d4-a716-446655440002",
      "unit_name": "Apt 302",
      "amount": 8000.00,
      "percentage": 66.67,
      "calculation_details": "Surface: 90m² / 135m² total"
    }
  ]
}
```

---

### Filtered List

**GET** `/api/charges/distributions/filtered`

Returns distribution keys filtered by calculation type or other criteria.

**Query Parameters:**
- `calculation_type` (optional): Filter by calculation type (e.g., `SURFACE`, `OCCUPANT`)
- `place_id` (optional, UUID): Filter by place
- `estate_id` (optional, UUID): Filter by estate
- `charge_category_id` (optional, UUID): Filter by charge category

**Response:** `200 OK`
Returns an array of matching distribution keys.

### Check Name Uniqueness

**GET** `/api/charges/distributions/check-name/{name}`

Check if a distribution key name is already in use. Useful for UI validation before creating a new key.

**Path Parameters:**
- `name` (string): The name to check

**Response:** `200 OK`
```json
{
  "is_unique": true
}
```

---

## Distribution Type × Billing Mode Constraint

When a distribution key is used in a [lease charge](/leases/charges), the distribution type must be compatible with the billing mode:

| Distribution Type | Allowed Billing Modes |
|---|---|
| `CONSOMMATION_MESUREE` | `RELEVE_DIRECT`, `PROVISION` only |
| All other types | `PROVISION`, `FORFAIT` |
| Any type | `DEPENSE_REELLE` (always allowed) |

The API validates this when creating a lease charge — see [Charges API](/leases/charges#validation-rules) for the full validation pipeline.

---

## Error Responses

| Status | Condition |
|--------|-----------|
| `400 Bad Request` | Missing required fields, or `FORMULE_PERSONNALISEE` without `formula` |
| `403 Forbidden` | Attempting to update or delete a system key |
| `404 Not Found` | Distribution key not found |
| `409 Conflict` | Cannot delete — key is referenced by active services or charges |
| `422 Unprocessable Entity` | Calculation failed — invalid formula or missing unit data |

---

## Common Workflows

### Set up cost distribution for a building

1. Review predefined system keys (`GET /api/charges/distributions`)
2. Create custom keys if needed (`POST /api/charges/distributions`)
3. Assign keys to [place services](/properties/services) as `default_distribution_key_id`
4. When creating [lease charges](/leases/charges), the distribution key determines each tenant's share

### Test a distribution before applying it

Use the calculate endpoint to preview how costs would be split:

```bash
curl -X POST https://api.faireplace.com/api/charges/distributions/<key_id>/calculate \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "place_id": "550e8400-e29b-41d4-a716-446655440000",
    "total_amount": 5000.00,
    "calculation_date": "2024-01-01"
  }'
```

---

## Related

- **[Place Services](/properties/services)** — Link chargeable services to places
- **[Charges](/leases/charges)** — Billing modes, charge categories, and lease charge management
- **[Property Overview](/properties/overview)** — Property hierarchy and structure
