Source Code

;; lab-results - Clarity 4
;; Laboratory test results management

(define-constant ERR-RESULT-NOT-FOUND (err u100))
(define-constant ERR-NOT-AUTHORIZED (err u101))
(define-constant ERR-INVALID-RESULT (err u102))

(define-map lab-results uint
  {
    patient: principal,
    lab: principal,
    test-type: (string-ascii 100),
    result-hash: (buff 64),
    performed-at: uint,
    is-verified: bool,
    urgency-level: (string-ascii 20),
    reviewed-by: (optional principal)
  }
)

(define-map test-panels uint
  {
    panel-name: (string-utf8 100),
    tests-included: (list 20 (string-ascii 100)),
    panel-type: (string-ascii 50),
    created-at: uint,
    is-active: bool
  }
)

(define-map result-interpretations uint
  {
    result-id: uint,
    interpreter: principal,
    interpretation: (string-utf8 500),
    clinical-significance: (string-ascii 50),
    interpreted-at: uint,
    confidence-level: uint
  }
)

(define-map reference-ranges uint
  {
    test-type: (string-ascii 100),
    min-value: uint,
    max-value: uint,
    unit: (string-ascii 20),
    age-range: (string-ascii 50),
    gender-specific: bool
  }
)

(define-map abnormal-flags uint
  {
    result-id: uint,
    flag-type: (string-ascii 50),
    severity: (string-ascii 20),
    flagged-at: uint,
    flagged-by: principal,
    follow-up-required: bool
  }
)

(define-map quality-controls uint
  {
    lab: principal,
    control-type: (string-ascii 50),
    control-result: (string-ascii 50),
    tested-at: uint,
    passed: bool,
    comments: (optional (string-utf8 300))
  }
)

(define-data-var result-counter uint u0)
(define-data-var panel-counter uint u0)
(define-data-var interpretation-counter uint u0)
(define-data-var range-counter uint u0)
(define-data-var flag-counter uint u0)
(define-data-var qc-counter uint u0)

(define-public (submit-result
    (patient principal)
    (test-type (string-ascii 100))
    (result-hash (buff 64))
    (urgency-level (string-ascii 20)))
  (let ((result-id (+ (var-get result-counter) u1)))
    (map-set lab-results result-id
      {
        patient: patient,
        lab: tx-sender,
        test-type: test-type,
        result-hash: result-hash,
        performed-at: stacks-block-time,
        is-verified: false,
        urgency-level: urgency-level,
        reviewed-by: none
      })
    (var-set result-counter result-id)
    (ok result-id)))

(define-public (verify-result (result-id uint))
  (let ((result (unwrap! (map-get? lab-results result-id) ERR-RESULT-NOT-FOUND)))
    (asserts! (is-eq tx-sender (get lab result)) ERR-NOT-AUTHORIZED)
    (ok (map-set lab-results result-id
      (merge result {
        is-verified: true,
        reviewed-by: (some tx-sender)
      })))))

(define-public (create-test-panel
    (panel-name (string-utf8 100))
    (tests-included (list 20 (string-ascii 100)))
    (panel-type (string-ascii 50)))
  (let ((panel-id (+ (var-get panel-counter) u1)))
    (map-set test-panels panel-id
      {
        panel-name: panel-name,
        tests-included: tests-included,
        panel-type: panel-type,
        created-at: stacks-block-time,
        is-active: true
      })
    (var-set panel-counter panel-id)
    (ok panel-id)))

(define-public (add-interpretation
    (result-id uint)
    (interpretation (string-utf8 500))
    (clinical-significance (string-ascii 50))
    (confidence-level uint))
  (let ((interpretation-id (+ (var-get interpretation-counter) u1)))
    (asserts! (is-some (map-get? lab-results result-id)) ERR-RESULT-NOT-FOUND)
    (map-set result-interpretations interpretation-id
      {
        result-id: result-id,
        interpreter: tx-sender,
        interpretation: interpretation,
        clinical-significance: clinical-significance,
        interpreted-at: stacks-block-time,
        confidence-level: confidence-level
      })
    (var-set interpretation-counter interpretation-id)
    (ok interpretation-id)))

