openapi: 3.1.0
info:
  title: OpenBusinessAPI (OBAPI)
  description: |
    Open, standardized API specification for accessing business documents
    (invoices, orders, proposals, etc.) from any OBAPI-compatible provider.

    This specification covers all three tiers:
    - **Tier 1 -- Core**: essential B2B exchange (invoices, orders, products...)
    - **Tier 2 -- Extended**: supplier flows and service management
    - **Tier 3 -- Advanced**: projects, manufacturing, associations

    More information: https://obapi.org
  version: "1.0.0-draft"
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
  contact:
    name: OpenBusinessAPI
    url: https://github.com/OpenBusinessAPI
    email: contact@obapi.org

servers:
  - url: https://{provider}/obapi/v1
    description: Any OBAPI-compatible provider
    variables:
      provider:
        default: demo.obapi.org
        description: Provider hostname

security:
  - BearerAuth: []

tags:
  - name: Discovery
    description: Server capabilities discovery
  - name: Thirdparty
    description: Provider identity
  - name: Contact
    description: Contact persons
  - name: Product
    description: Product and service catalog
  - name: Proposal
    description: Sales quotations / devis
  - name: Order
    description: Customer orders
  - name: Invoice
    description: Customer invoices
  - name: CreditNote
    description: Credit notes / avoirs
  - name: Shipment
    description: Delivery / despatch advice
  - name: Download
    description: Document download (PDF)
  - name: Dictionary
    description: Reference data (countries, payment terms, etc.)
  # Tier 2
  - name: SupplierProposal
    description: Request for quotation to supplier
  - name: SupplierOrder
    description: Purchase orders
  - name: SupplierInvoice
    description: Supplier invoices received
  - name: Reception
    description: Goods receipt
  - name: Contract
    description: Service contracts / subscriptions
  - name: Intervention
    description: Service intervention reports
  - name: Ticket
    description: Support tickets
  # Tier 3
  - name: Project
    description: Shared project tracking
  - name: Task
    description: Project tasks
  - name: ExpenseReport
    description: Employee expense claims
  - name: BOM
    description: Bill of Materials
  - name: ManufacturingOrder
    description: Manufacturing orders
  - name: Warehouse
    description: Stock locations
  - name: Member
    description: Association / cooperative members
  - name: Category
    description: Shared classification

