Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/checkout_sdk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
require 'checkout_sdk/network_tokens/network_tokens'
require 'checkout_sdk/payment_methods/payment_methods'
require 'checkout_sdk/identities/identities'
require 'checkout_sdk/inventory/inventory'

# Checkout modules (previous)
require 'checkout_sdk/sources/sources'
Expand Down
6 changes: 5 additions & 1 deletion lib/checkout_sdk/checkout_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ module CheckoutSdk
# @return [CheckoutSdk::Payments::ApplePayClient]
# @!attribute google_pay
# @return [CheckoutSdk::Payments::GooglePayClient]
# @!attribute inventory
# @return [CheckoutSdk::Inventory::InventoryClient]
class CheckoutApi
attr_reader :customers,
:disputes,
Expand Down Expand Up @@ -118,7 +120,8 @@ class CheckoutApi
:identity_verification,
:face_authentication,
:apple_pay,
:google_pay
:google_pay,
:inventory

# @param [CheckoutConfiguration] configuration
def initialize(configuration)
Expand Down Expand Up @@ -168,6 +171,7 @@ def initialize(configuration)
CheckoutSdk::Identities::FaceAuthentication::FaceAuthenticationClient.new(api_client, configuration)
@apple_pay = CheckoutSdk::Payments::ApplePayClient.new(api_client, configuration)
@google_pay = CheckoutSdk::Payments::GooglePayClient.new(api_client, configuration)
@inventory = CheckoutSdk::Inventory::InventoryClient.new(api_client, configuration)
end

private
Expand Down
9 changes: 9 additions & 0 deletions lib/checkout_sdk/inventory/inventory.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

require 'checkout_sdk/inventory/inventory_money'
require 'checkout_sdk/inventory/inventory_adjustment_request'
require 'checkout_sdk/inventory/inventory_reservation_item'
require 'checkout_sdk/inventory/inventory_reservation_request'
require 'checkout_sdk/inventory/inventory_set_levels_request'
require 'checkout_sdk/inventory/inventory_set_product_request'
require 'checkout_sdk/inventory/inventory_client'
24 changes: 24 additions & 0 deletions lib/checkout_sdk/inventory/inventory_adjustment_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

module CheckoutSdk
module Inventory
# Request body for POST /inventory/adjustments. Mirrors swagger
# `InventoryAdjustmentRequest`.
#
# @!attribute variant_id
# @return [String] The identifier of the variant to adjust. The variant must already
# exist. [Required] max 128 characters.
# @!attribute delta
# @return [Integer] The signed change to apply to on_hand. A negative delta that would
# drive on_hand below zero is rejected with a 409. Per spec, must be non-zero (not a
# formal schema constraint). [Required]
# @!attribute reason
# @return [String] A free-text reason recorded in the ledger. Must not contain personal
# data. [Required] min 1 character, max 256 characters.
class InventoryAdjustmentRequest
attr_accessor :variant_id,
:delta,
:reason
end
end
end
149 changes: 149 additions & 0 deletions lib/checkout_sdk/inventory/inventory_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# frozen_string_literal: true

module CheckoutSdk
module Inventory
# Client for the Inventory API: stock levels, atomic multi-variant reservations
# (hold/commit/release), stock adjustments, and per-variant "product knowledge"
# merchandising metadata for AI agents.
#
# All 10 operations require OAuth with the agentic:inventory scope (see
# {CheckoutSdk::OAuthScopes::AGENTIC_INVENTORY}); unlike most domains in this SDK, there is
# no ApiSecretKey/ApiPublicKey fallback, so this client always authorizes with
# {CheckoutSdk::AuthorizationType::OAUTH} (the same pattern already used by
# {CheckoutSdk::Payments::GooglePayClient}).
#
# Responses are returned as Hash (OpenStruct), per this SDK's convention (see e.g.
# {CheckoutSdk::Balances::BalancesClient}); there are no typed InventoryLevels,
# InventoryReservation or InventoryProductKnowledge response classes. Error responses
# (404/409/422) surface as {CheckoutSdk::CheckoutApiException}; this SDK has no per-domain
# typed error response classes, so `InventoryErrorResponse`'s fields
# (request_id, error_type, error_codes, variant_id, available) are available generically via
# `error.error_details`, the same as every other domain.
#
# getInventoryProduct, setInventoryProduct and deleteInventoryProduct are marked Beta in the
# specification.
class InventoryClient < Client
INVENTORY = 'inventory'
ADJUSTMENTS = 'adjustments'
RESERVATIONS = 'reservations'
COMMIT = 'commit'
RELEASE = 'release'
PRODUCT = 'product'
private_constant :INVENTORY, :ADJUSTMENTS, :RESERVATIONS, :COMMIT, :RELEASE, :PRODUCT

