openapi: 3.1.0
info:
  title: order-mesh API
  version: "1.0.0"
  description: |
    AIや外部システムから order-mesh を操作するための REST API。
    認証は Bearer トークン (`Authorization: Bearer omsh_xxxx`)。
    トークンは社内画面 `/api_keys` から発行する。

servers:
  - url: "{baseUrl}/api/v1"
    description: API server
    variables:
      baseUrl:
        default: https://tokuiten.minorisu.com

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: omsh

  schemas:
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code: { type: string }
            message: { type: string }
            details: { type: object }

    Partner:
      type: object
      properties:
        id: { type: integer }
        name: { type: string }
        kind:
          type: string
          enum: [customer, producer]
        email: { type: string, nullable: true }
        origin: { type: string, nullable: true }
        phone: { type: string, nullable: true }
        note: { type: string, nullable: true }

    PartnerInput:
      type: object
      required: [name, kind]
      properties:
        name: { type: string }
        kind:
          type: string
          enum: [customer, producer]
        email: { type: string }
        origin: { type: string }
        phone: { type: string }
        note: { type: string }

    Product:
      type: object
      properties:
        id: { type: integer }
        code: { type: string }
        name: { type: string }
        spec: { type: string, nullable: true }
        box_size: { type: string, nullable: true }
        lot_size: { type: integer, nullable: true }
        standard: { type: string, nullable: true }
        producer_partner_id: { type: integer }
        producer_name: { type: string }
        origin_snapshot: { type: string, nullable: true }
        note: { type: string, nullable: true }

    ProductInput:
      type: object
      required: [name, producer_partner_id]
      properties:
        name: { type: string }
        spec: { type: string }
        box_size: { type: string }
        lot_size: { type: integer }
        standard: { type: string }
        producer_partner_id: { type: integer }
        note: { type: string }

    Estimate:
      type: object
      properties:
        id: { type: integer }
        title: { type: string }
        start_date: { type: string, format: date }
        status:
          type: string
          enum: [draft, sent, ordered]
        note: { type: string, nullable: true }
        items:
          type: array
          items: { $ref: "#/components/schemas/EstimateItem" }

    EstimateInput:
      type: object
      required: [title, start_date]
      properties:
        title: { type: string }
        start_date: { type: string, format: date }
        status: { type: string, enum: [draft, sent, ordered] }
        note: { type: string }

    EstimateItem:
      type: object
      properties:
        id: { type: integer }
        product_id: { type: integer }
        product_code: { type: string }
        product_name: { type: string }
        spec: { type: string, nullable: true }
        unit_price: { type: integer }
        lot_size: { type: integer, nullable: true }
        position: { type: integer }
        note: { type: string, nullable: true }
        producer_partner_id: { type: integer, nullable: true }
        producer_name: { type: string, nullable: true }

    EstimateItemInput:
      type: object
      required: [product_id, unit_price]
      properties:
        product_id: { type: integer }
        unit_price: { type: integer }
        lot_size: { type: integer }
        position: { type: integer }
        note: { type: string }

    Order:
      type: object
      properties:
        id: { type: integer }
        status: { type: string }
        submitted: { type: boolean }
        submitted_at: { type: string, format: date-time, nullable: true }
        confirmed: { type: boolean }
        confirmed_at: { type: string, format: date-time, nullable: true }
        partner_id: { type: integer }
        partner_name: { type: string }
        estimate_id: { type: integer }
        estimate_title: { type: string }
        total_quantity: { type: integer }
        items:
          type: array
          items: { $ref: "#/components/schemas/OrderItem" }

    OrderItem:
      type: object
      properties:
        id: { type: integer }
        estimate_item_id: { type: integer }
        product_code: { type: string }
        product_name: { type: string }
        delivery_date: { type: string, format: date }
        quantity: { type: integer }
        unit_price: { type: integer }
        subtotal: { type: integer }

security:
  - BearerAuth: []

paths:
  /partners:
    get:
      summary: List partners
      parameters:
        - name: kind
          in: query
          required: false
          schema: { type: string, enum: [customer, producer] }
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  partners:
                    type: array
                    items: { $ref: "#/components/schemas/Partner" }
    post:
      summary: Create partner
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                partner: { $ref: "#/components/schemas/PartnerInput" }
      responses:
        "201":
          description: Created
          content: { application/json: { schema: { type: object, properties: { partner: { $ref: "#/components/schemas/Partner" } } } } }

  /partners/{id}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: integer } }
    get:
      summary: Get partner
      responses:
        "200":
          description: OK
          content: { application/json: { schema: { type: object, properties: { partner: { $ref: "#/components/schemas/Partner" } } } } }
    patch:
      summary: Update partner
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                partner: { $ref: "#/components/schemas/PartnerInput" }
      responses:
        "200": { description: OK }
    delete:
      summary: Delete partner
      responses:
        "204": { description: No Content }

  /products:
    get:
      summary: List products
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  products:
                    type: array
                    items: { $ref: "#/components/schemas/Product" }
    post:
      summary: Create product
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                product: { $ref: "#/components/schemas/ProductInput" }
      responses:
        "201": { description: Created }

  /products/{id}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: integer } }
    get: { summary: Get product, responses: { "200": { description: OK } } }
    patch: { summary: Update product, responses: { "200": { description: OK } } }
    delete: { summary: Delete product, responses: { "204": { description: No Content } } }

  /estimates:
    get:
      summary: List estimates
      responses:
        "200": { description: OK }
    post:
      summary: Create estimate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                estimate: { $ref: "#/components/schemas/EstimateInput" }
      responses:
        "201": { description: Created }

  /estimates/{id}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: integer } }
    get: { summary: Get estimate (with items), responses: { "200": { description: OK } } }
    patch: { summary: Update estimate, responses: { "200": { description: OK } } }
    delete: { summary: Delete estimate, responses: { "204": { description: No Content } } }

  /estimates/{estimate_id}/items:
    parameters:
      - { name: estimate_id, in: path, required: true, schema: { type: integer } }
    get: { summary: List items, responses: { "200": { description: OK } } }
    post:
      summary: Add item
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                item: { $ref: "#/components/schemas/EstimateItemInput" }
      responses:
        "201": { description: Created }

  /estimates/{estimate_id}/items/{id}:
    parameters:
      - { name: estimate_id, in: path, required: true, schema: { type: integer } }
      - { name: id, in: path, required: true, schema: { type: integer } }
    patch: { summary: Update item, responses: { "200": { description: OK } } }
    delete: { summary: Delete item, responses: { "204": { description: No Content } } }

  /orders:
    get:
      summary: List orders
      parameters:
        - name: status
          in: query
          schema: { type: string, enum: [submitted, confirmed] }
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  orders:
                    type: array
                    items: { $ref: "#/components/schemas/Order" }

  /orders/{id}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: integer } }
    get: { summary: Get order (with items), responses: { "200": { description: OK } } }

  /orders/{id}/confirm:
    parameters:
      - { name: id, in: path, required: true, schema: { type: integer } }
    post:
      summary: Confirm a submitted order
      responses:
        "200": { description: OK }
        "422": { description: Order not in submitted state }

  /orders/{id}/unconfirm:
    parameters:
      - { name: id, in: path, required: true, schema: { type: integer } }
    post:
      summary: Revert a confirmed order back to submitted
      responses:
        "200": { description: OK }
