Hier is een concreet, schaalbaar API-contract voor jouw pricing systeem, afgestemd op:

stay_period_definition (leidend)
pricing_rate (basisprijzen)
pricing_rule (complexe regels)

Doel: snel, voorspelbaar, uitbreidbaar en goed te debuggen

🔷 0. Basisprincipes
🔑 Scheiding
Durations → configuratie
Rates → basisprijzen
Rules → dynamische logica
🔑 Idempotent & bulk-friendly
altijd bulk endpoints mogelijk
versieerbare payloads
🔑 Debug-first
pricing moet uitlegbaar zijn
🔷 1. DURATIONS (stay_period_definition)
GET /pricing/durations
[
  {
    "id": 1,
    "name": "Week",
    "duration_unit": "night",
    "duration_value": 7
  },
  {
    "id": 2,
    "name": "4 uur",
    "duration_unit": "hour",
    "duration_value": 4
  }
]
POST /pricing/durations
{
  "name": "Midweek",
  "duration_unit": "night",
  "duration_value": 4
}
PUT /pricing/durations/{id}
{
  "name": "Lang weekend",
  "duration_value": 3
}
DELETE /pricing/durations/{id}
🔷 2. RATES (basisprijzen)
🔹 GET /pricing/rates

Query:

?rentable_id=123
&from=2026-01-01
&to=2026-12-31

Response (gegroepeerd per periode):

[
  {
    "period": {
      "from": "2026-01-01",
      "to": "2026-01-31"
    },
    "rates": [
      {
        "stay_period_definition_id": 1,
        "name": "Week",
        "price": 1548.00
      },
      {
        "stay_period_definition_id": 2,
        "name": "2 weken",
        "price": 2940.00
      }
    ]
  }
]

👉 UI-ready (belangrijk)

🔹 POST /pricing/rates (bulk create/update)
{
  "rentable_id": 123,
  "period": {
    "from": "2026-01-01",
    "to": "2026-01-31"
  },
  "rates": [
    {
      "stay_period_definition_id": 1,
      "price": 1548.00
    },
    {
      "stay_period_definition_id": 2,
      "price": 2940.00
    }
  ]
}

Gedrag:

upsert per combinatie:
(rentable_id, duration, period)
🔹 PUT /pricing/rates/{id}

Alleen voor single update (optioneel)

🔹 DELETE /pricing/rates
{
  "rentable_id": 123,
  "period": {
    "from": "2026-01-01",
    "to": "2026-01-31"
  }
}

👉 verwijdert hele periode-blok

🔹 POST /pricing/rates/copy
{
  "rentable_id": 123,
  "source_period": {
    "from": "2026-01-01",
    "to": "2026-01-31"
  },
  "target_period": {
    "from": "2026-02-01",
    "to": "2026-02-28"
  },
  "adjustment": {
    "type": "percentage",
    "value": 10
  }
}
🔷 3. RULES (pricing_rule)
🔹 GET /pricing/rules
[
  {
    "id": 10,
    "name": "Last minute",
    "priority": 10,
    "stacking_mode": "stackable",
    "conditions": {...},
    "action": {...}
  }
]
🔹 POST /pricing/rules
{
  "name": "Last minute korting",
  "priority": 10,
  "stacking_mode": "stackable",

  "valid_period": {
    "from": "2026-01-01",
    "to": "2026-12-31"
  },

  "conditions": {
    "operator": "and",
    "rules": [
      {
        "field": "arrival_date",
        "operator": "<=",
        "value": "3d"
      }
    ]
  },

  "action": {
    "type": "discount_percentage",
    "value": 10
  }
}
🔹 Condition DSL (belangrijk)
{
  "operator": "and",
  "rules": [
    {
      "field": "persons",
      "operator": ">",
      "value": 4
    },
    {
      "field": "has_extra",
      "operator": "=",
      "value": "baby_bed"
    }
  ]
}
🔹 Action DSL
{
  "type": "discount_percentage",
  "value": 10
}

Andere voorbeelden:

{ "type": "surcharge_percentage", "value": 15 }

{ "type": "override_price", "value": 1200 }

{
  "type": "discount_on_product",
  "target": "sloep",
  "value": 20
}

{
  "type": "add_product",
  "product_id": 55,
  "price": 0
}
🔷 4. PRICING ENGINE (cruciaal)
🔹 POST /pricing/quote

👉 dit is je belangrijkste endpoint

{
  "rentable_id": 123,
  "arrival_date": "2026-01-10",
  "departure_date": "2026-01-17",

  "persons": 4,
  "extras": ["baby_bed"],

  "context": {
    "booking_date": "2026-01-08"
  }
}
🔹 Response
{
  "base_price": 1548.00,
  "final_price": 1393.20,

  "breakdown": [
    {
      "type": "base",
      "amount": 1548.00
    },
    {
      "type": "discount",
      "name": "Last minute",
      "amount": -154.80
    }
  ],

  "applied_rules": [10]
}
🔷 5. DEBUG ENDPOINT (must-have)
🔹 POST /pricing/debug
{
  "rentable_id": 123,
  "arrival_date": "2026-01-10",
  "departure_date": "2026-01-17",
  "persons": 4
}
🔹 Response
{
  "steps": [
    {
      "step": "select_rate",
      "result": 1548.00
    },
    {
      "step": "rule_check",
      "rule_id": 10,
      "matched": true
    },
    {
      "step": "apply_rule",
      "effect": "-10%"
    }
  ]
}

👉 dit gaat je enorm helpen bij support/debugging

🔷 6. VALIDATIE REGELS
geen overlapping rates (zelfde duration)
duration moet bestaan
rules moeten valide DSL hebben
priority bepaalt volgorde
🔷 7. SAMENVATTING

Dit contract geeft je:

✔ simpele UI integratie (period + durations)
✔ krachtige rules (DSL-based)
✔ schaalbaarheid (bulk + uitbreidbaar)
✔ debugbaarheid (breakdown + debug endpoint)

🚀 Aanrader volgende stap

De pricing engine zelf wordt nu de bottleneck.

Ik kan voor je uitwerken:

rule evaluator (performance-proof)
condition parser (DSL → executable)
stacking logic (priority + combinaties)

Dat is het moeilijkste stuk in je hele systeem.