# @param [ApiClient] api_client
# @param [CheckoutConfiguration] configuration
def initialize(api_client, configuration)
super(api_client, configuration, CheckoutSdk::AuthorizationType::OAUTH)
end

# Apply a signed stock adjustment to a variant's on_hand quantity, recording the reason in
# the ledger. Returns 201, or 200 with a Cache-Control response header on an idempotent
# replay; both share the InventoryLevels response schema.
#
# @param [Hash, InventoryAdjustmentRequest] adjustment_request
# @param [String, nil] idempotency_key Optional. Cko-Idempotency-Key request header.
# @return [Hash] the InventoryLevels response
def adjust_inventory(adjustment_request, idempotency_key = nil)
api_client.invoke_post(
build_path(INVENTORY, ADJUSTMENTS),
sdk_authorization,
adjustment_request,
idempotency_key
)
end

# Create an atomic multi-variant hold. Returns 201, or 200 with a Cache-Control response
# header on an idempotent replay; both share the InventoryReservation response schema.
#
# @param [Hash, InventoryReservationRequest] reservation_request
# @param [String, nil] idempotency_key Optional. Cko-Idempotency-Key request header.
# @return [Hash] the InventoryReservation response
def create_inventory_reservation(reservation_request, idempotency_key = nil)
api_client.invoke_post(
build_path(INVENTORY, RESERVATIONS),
sdk_authorization,
reservation_request,
idempotency_key
)
end

# Retrieve a reservation by ID.
#
# @param [String] reservation_id
# @return [Hash] the InventoryReservation response
def get_inventory_reservation(reservation_id)
api_client.invoke_get(build_path(INVENTORY, RESERVATIONS, reservation_id), sdk_authorization)
end

# Commit a held reservation, converting the hold into a permanent deduction. Takes no
# request body.
#
# @param [String] reservation_id
# @return [Hash] the InventoryReservation response
def commit_inventory_reservation(reservation_id)
api_client.invoke_post(
build_path(INVENTORY, RESERVATIONS, reservation_id, COMMIT),
sdk_authorization
)
end

# Release a held reservation, returning the reserved quantity to available stock. Takes
# no request body.
#
# @param [String] reservation_id
# @return [Hash] the InventoryReservation response
def release_inventory_reservation(reservation_id)
api_client.invoke_post(
build_path(INVENTORY, RESERVATIONS, reservation_id, RELEASE),
sdk_authorization
)
end

# Retrieve the stock levels for a variant.
#
# @param [String] variant_id
# @param [Boolean, nil] expand_product Optional. When true, adds `?expand=product` so the
# response embeds the variant's InventoryProductKnowledge (when it exists) under
# `product`.
# @return [Hash] the InventoryLevels response
def get_inventory_levels(variant_id, expand_product: false)
params = { expand: 'product' } if expand_product
api_client.invoke_get(build_path(INVENTORY, variant_id), sdk_authorization, params)
end

# Create or replace the stock levels for a variant.
#
# @param [String] variant_id
# @param [Hash, InventorySetLevelsRequest] set_levels_request
# @return [Hash] the InventoryLevels response
def set_inventory_levels(variant_id, set_levels_request)
api_client.invoke_put(build_path(INVENTORY, variant_id), sdk_authorization, set_levels_request)
end