paths:
  # ─── Discovery ──────────────────────────────────────────────────────
  /:
    get:
      operationId: getDiscovery
      tags: [Discovery]
      summary: Discover server capabilities
      security: []
      responses:
        "200":
          description: Server capabilities
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DiscoveryResponse"
        "404":
          description: OBAPI not available at this URL
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  # ─── Thirdparty ────────────────────────────────────────────────────
  /thirdparty:
    get:
      operationId: getThirdparty
      tags: [Thirdparty]
      summary: Get the provider's identity
      responses:
        "200":
          description: Provider identity
          content:
            application/json:
              schema:
                type: object
                properties:
                  thirdparty:
                    $ref: "#/components/schemas/Thirdparty"
        "401":
          $ref: "#/components/responses/Unauthorized"

  # ─── Contacts ──────────────────────────────────────────────────────
  /contacts:
    get:
      operationId: listContacts
      tags: [Contact]
      summary: List contacts
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
      responses:
        "200":
          description: Contact list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/Contact"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /contacts/{id}:
    get:
      operationId: getContact
      tags: [Contact]
      summary: Get a single contact
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Contact details
          content:
            application/json:
              schema:
                type: object
                properties:
                  contact:
                    $ref: "#/components/schemas/Contact"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Products ──────────────────────────────────────────────────────
  /products:
    get:
      operationId: listProducts
      tags: [Product]
      summary: List products
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/search"
        - name: type
          in: query
          schema:
            type: string
            enum: [product, service]
          description: Filter by product type
        - name: for_sale
          in: query
          schema:
            type: boolean
          description: Filter products available for sale
        - name: for_purchase
          in: query
          schema:
            type: boolean
          description: Filter products available for purchase
      responses:
        "200":
          description: Product list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/Product"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /products/{id}:
    get:
      operationId: getProduct
      tags: [Product]
      summary: Get a single product
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Product details
          content:
            application/json:
              schema:
                type: object
                properties:
                  product:
                    $ref: "#/components/schemas/Product"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Proposals ─────────────────────────────────────────────────────
  /proposals:
    get:
      operationId: listProposals
      tags: [Proposal]
      summary: List proposals
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, signed, refused, billed]
      responses:
        "200":
          description: Proposal list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/ProposalSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /proposals/{id}:
    get:
      operationId: getProposal
      tags: [Proposal]
      summary: Get a single proposal with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Proposal details
          content:
            application/json:
              schema:
                type: object
                properties:
                  proposal:
                    $ref: "#/components/schemas/Proposal"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Orders ────────────────────────────────────────────────────────
  /orders:
    get:
      operationId: listOrders
      tags: [Order]
      summary: List orders
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, in_progress, delivered, cancelled]
      responses:
        "200":
          description: Order list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/OrderSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /orders/{id}:
    get:
      operationId: getOrder
      tags: [Order]
      summary: Get a single order with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Order details
          content:
            application/json:
              schema:
                type: object
                properties:
                  order:
                    $ref: "#/components/schemas/Order"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Invoices ──────────────────────────────────────────────────────
  /invoices:
    get:
      operationId: listInvoices
      tags: [Invoice]
      summary: List invoices
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, paid, abandoned]
      responses:
        "200":
          description: Invoice list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/InvoiceSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /invoices/{id}:
    get:
      operationId: getInvoice
      tags: [Invoice]
      summary: Get a single invoice with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Invoice details
          content:
            application/json:
              schema:
                type: object
                properties:
                  invoice:
                    $ref: "#/components/schemas/Invoice"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Credit Notes ──────────────────────────────────────────────────
  /creditnotes:
    get:
      operationId: listCreditNotes
      tags: [CreditNote]
      summary: List credit notes
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, paid, abandoned]
      responses:
        "200":
          description: Credit note list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/InvoiceSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /creditnotes/{id}:
    get:
      operationId: getCreditNote
      tags: [CreditNote]
      summary: Get a single credit note with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Credit note details
          content:
            application/json:
              schema:
                type: object
                properties:
                  creditnote:
                    $ref: "#/components/schemas/Invoice"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Shipments ─────────────────────────────────────────────────────
  /shipments:
    get:
      operationId: listShipments
      tags: [Shipment]
      summary: List shipments
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, closed]
      responses:
        "200":
          description: Shipment list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/ShipmentSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /shipments/{id}:
    get:
      operationId: getShipment
      tags: [Shipment]
      summary: Get a single shipment with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Shipment details
          content:
            application/json:
              schema:
                type: object
                properties:
                  shipment:
                    $ref: "#/components/schemas/Shipment"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Download ──────────────────────────────────────────────────────
  /download/{id}:
    get:
      operationId: downloadDocument
      tags: [Download]
      summary: Download a document (PDF)
      parameters:
        - $ref: "#/components/parameters/id"
        - name: type
          in: query
          required: true
          schema:
            type: string
            enum:
              - invoice
              - creditnote
              - order
              - proposal
              - shipment
              - supplier-invoice
              - supplier-order
              - supplier-proposal
              - reception
              - contract
              - intervention
              - expense-report
          description: Object type to download
        - name: format
          in: query
          schema:
            type: string
            default: pdf
          description: Output format
      responses:
        "200":
          description: Binary document
          headers:
            Content-Disposition:
              schema:
                type: string
              example: 'attachment; filename="FA2405-2401.pdf"'
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/DocumentNotFound"

  # ─── Dictionaries ──────────────────────────────────────────────────
  # ═══════════════════════════════════════════════════════════════════
  # TIER 2 -- Extended
  # ═══════════════════════════════════════════════════════════════════

  # ─── Supplier Proposals ────────────────────────────────────────────
  /supplier-proposals:
    get:
      operationId: listSupplierProposals
      tags: [SupplierProposal]
      summary: List supplier proposals
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, signed, refused, closed]
      responses:
        "200":
          description: Supplier proposal list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/SupplierProposalSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /supplier-proposals/{id}:
    get:
      operationId: getSupplierProposal
      tags: [SupplierProposal]
      summary: Get a single supplier proposal with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Supplier proposal details
          content:
            application/json:
              schema:
                type: object
                properties:
                  supplier_proposal:
                    $ref: "#/components/schemas/SupplierProposal"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Supplier Orders ───────────────────────────────────────────────
  /supplier-orders:
    get:
      operationId: listSupplierOrders
      tags: [SupplierOrder]
      summary: List supplier orders
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, approved, ordered, received_partially, received_completely, cancelled, refused]
      responses:
        "200":
          description: Supplier order list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/SupplierOrderSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /supplier-orders/{id}:
    get:
      operationId: getSupplierOrder
      tags: [SupplierOrder]
      summary: Get a single supplier order with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Supplier order details
          content:
            application/json:
              schema:
                type: object
                properties:
                  supplier_order:
                    $ref: "#/components/schemas/SupplierOrder"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Supplier Invoices ─────────────────────────────────────────────
  /supplier-invoices:
    get:
      operationId: listSupplierInvoices
      tags: [SupplierInvoice]
      summary: List supplier invoices
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, paid, abandoned]
      responses:
        "200":
          description: Supplier invoice list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/SupplierInvoiceSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /supplier-invoices/{id}:
    get:
      operationId: getSupplierInvoice
      tags: [SupplierInvoice]
      summary: Get a single supplier invoice with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Supplier invoice details
          content:
            application/json:
              schema:
                type: object
                properties:
                  supplier_invoice:
                    $ref: "#/components/schemas/SupplierInvoice"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Receptions ────────────────────────────────────────────────────
  /receptions:
    get:
      operationId: listReceptions
      tags: [Reception]
      summary: List receptions
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, closed]
      responses:
        "200":
          description: Reception list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/ReceptionSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /receptions/{id}:
    get:
      operationId: getReception
      tags: [Reception]
      summary: Get a single reception with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Reception details
          content:
            application/json:
              schema:
                type: object
                properties:
                  reception:
                    $ref: "#/components/schemas/Reception"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Contracts ─────────────────────────────────────────────────────
  /contracts:
    get:
      operationId: listContracts
      tags: [Contract]
      summary: List contracts
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, closed]
      responses:
        "200":
          description: Contract list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/ContractSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /contracts/{id}:
    get:
      operationId: getContract
      tags: [Contract]
      summary: Get a single contract with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Contract details
          content:
            application/json:
              schema:
                type: object
                properties:
                  contract:
                    $ref: "#/components/schemas/Contract"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Interventions ─────────────────────────────────────────────────
  /interventions:
    get:
      operationId: listInterventions
      tags: [Intervention]
      summary: List interventions
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, done, billed]
      responses:
        "200":
          description: Intervention list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/InterventionSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /interventions/{id}:
    get:
      operationId: getIntervention
      tags: [Intervention]
      summary: Get a single intervention with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Intervention details
          content:
            application/json:
              schema:
                type: object
                properties:
                  intervention:
                    $ref: "#/components/schemas/Intervention"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Tickets ───────────────────────────────────────────────────────
  /tickets:
    get:
      operationId: listTickets
      tags: [Ticket]
      summary: List tickets
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [new, read, assigned, in_progress, waiting, resolved, closed, cancelled]
        - name: severity
          in: query
          schema:
            type: string
          description: Filter by severity code
      responses:
        "200":
          description: Ticket list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/TicketSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /tickets/{id}:
    get:
      operationId: getTicket
      tags: [Ticket]
      summary: Get a single ticket
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Ticket details
          content:
            application/json:
              schema:
                type: object
                properties:
                  ticket:
                    $ref: "#/components/schemas/Ticket"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ═══════════════════════════════════════════════════════════════════
  # TIER 3 -- Advanced
  # ═══════════════════════════════════════════════════════════════════

  # ─── Projects ──────────────────────────────────────────────────────
  /projects:
    get:
      operationId: listProjects
      tags: [Project]
      summary: List projects
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, closed]
      responses:
        "200":
          description: Project list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/ProjectSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /projects/{id}:
    get:
      operationId: getProject
      tags: [Project]
      summary: Get a single project with tasks
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Project details
          content:
            application/json:
              schema:
                type: object
                properties:
                  project:
                    $ref: "#/components/schemas/Project"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Tasks ─────────────────────────────────────────────────────────
  /tasks:
    get:
      operationId: listTasks
      tags: [Task]
      summary: List tasks
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/sort"
        - name: project_id
          in: query
          schema:
            type: string
          description: Filter by project
        - name: status
          in: query
          schema:
            type: string
          description: Filter by status
      responses:
        "200":
          description: Task list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/TaskSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /tasks/{id}:
    get:
      operationId: getTask
      tags: [Task]
      summary: Get a single task
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Task details
          content:
            application/json:
              schema:
                type: object
                properties:
                  task:
                    $ref: "#/components/schemas/Task"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /projects/{id}/tasks:
    get:
      operationId: listProjectTasks
      tags: [Task]
      summary: List tasks for a specific project
      parameters:
        - $ref: "#/components/parameters/id"
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/sort"
      responses:
        "200":
          description: Task list for the project
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/TaskSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Expense Reports ───────────────────────────────────────────────
  /expense-reports:
    get:
      operationId: listExpenseReports
      tags: [ExpenseReport]
      summary: List expense reports
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, approved, paid, refused, cancelled]
      responses:
        "200":
          description: Expense report list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/ExpenseReportSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /expense-reports/{id}:
    get:
      operationId: getExpenseReport
      tags: [ExpenseReport]
      summary: Get a single expense report with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Expense report details
          content:
            application/json:
              schema:
                type: object
                properties:
                  expense_report:
                    $ref: "#/components/schemas/ExpenseReport"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── BOMs ──────────────────────────────────────────────────────────
  /boms:
    get:
      operationId: listBoms
      tags: [BOM]
      summary: List bills of materials
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, closed]
        - name: product_ref
          in: query
          schema:
            type: string
          description: Filter by finished product reference
      responses:
        "200":
          description: BOM list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/BomSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /boms/{id}:
    get:
      operationId: getBom
      tags: [BOM]
      summary: Get a single BOM with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: BOM details
          content:
            application/json:
              schema:
                type: object
                properties:
                  bom:
                    $ref: "#/components/schemas/Bom"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Manufacturing Orders ──────────────────────────────────────────
  /manufacturing-orders:
    get:
      operationId: listManufacturingOrders
      tags: [ManufacturingOrder]
      summary: List manufacturing orders
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/date_start"
        - $ref: "#/components/parameters/date_end"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, in_progress, produced, cancelled]
      responses:
        "200":
          description: Manufacturing order list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/ManufacturingOrderSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /manufacturing-orders/{id}:
    get:
      operationId: getManufacturingOrder
      tags: [ManufacturingOrder]
      summary: Get a single manufacturing order with lines
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Manufacturing order details
          content:
            application/json:
              schema:
                type: object
                properties:
                  manufacturing_order:
                    $ref: "#/components/schemas/ManufacturingOrder"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Warehouses ────────────────────────────────────────────────────
  /warehouses:
    get:
      operationId: listWarehouses
      tags: [Warehouse]
      summary: List warehouses
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [open, closed]
      responses:
        "200":
          description: Warehouse list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/Warehouse"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /warehouses/{id}:
    get:
      operationId: getWarehouse
      tags: [Warehouse]
      summary: Get a single warehouse
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Warehouse details
          content:
            application/json:
              schema:
                type: object
                properties:
                  warehouse:
                    $ref: "#/components/schemas/Warehouse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Members ───────────────────────────────────────────────────────
  /members:
    get:
      operationId: listMembers
      tags: [Member]
      summary: List members
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/sort"
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, validated, excluded, resigned]
        - name: type
          in: query
          schema:
            type: string
          description: Filter by member type
      responses:
        "200":
          description: Member list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/MemberSummary"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /members/{id}:
    get:
      operationId: getMember
      tags: [Member]
      summary: Get a single member
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Member details
          content:
            application/json:
              schema:
                type: object
                properties:
                  member:
                    $ref: "#/components/schemas/Member"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ─── Categories ────────────────────────────────────────────────────
  /categories:
    get:
      operationId: listCategories
      tags: [Category]
      summary: List categories
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/per_page"
        - $ref: "#/components/parameters/sort"
        - name: type
          in: query
          schema:
            type: string
            enum: [product, thirdparty, contact, member, project]
          description: Filter by category type
        - name: parent_id
          in: query
          schema:
            type: string
          description: Filter by parent category
      responses:
        "200":
          description: Category list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/Category"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /categories/{id}:
    get:
      operationId: getCategory
      tags: [Category]
      summary: Get a single category
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        "200":
          description: Category details
          content:
            application/json:
              schema:
                type: object
                properties:
                  category:
                    $ref: "#/components/schemas/Category"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  # ═══════════════════════════════════════════════════════════════════
  # Dictionaries (shared)
  # ═══════════════════════════════════════════════════════════════════

  /dictionaries:
    get:
      operationId: listDictionaries
      tags: [Dictionary]
      summary: List available dictionaries
      responses:
        "200":
          description: Dictionary list
          content:
            application/json:
              schema:
                type: object
                properties:
                  dictionaries:
                    type: array
                    items:
                      type: string
                    example:
                      - countries
                      - payment_terms
                      - payment_methods
                      - shipping_methods
                      - units
                      - currencies
                      - incoterms
        "401":
          $ref: "#/components/responses/Unauthorized"

  /dictionaries/{name}:
    get:
      operationId: getDictionary
      tags: [Dictionary]
      summary: Get all entries for a dictionary
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
            enum:
              - countries
              - states
              - civilities
              - payment_terms
              - payment_methods
              - shipping_methods
              - units
              - currencies
              - incoterms
      responses:
        "200":
          description: Dictionary entries
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DictionaryResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

