Source Code

(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u100))
(define-constant err-not-found (err u101))
(define-constant err-unauthorized (err u102))
(define-constant err-invalid-params (err u103))
(define-constant err-insufficient-inventory (err u104))

(define-map inventory-items
  {item-id: uint}
  {
    product-type: (string-ascii 64),
    owner: principal,
    quantity: uint,
    unit: (string-ascii 16),
    location: (string-ascii 128),
    batch-number: (string-ascii 64),
    created-at: uint,
    updated-at: uint
  }
)

(define-map inventory-movements
  {movement-id: uint}
  {
    item-id: uint,
    movement-type: (string-ascii 32),
    quantity: uint,
    from-location: (optional (string-ascii 128)),
    to-location: (optional (string-ascii 128)),
    timestamp: uint,
    initiated-by: principal
  }
)

(define-data-var item-nonce uint u0)
(define-data-var movement-nonce uint u0)

(define-read-only (get-inventory-item (item-id uint))
  (map-get? inventory-items {item-id: item-id})
)

(define-read-only (get-movement (movement-id uint))
  (map-get? inventory-movements {movement-id: movement-id})
)

(define-public (create-inventory-item
  (product-type (string-ascii 64))
  (quantity uint)
  (unit (string-ascii 16))
  (location (string-ascii 128))
  (batch-number (string-ascii 64))
)
  (let ((item-id (var-get item-nonce)))
    (asserts! (> quantity u0) err-invalid-params)
    (map-set inventory-items {item-id: item-id}
      {
        product-type: product-type,
        owner: tx-sender,
        quantity: quantity,
        unit: unit,
        location: location,
        batch-number: batch-number,
        created-at: stacks-block-height,
        updated-at: stacks-block-height
      }
    )
    (var-set item-nonce (+ item-id u1))
    (ok item-id)
  )
)

(define-public (adjust-inventory
  (item-id uint)
  (quantity-change int)
  (movement-type (string-ascii 32))
)
  (let (
    (item (unwrap! (map-get? inventory-items {item-id: item-id}) err-not-found))
    (movement-id (var-get movement-nonce))
    (new-quantity (if (>= quantity-change 0)
      (+ (get quantity item) (to-uint quantity-change))
      (- (get quantity item) (to-uint (- 0 quantity-change)))))
  )
    (asserts! (is-eq tx-sender (get owner item)) err-unauthorized)
    (if (< quantity-change 0)
      (asserts! (>= (get quantity item) (to-uint (- 0 quantity-change))) err-insufficient-inventory)
      true
    )
    (map-set inventory-items {item-id: item-id}
      (merge item {
        quantity: new-quantity,
        updated-at: stacks-block-height
      })
    )
    (map-set inventory-movements {movement-id: movement-id}
      {
        item-id: item-id,
        movement-type: movement-type,
        quantity: (if (>= quantity-change 0) (to-uint quantity-change) (to-uint (- 0 quantity-change))),
        from-location: (if (< quantity-change 0) (some (get location item)) none),
        to-location: (if (>= quantity-change 0) (some (get location item)) none),
        timestamp: stacks-block-height,
        initiated-by: tx-sender
      }
    )
    (var-set movement-nonce (+ movement-id u1))
    (ok movement-id)
  )
)

(define-public (transfer-inventory
  (item-id uint)
  (quantity uint)
  (new-owner principal)
  (new-location (string-ascii 128))
)
  (let (
    (item (unwrap! (map-get? inventory-items {item-id: item-id}) err-not-found))
    (movement-id (var-get movement-nonce))
  )
    (asserts! (is-eq tx-sender (get owner item)) err-unauthorized)
    (asserts! (<= quantity (get quantity item)) err-insufficient-inventory)
    (if (is-eq quantity (get quantity item))
      (map-set inventory-items {item-id: item-id}
        (merge item {
          owner: new-owner,
          location: new-location,
          updated-at: stacks-block-height
        })
      )
      (begin
        (map-set inventory-items {item-id: item-id}
          (merge item {
            quantity: (- (get quantity item) quantity),
            updated-at: stacks-block-height
          })
        )
        (map-set inventory-items {item-id: (var-get item-nonce)}
          {
            product-type: (get product-type item),
            owner: new-owner,
            quantity: quantity,
            unit: (get unit item),
            location: new-location,
            batch-number: (get batch-number item),
            created-at: stacks-block-height,
            updated-at: stacks-block-height
          }
        )
        (var-set item-nonce (+ (var-get item-nonce) u1))
      )
    )
    (map-set inventory-movements {movement-id: movement-id}
      {
        item-id: item-id,
        movement-type: "transfer",
        quantity: quantity,
        from-location: (some (get location item)),
        to-location: (some new-location),
        timestamp: stacks-block-height,
        initiated-by: tx-sender
      }
    )
    (var-set movement-nonce (+ movement-id u1))
    (ok movement-id)
  )
)

Functions (5)

FunctionAccessArgs
get-inventory-itemread-onlyitem-id: uint
get-movementread-onlymovement-id: uint
create-inventory-itempublicproduct-type: (string-ascii 64
adjust-inventorypublicitem-id: uint, quantity-change: int, movement-type: (string-ascii 32
transfer-inventorypublicitem-id: uint, quantity: uint, new-owner: principal, new-location: (string-ascii 128