# Retrieve the product knowledge (merchandising metadata) for a variant. Beta.
#
# @param [String] variant_id
# @return [Hash] the InventoryProductKnowledge response
def get_inventory_product(variant_id)
api_client.invoke_get(build_path(INVENTORY, variant_id, PRODUCT), sdk_authorization)
end

# Create or replace the product knowledge for a variant. Beta.
#
# @param [String] variant_id
# @param [Hash, InventorySetProductRequest] set_product_request
# @return [Hash] the InventoryProductKnowledge response
def set_inventory_product(variant_id, set_product_request)
api_client.invoke_put(build_path(INVENTORY, variant_id, PRODUCT), sdk_authorization, set_product_request)
end

# Delete the product knowledge for a variant. Beta. Returns 204 with no body.
#
# @param [String] variant_id
def delete_inventory_product(variant_id)
api_client.invoke_delete(build_path(INVENTORY, variant_id, PRODUCT), sdk_authorization)
end
end
end
end
19 changes: 19 additions & 0 deletions lib/checkout_sdk/inventory/inventory_money.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module CheckoutSdk
module Inventory
# A monetary amount in an inventory product's price or sale_price. Mirrors swagger
# `InventoryMoney`. Used by {InventorySetProductRequest#price} and
# {InventorySetProductRequest#sale_price}.
#
# @!attribute amount
# @return [Integer] The amount in the currency's minor unit. [Required]
# @!attribute currency
# @return [String] The 3-letter ISO 4217 currency code. [Required] min 3 characters,
# max 3 characters.
class InventoryMoney
attr_accessor :amount,
:currency
end
end
end
20 changes: 20 additions & 0 deletions lib/checkout_sdk/inventory/inventory_reservation_item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

module CheckoutSdk
module Inventory
# A single line item within an inventory reservation. Mirrors swagger
# `InventoryReservationItem`. Used by {InventoryReservationRequest#items} and present in the
# `InventoryReservation` response's `items` array (returned as a Hash, not deserialized into
# this class, per this SDK's response convention).
#
# @!attribute variant_id
# @return [String] The identifier of the variant to reserve. The variant must already
# exist. [Required] max 128 characters.
# @!attribute quantity
# @return [Integer] The quantity to reserve. [Required] min 1.
class InventoryReservationItem
attr_accessor :variant_id,
:quantity
end
end
end
27 changes: 27 additions & 0 deletions lib/checkout_sdk/inventory/inventory_reservation_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

module CheckoutSdk
module Inventory
# Request body for POST /inventory/reservations. Mirrors swagger
# `InventoryReservationRequest`.
#
# @!attribute owner_type
# @return [String] Free-text classification of the reservation's owner (e.g. an agent or
# order type). [Required] max 64 characters.
# @!attribute owner_reference
# @return [String] A reference identifying the specific owner, echoed back on the
# reservation. [Required] max 256 characters.
# @!attribute items
# @return [Array<InventoryReservationItem>] The variants and quantities to hold.
# [Required] min 1 item, max 45 items. variant_id must be unique within the request.
# @!attribute ttl_seconds
# @return [Integer] How long the hold stays active before it expires. [Optional]
# min 60, max 3600. Default: 900.
class InventoryReservationRequest
attr_accessor :owner_type,
:owner_reference,
:items,
:ttl_seconds
end
end
end
22 changes: 22 additions & 0 deletions lib/checkout_sdk/inventory/inventory_set_levels_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

module CheckoutSdk
module Inventory
# Request body for PUT /inventory/{variant_id}. Mirrors swagger
# `InventorySetLevelsRequest`.
#
# @!attribute on_hand
# @return [Integer] The physical stock to set for the variant. [Required] min 0.
# @!attribute safety_stock
# @return [Integer] The buffer withheld from sale. [Optional] min 0. Defaults to 0 on
# create; left unchanged on update if omitted.
# @!attribute reason
# @return [String] A free-text reason recorded in the ledger. Must not contain personal
# data. [Optional] max 256 characters.
class InventorySetLevelsRequest
attr_accessor :on_hand,
:safety_stock,
:reason
end
end
end
Loading
Loading