# ═══════════════════════════════════════════════════════════════════════
# COMPONENTS
# ═══════════════════════════════════════════════════════════════════════
components:

  # ─── Security ────────────────────────────────────────────────────
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: |
        API key obtained from the provider. The enrollment process
        (how you get the key) is outside the scope of OBAPI.

  # ─── Parameters ──────────────────────────────────────────────────
  parameters:
    id:
      name: id
      in: path
      required: true
      schema:
        type: string
      description: Object unique identifier

    page:
      name: page
      in: query
      schema:
        type: integer
        minimum: 1
        default: 1
      description: Page number (1-based)

    per_page:
      name: per_page
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 200
        default: 50
      description: Items per page (max 200)

    date_start:
      name: date_start
      in: query
      schema:
        type: string
        format: date
      description: Filter from date (YYYY-MM-DD, inclusive)

    date_end:
      name: date_end
      in: query
      schema:
        type: string
        format: date
      description: Filter to date (YYYY-MM-DD, inclusive)

    search:
      name: search
      in: query
      schema:
        type: string
      description: Free-text search in ref, label, description

    sort:
      name: sort
      in: query
      schema:
        type: string
        enum: [date_asc, date_desc, ref_asc, ref_desc]
        default: date_desc
      description: Sort order

  # ─── Responses ───────────────────────────────────────────────────
  responses:
    Unauthorized:
      description: Invalid or missing authentication token
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            error:
              type: authentication_error
              code: INVALID_TOKEN
              message: Invalid or expired API token

    Forbidden:
      description: Insufficient permissions
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            error:
              type: authorization_error
              code: INSUFFICIENT_PERMISSIONS
              message: Your token does not have access to this resource

    NotFound:
      description: Object not found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            error:
              type: not_found
              code: OBJECT_NOT_FOUND
              message: Requested object does not exist

    DocumentNotFound:
      description: No document available for this object
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            error:
              type: not_found
              code: DOCUMENT_NOT_FOUND
              message: No document available for this object

  # ─── Schemas ─────────────────────────────────────────────────────
  schemas:

    # ── Error ──────────────────────────────────────────────────────
    ErrorResponse:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [type, code, message]
          properties:
            type:
              type: string
              enum:
                - bad_request
                - authentication_error
                - authorization_error
                - not_found
                - method_not_allowed
                - validation_error
                - rate_limit
                - server_error
                - not_implemented
            code:
              type: string
            message:
              type: string

    # ── Pagination ─────────────────────────────────────────────────
    Pagination:
      type: object
      required: [page, per_page, total_items, total_pages]
      properties:
        page:
          type: integer
          example: 1
        per_page:
          type: integer
          example: 50
        total_items:
          type: integer
          example: 234
        total_pages:
          type: integer
          example: 5

    # ── Discovery ──────────────────────────────────────────────────
    DiscoveryResponse:
      type: object
      required: [obapi_version, provider, capabilities]
      properties:
        obapi_version:
          type: string
          example: "1.0"
        provider:
          type: object
          properties:
            name:
              type: string
              example: "CAP-REL"
            website:
              type: string
              format: uri
              example: "https://cap-rel.fr"
            contact_email:
              type: string
              format: email
        software:
          type: object
          properties:
            name:
              type: string
              example: "Dolibarr"
            version:
              type: string
              example: "20.0.0"
        capabilities:
          type: array
          items:
            type: string
          example:
            - thirdparty
            - contacts
            - products
            - proposals
            - orders
            - invoices
            - creditnotes
            - shipments
            - download
        pagination:
          type: object
          properties:
            default_per_page:
              type: integer
              example: 50
            max_per_page:
              type: integer
              example: 200

    # ── Thirdparty ─────────────────────────────────────────────────
    Thirdparty:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
          example: "CAP-REL"
        address:
          type: string
        zip:
          type: string
        city:
          type: string
        state:
          type: string
        country:
          type: string
          description: ISO 3166-1 alpha-2
          example: "FR"
        phone:
          type: string
        email:
          type: string
          format: email
        website:
          type: string
          format: uri
        logo:
          type: string
          description: Base64 encoded image (data:image/png;base64,...)
        vat_number:
          type: string
          description: VAT identification number
          example: "FR12345678901"
        siret:
          type: string
          description: SIRET number (FR specific)
        siren:
          type: string
          description: SIREN number (FR specific)
        ape_code:
          type: string
          description: APE/NAF code (FR specific)
        rcs:
          type: string
          description: RCS registration city (FR specific)
        capital:
          type: string
        legal_form:
          type: string
          example: "SAS"
        currency_code:
          type: string
          description: ISO 4217
          example: "EUR"
        language:
          type: string
          example: "fr_FR"
        public_note:
          type: string

    # ── Contact ────────────────────────────────────────────────────
    Contact:
      type: object
      properties:
        id:
          type: string
        civility:
          type: string
          example: "MR"
        lastname:
          type: string
        firstname:
          type: string
        address:
          type: string
        zip:
          type: string
        city:
          type: string
        state:
          type: string
        country:
          type: string
          description: ISO 3166-1 alpha-2
        phone:
          type: string
        mobile:
          type: string
        email:
          type: string
          format: email
        public_note:
          type: string

    # ── Product ────────────────────────────────────────────────────
    Product:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
          example: "PROD-001"
        label:
          type: string
          example: "Consulting service"
        description:
          type: string
        type:
          type: string
          enum: [product, service]
        price_excl_tax:
          type: string
          example: "100.00"
        price_incl_tax:
          type: string
          example: "120.00"
        price_min_excl_tax:
          type: string
        price_min_incl_tax:
          type: string
        price_base_type:
          type: string
          enum: [HT, TTC]
          description: "HT = excl. tax, TTC = incl. tax"
        vat_rate:
          type: string
          example: "20.000"
        barcode:
          type: string
        weight:
          type: string
        weight_unit:
          type: string
        length:
          type: string
        width:
          type: string
        height:
          type: string
        stock:
          type: string
          description: Current stock quantity
        stock_alert_threshold:
          type: string
        for_sale:
          type: boolean
        for_purchase:
          type: boolean
        created_at:
          type: string
          format: date-time
        public_note:
          type: string

    # ── Common Line ────────────────────────────────────────────────
    DocumentLine:
      type: object
      description: Common line structure for Proposal, Order, Invoice, CreditNote
      properties:
        id:
          type: string
        position:
          type: integer
          description: Line order (1-based)
        product_ref:
          type: string
        product_label:
          type: string
        product_type:
          type: string
          enum: [product, service]
        description:
          type: string
          description: Line description (may differ from product label)
        quantity:
          type: string
        unit:
          type: string
          description: Unit label (piece, hour, kg, etc.)
        unit_price_excl_tax:
          type: string
        discount_percent:
          type: string
        vat_rate:
          type: string
          example: "20.000"
        total_excl_tax:
          type: string
        total_vat:
          type: string
        total_incl_tax:
          type: string
        date_start:
          type: string
          format: date
          description: Service start date
        date_end:
          type: string
          format: date
          description: Service end date
        multicurrency_code:
          type: string
        multicurrency_unit_price:
          type: string
        multicurrency_total_excl_tax:
          type: string
        multicurrency_total_vat:
          type: string
        multicurrency_total_incl_tax:
          type: string

    # ── Multicurrency fields (reusable) ────────────────────────────
    MulticurrencyFields:
      type: object
      properties:
        multicurrency_code:
          type: string
          description: ISO 4217
        multicurrency_total_excl_tax:
          type: string
        multicurrency_total_vat:
          type: string
        multicurrency_total_incl_tax:
          type: string

    # ── Proposal ───────────────────────────────────────────────────
    ProposalSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        customer_ref:
          type: string
        date_proposal:
          type: string
          format: date
        date_expiry:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, signed, refused, billed]
        total_excl_tax:
          type: string
        total_vat:
          type: string
        total_incl_tax:
          type: string

    Proposal:
      allOf:
        - $ref: "#/components/schemas/ProposalSummary"
        - type: object
          properties:
            date_delivery:
              type: string
              format: date
            signed_at:
              type: string
              format: date-time
            validated_at:
              type: string
              format: date-time
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            payment_terms:
              type: string
            payment_method:
              type: string
            multicurrency_code:
              type: string
            multicurrency_total_excl_tax:
              type: string
            multicurrency_total_vat:
              type: string
            multicurrency_total_incl_tax:
              type: string
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/DocumentLine"

    # ── Order ──────────────────────────────────────────────────────
    OrderSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        customer_ref:
          type: string
        date_order:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, in_progress, delivered, cancelled]
        is_billed:
          type: boolean
        total_excl_tax:
          type: string
        total_vat:
          type: string
        total_incl_tax:
          type: string

    Order:
      allOf:
        - $ref: "#/components/schemas/OrderSummary"
        - type: object
          properties:
            date_delivery:
              type: string
              format: date
            validated_at:
              type: string
              format: date-time
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            payment_terms:
              type: string
            payment_method:
              type: string
            shipping_method:
              type: string
            multicurrency_code:
              type: string
            multicurrency_total_excl_tax:
              type: string
            multicurrency_total_vat:
              type: string
            multicurrency_total_incl_tax:
              type: string
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/DocumentLine"

    # ── Invoice ────────────────────────────────────────────────────
    InvoiceSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
          example: "FA2405-2401"
        customer_ref:
          type: string
        date_invoice:
          type: string
          format: date
        date_due:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, paid, abandoned]
        total_excl_tax:
          type: string
          example: "1527.00"
        total_vat:
          type: string
          example: "305.40"
        total_incl_tax:
          type: string
          example: "1832.40"

    Invoice:
      allOf:
        - $ref: "#/components/schemas/InvoiceSummary"
        - type: object
          properties:
            type:
              type: string
              enum: [standard, replacement, credit_note, deposit, situation]
            date_delivery:
              type: string
              format: date
            validated_at:
              type: string
              format: date-time
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            payment_terms:
              type: string
            payment_method:
              type: string
            revenue_stamp:
              type: string
            multicurrency_code:
              type: string
            multicurrency_total_excl_tax:
              type: string
            multicurrency_total_vat:
              type: string
            multicurrency_total_incl_tax:
              type: string
            close_code:
              type: string
            close_note:
              type: string
            related_invoice_ref:
              type: string
              description: Original invoice reference (for credit notes)
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/DocumentLine"
            customer:
              $ref: "#/components/schemas/Thirdparty"
            supplier:
              $ref: "#/components/schemas/Thirdparty"

    # ── Shipment ───────────────────────────────────────────────────
    ShipmentSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        date_shipment:
          type: string
          format: date
        date_delivery:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, closed]
        tracking_number:
          type: string
        order_ref:
          type: string

    ShipmentLine:
      type: object
      properties:
        id:
          type: string
        product_ref:
          type: string
        product_label:
          type: string
        quantity:
          type: string
        warehouse:
          type: string
        position:
          type: integer

    Shipment:
      allOf:
        - $ref: "#/components/schemas/ShipmentSummary"
        - type: object
          properties:
            customer_ref:
              type: string
            validated_at:
              type: string
              format: date-time
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            tracking_url:
              type: string
              format: uri
            shipping_method:
              type: string
            weight:
              type: string
            weight_units:
              type: string
            width:
              type: string
            height:
              type: string
            depth:
              type: string
            billed:
              type: boolean
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/ShipmentLine"

    # ── Dictionary ─────────────────────────────────────────────────
    DictionaryEntry:
      type: object
      required: [code, label]
      properties:
        code:
          type: string
          example: "30D"
        label:
          type: string
          example: "Net 30 days"

    DictionaryResponse:
      type: object
      required: [dictionary, items]
      properties:
        dictionary:
          type: string
          example: "payment_terms"
        items:
          type: array
          items:
            $ref: "#/components/schemas/DictionaryEntry"

    # ══════════════════════════════════════════════════════════════════
    # TIER 2 SCHEMAS
    # ══════════════════════════════════════════════════════════════════

    # ── Supplier Proposal ──────────────────────────────────────────
    SupplierProposalSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        supplier_ref:
          type: string
        date_proposal:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, signed, refused, closed]
        total_excl_tax:
          type: string
        total_vat:
          type: string
        total_incl_tax:
          type: string

    SupplierProposal:
      allOf:
        - $ref: "#/components/schemas/SupplierProposalSummary"
        - type: object
          properties:
            date_delivery:
              type: string
              format: date
            validated_at:
              type: string
              format: date-time
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            payment_terms:
              type: string
            payment_method:
              type: string
            multicurrency_code:
              type: string
            multicurrency_total_excl_tax:
              type: string
            multicurrency_total_vat:
              type: string
            multicurrency_total_incl_tax:
              type: string
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/DocumentLine"

    # ── Supplier Order ─────────────────────────────────────────────
    SupplierOrderSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        supplier_ref:
          type: string
        date_order:
          type: string
          format: date
        date_delivery:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, approved, ordered, received_partially, received_completely, cancelled, refused]
        billed:
          type: boolean
        total_excl_tax:
          type: string
        total_vat:
          type: string
        total_incl_tax:
          type: string

    SupplierOrder:
      allOf:
        - $ref: "#/components/schemas/SupplierOrderSummary"
        - type: object
          properties:
            date_order_supplier:
              type: string
              format: date
              description: Date supplier confirmed the order
            validated_at:
              type: string
              format: date-time
            approved_at:
              type: string
              format: date-time
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            payment_terms:
              type: string
            payment_method:
              type: string
            bank_account:
              type: string
            multicurrency_code:
              type: string
            multicurrency_total_excl_tax:
              type: string
            multicurrency_total_vat:
              type: string
            multicurrency_total_incl_tax:
              type: string
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/DocumentLine"

    # ── Supplier Invoice ───────────────────────────────────────────
    SupplierInvoiceSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        supplier_ref:
          type: string
        label:
          type: string
        date_invoice:
          type: string
          format: date
        date_due:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, paid, abandoned]
        paid:
          type: boolean
        total_excl_tax:
          type: string
        total_vat:
          type: string
        total_incl_tax:
          type: string

    SupplierInvoice:
      allOf:
        - $ref: "#/components/schemas/SupplierInvoiceSummary"
        - type: object
          properties:
            type:
              type: string
              enum: [standard, credit_note, deposit]
            validated_at:
              type: string
              format: date-time
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            payment_terms:
              type: string
            payment_method:
              type: string
            bank_account:
              type: string
            multicurrency_code:
              type: string
            multicurrency_total_excl_tax:
              type: string
            multicurrency_total_vat:
              type: string
            multicurrency_total_incl_tax:
              type: string
            close_code:
              type: string
            close_note:
              type: string
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/DocumentLine"

    # ── Reception ──────────────────────────────────────────────────
    ReceptionSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        supplier_ref:
          type: string
        date_reception:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, closed]
        tracking_number:
          type: string
        billed:
          type: boolean

    ReceptionLine:
      type: object
      properties:
        id:
          type: string
        product_ref:
          type: string
        product_label:
          type: string
        quantity:
          type: string
        warehouse:
          type: string
        position:
          type: integer
        comment:
          type: string

    Reception:
      allOf:
        - $ref: "#/components/schemas/ReceptionSummary"
        - type: object
          properties:
            date_delivery:
              type: string
              format: date
            validated_at:
              type: string
              format: date-time
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            origin_type:
              type: string
              description: Source object type (e.g. supplier_order)
            origin_id:
              type: string
            tracking_url:
              type: string
              format: uri
            shipping_method:
              type: string
            weight:
              type: string
            weight_units:
              type: string
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/ReceptionLine"

    # ── Contract ───────────────────────────────────────────────────
    ContractSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        customer_ref:
          type: string
        date_contract:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, closed]

    ContractLine:
      type: object
      properties:
        id:
          type: string
        product_ref:
          type: string
        product_label:
          type: string
        description:
          type: string
        quantity:
          type: string
        unit_price_excl_tax:
          type: string
        vat_rate:
          type: string
        total_excl_tax:
          type: string
        total_vat:
          type: string
        total_incl_tax:
          type: string
        date_start_planned:
          type: string
          format: date
        date_start_real:
          type: string
          format: date
        date_end_planned:
          type: string
          format: date
        date_end_real:
          type: string
          format: date
        status:
          type: string
          enum: [inactive, active, closed]
        position:
          type: integer

    Contract:
      allOf:
        - $ref: "#/components/schemas/ContractSummary"
        - type: object
          properties:
            supplier_ref:
              type: string
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/ContractLine"

    # ── Intervention ───────────────────────────────────────────────
    InterventionSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        date_intervention:
          type: string
          format: date
        duration:
          type: integer
          description: Total duration in seconds
        status:
          type: string
          enum: [draft, validated, done, billed]

    InterventionLine:
      type: object
      properties:
        id:
          type: string
        description:
          type: string
        date:
          type: string
          format: date
        duration:
          type: integer
          description: Duration in seconds
        product_ref:
          type: string
        position:
          type: integer

    Intervention:
      allOf:
        - $ref: "#/components/schemas/InterventionSummary"
        - type: object
          properties:
            customer_ref:
              type: string
            date_start:
              type: string
              format: date
            date_end:
              type: string
              format: date
            contract_ref:
              type: string
              description: Related contract reference
            description:
              type: string
            validated_at:
              type: string
              format: date-time
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/InterventionLine"

    # ── Ticket ─────────────────────────────────────────────────────
    TicketSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        track_id:
          type: string
          description: Public tracking identifier
        subject:
          type: string
        type_label:
          type: string
        severity_label:
          type: string
        status:
          type: string
          enum: [new, read, assigned, in_progress, waiting, resolved, closed, cancelled]
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    Ticket:
      allOf:
        - $ref: "#/components/schemas/TicketSummary"
        - type: object
          properties:
            message:
              type: string
              description: Initial message content
            type_code:
              type: string
            category_code:
              type: string
            category_label:
              type: string
            severity_code:
              type: string
            resolution:
              type: string
            progress:
              type: integer
              description: Percentage 0-100
            origin_email:
              type: string
              format: email
            read_at:
              type: string
              format: date-time
            closed_at:
              type: string
              format: date-time
            last_message_at:
              type: string
              format: date-time
            public_note:
              type: string

    # ══════════════════════════════════════════════════════════════════
    # TIER 3 SCHEMAS
    # ══════════════════════════════════════════════════════════════════

    # ── Project ────────────────────────────────────────────────────
    ProjectSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        title:
          type: string
        date_start:
          type: string
          format: date
        date_end:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, closed]

    Project:
      allOf:
        - $ref: "#/components/schemas/ProjectSummary"
        - type: object
          properties:
            description:
              type: string
            created_at:
              type: string
              format: date-time
            public_note:
              type: string
            tasks:
              type: array
              items:
                $ref: "#/components/schemas/Task"

    # ── Task ───────────────────────────────────────────────────────
    TaskSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        label:
          type: string
        project_ref:
          type: string
        date_start:
          type: string
          format: date
        date_end:
          type: string
          format: date
        progress:
          type: integer
          description: Percentage 0-100
        status:
          type: string

    Task:
      allOf:
        - $ref: "#/components/schemas/TaskSummary"
        - type: object
          properties:
            description:
              type: string
            planned_hours:
              type: string
            spent_hours:
              type: string
            priority:
              type: integer
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            public_note:
              type: string

    # ── Expense Report ─────────────────────────────────────────────
    ExpenseReportSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        date_start:
          type: string
          format: date
        date_end:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, approved, paid, refused, cancelled]
        paid:
          type: boolean
        total_excl_tax:
          type: string
        total_incl_tax:
          type: string

    ExpenseReportLine:
      type: object
      properties:
        id:
          type: string
        fee_type:
          type: string
        date:
          type: string
          format: date
        comments:
          type: string
        quantity:
          type: string
        unit_value:
          type: string
        vat_rate:
          type: string
        total_excl_tax:
          type: string
        total_vat:
          type: string
        total_incl_tax:
          type: string
        project_ref:
          type: string
        position:
          type: integer

    ExpenseReport:
      allOf:
        - $ref: "#/components/schemas/ExpenseReportSummary"
        - type: object
          properties:
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            validated_at:
              type: string
              format: date-time
            approved_at:
              type: string
              format: date-time
            payment_method:
              type: string
            total_vat:
              type: string
            multicurrency_code:
              type: string
            multicurrency_total_excl_tax:
              type: string
            multicurrency_total_vat:
              type: string
            multicurrency_total_incl_tax:
              type: string
            refuse_reason:
              type: string
            cancel_reason:
              type: string
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/ExpenseReportLine"

    # ── BOM ────────────────────────────────────────────────────────
    BomSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        label:
          type: string
        product_ref:
          type: string
        quantity:
          type: string
        status:
          type: string
          enum: [draft, validated, closed]

    BomLine:
      type: object
      properties:
        id:
          type: string
        product_ref:
          type: string
        product_label:
          type: string
        description:
          type: string
        quantity:
          type: string
        quantity_frozen:
          type: boolean
        disable_stock_change:
          type: boolean
        efficiency:
          type: string
        child_bom_ref:
          type: string
          description: Sub-BOM reference (if nested)
        position:
          type: integer

    Bom:
      allOf:
        - $ref: "#/components/schemas/BomSummary"
        - type: object
          properties:
            bom_type:
              type: string
              enum: [manufacturing, disassembly]
            description:
              type: string
            product_label:
              type: string
            duration:
              type: string
            efficiency:
              type: string
            warehouse:
              type: string
            created_at:
              type: string
              format: date-time
            validated_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/BomLine"

    # ── Manufacturing Order ────────────────────────────────────────
    ManufacturingOrderSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        label:
          type: string
        product_ref:
          type: string
        quantity:
          type: string
        date_start_planned:
          type: string
          format: date
        date_end_planned:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, in_progress, produced, cancelled]

    ManufacturingOrderLine:
      type: object
      properties:
        id:
          type: string
        product_ref:
          type: string
        product_label:
          type: string
        quantity:
          type: string
        warehouse:
          type: string
        role:
          type: string
          enum: [consumed, produced]
        origin_type:
          type: string
          description: Source object type
        origin_id:
          type: string
          description: Source object identifier
        position:
          type: integer

    ManufacturingOrder:
      allOf:
        - $ref: "#/components/schemas/ManufacturingOrderSummary"
        - type: object
          properties:
            mrp_type:
              type: string
              enum: [manufacturing, disassembly]
            product_label:
              type: string
            bom_ref:
              type: string
            warehouse:
              type: string
            created_at:
              type: string
              format: date-time
            validated_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            project_ref:
              type: string
            public_note:
              type: string
            lines:
              type: array
              items:
                $ref: "#/components/schemas/ManufacturingOrderLine"

    # ── Warehouse ──────────────────────────────────────────────────
    Warehouse:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        label:
          type: string
        description:
          type: string
        address:
          type: string
        zip:
          type: string
        city:
          type: string
        country:
          type: string
          description: ISO 3166-1 alpha-2
        phone:
          type: string
        status:
          type: string
          enum: [open, closed]
        parent_warehouse_ref:
          type: string

    # ── Member ─────────────────────────────────────────────────────
    MemberSummary:
      type: object
      properties:
        id:
          type: string
        ref:
          type: string
        type:
          type: string
        lastname:
          type: string
        firstname:
          type: string
        company:
          type: string
        email:
          type: string
          format: email
        date_subscription_end:
          type: string
          format: date
        status:
          type: string
          enum: [draft, validated, excluded, resigned]

    Member:
      allOf:
        - $ref: "#/components/schemas/MemberSummary"
        - type: object
          properties:
            civility:
              type: string
            address:
              type: string
            zip:
              type: string
            city:
              type: string
            state:
              type: string
            country:
              type: string
              description: ISO 3166-1 alpha-2
            phone:
              type: string
            date_birth:
              type: string
              format: date
            date_subscription_start:
              type: string
              format: date
            subscription_amount:
              type: string
            public_note:
              type: string

    # ── Category ───────────────────────────────────────────────────
    Category:
      type: object
      properties:
        id:
          type: string
        label:
          type: string
        description:
          type: string
        color:
          type: string
          description: Hex color code
          example: "#FF5733"
        type:
          type: string
          enum: [product, thirdparty, contact, member, project]
        parent_id:
          type: string
        parent_label:
          type: string