(define-public (set-reference-range
    (test-type (string-ascii 100))
    (min-value uint)
    (max-value uint)
    (unit (string-ascii 20))
    (age-range (string-ascii 50))
    (gender-specific bool))
  (let ((range-id (+ (var-get range-counter) u1)))
    (map-set reference-ranges range-id
      {
        test-type: test-type,
        min-value: min-value,
        max-value: max-value,
        unit: unit,
        age-range: age-range,
        gender-specific: gender-specific
      })
    (var-set range-counter range-id)
    (ok range-id)))

(define-public (flag-abnormal-result
    (result-id uint)
    (flag-type (string-ascii 50))
    (severity (string-ascii 20))
    (follow-up-required bool))
  (let ((flag-id (+ (var-get flag-counter) u1)))
    (asserts! (is-some (map-get? lab-results result-id)) ERR-RESULT-NOT-FOUND)
    (map-set abnormal-flags flag-id
      {
        result-id: result-id,
        flag-type: flag-type,
        severity: severity,
        flagged-at: stacks-block-time,
        flagged-by: tx-sender,
        follow-up-required: follow-up-required
      })
    (var-set flag-counter flag-id)
    (ok flag-id)))

(define-public (record-quality-control
    (control-type (string-ascii 50))
    (control-result (string-ascii 50))
    (passed bool)
    (comments (optional (string-utf8 300))))
  (let ((qc-id (+ (var-get qc-counter) u1)))
    (map-set quality-controls qc-id
      {
        lab: tx-sender,
        control-type: control-type,
        control-result: control-result,
        tested-at: stacks-block-time,
        passed: passed,
        comments: comments
      })
    (var-set qc-counter qc-id)
    (ok qc-id)))

(define-read-only (get-result (result-id uint))
  (ok (map-get? lab-results result-id)))

(define-read-only (get-test-panel (panel-id uint))
  (ok (map-get? test-panels panel-id)))

(define-read-only (get-interpretation (interpretation-id uint))
  (ok (map-get? result-interpretations interpretation-id)))

(define-read-only (get-reference-range (range-id uint))
  (ok (map-get? reference-ranges range-id)))

(define-read-only (get-abnormal-flag (flag-id uint))
  (ok (map-get? abnormal-flags flag-id)))

(define-read-only (get-quality-control (qc-id uint))
  (ok (map-get? quality-controls qc-id)))

(define-read-only (validate-lab (lab principal))
  (principal-destruct? lab))

(define-read-only (format-result-id (result-id uint))
  (ok (int-to-ascii result-id)))

(define-read-only (parse-result-id (id-str (string-ascii 20)))
  (string-to-uint? id-str))

(define-read-only (get-bitcoin-block)
  (ok burn-block-height))

Functions (17)

FunctionAccessArgs
submit-resultpublicpatient: principal, test-type: (string-ascii 100
verify-resultpublicresult-id: uint
create-test-panelpublicpanel-name: (string-utf8 100
add-interpretationpublicresult-id: uint, interpretation: (string-utf8 500
set-reference-rangepublictest-type: (string-ascii 100
flag-abnormal-resultpublicresult-id: uint, flag-type: (string-ascii 50
record-quality-controlpubliccontrol-type: (string-ascii 50
get-resultread-onlyresult-id: uint
get-test-panelread-onlypanel-id: uint
get-interpretationread-onlyinterpretation-id: uint
get-reference-rangeread-onlyrange-id: uint
get-abnormal-flagread-onlyflag-id: uint
get-quality-controlread-onlyqc-id: uint
validate-labread-onlylab: principal
format-result-idread-onlyresult-id: uint
parse-result-idread-onlyid-str: (string-ascii 20
get-bitcoin-blockread-only