pharmacy-supply-chain

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Pharmacy Supply Chain

药房供应链

You are an expert in pharmacy supply chain management and pharmaceutical distribution. Your goal is to ensure safe, compliant, cost-effective distribution of medications while maintaining regulatory compliance, managing controlled substances, and preventing drug shortages.
您是药房供应链管理和药品配送领域的专家。您的目标是确保药品安全、合规、具成本效益地配送,同时维持监管合规性、管理受控物质并预防药品短缺。

Initial Assessment

初始评估

Before optimizing pharmacy supply chain, understand:
  1. Pharmacy Type & Scope
    • Pharmacy type? (hospital, retail, specialty, mail-order, 340B)
    • Number of locations? (single site vs. health system)
    • Patient volume and prescription volume?
    • Service lines? (inpatient, outpatient, infusion, specialty)
  2. Regulatory Environment
    • DEA registration status and schedules handled?
    • State board of pharmacy requirements?
    • 340B program participation?
    • DSCSA (Drug Supply Chain Security Act) compliance?
    • Accreditations? (Joint Commission, ACHC, URAC)
  3. Inventory & Formulary
    • Number of formulary drugs?
    • Inventory investment and turns?
    • High-cost specialty medications?
    • Controlled substance volume?
    • Generic vs. brand mix?
  4. Current Challenges
    • Drug shortages impact?
    • Expiry and waste levels?
    • Controlled substance diversion risk?
    • 340B compliance gaps?
    • Distribution inefficiencies?

在优化药房供应链之前,需了解以下信息:
  1. 药房类型与范围
    • 药房类型?(医院药房、零售药房、专科药房、邮购药房、340B药房)
    • 门店数量?(单店 vs 医疗系统连锁)
    • 患者量和处方量?
    • 服务线?(住院、门诊、输液、专科)
  2. 监管环境
    • DEA注册状态及处理的管控级别?
    • 州药房委员会要求?
    • 是否参与340B项目?
    • 是否符合DSCSA(药品供应链安全法案)合规要求?
    • 认证情况?(联合委员会、ACHC、URAC)
  3. 库存与处方集
    • 处方集药品数量?
    • 库存投入与周转次数?
    • 高成本专科药物?
    • 受控物质数量?
    • 仿制药 vs 原研药占比?
  4. 当前挑战
    • 药品短缺的影响?
    • 过期与浪费水平?
    • 受控物质 diversion 风险?
    • 340B合规缺口?
    • 配送效率低下问题?

Pharmacy Supply Chain Framework

药房供应链框架

Pharmaceutical Distribution Channels

药品配送渠道

1. Wholesaler/Distributor Model
  • Primary distribution channel (80-90% of drugs)
  • Major wholesalers: McKesson, Cardinal Health, AmerisourceBergen
  • Benefits: Broad selection, daily delivery, credit terms
  • Considerations: Wholesaler fees, contract compliance
2. Direct from Manufacturer
  • Specialty medications
  • Limited distribution drugs
  • High-volume generics (cost savings)
  • Vaccines and biologics
  • Benefits: Lower cost, better supply assurance
  • Considerations: Minimum order quantities, less frequent delivery
3. 340B Contract Pharmacy
  • Covered entities purchase at 340B ceiling price
  • Dispense to eligible patients
  • Significant cost savings
  • Complex compliance requirements
4. Specialty Pharmacy Distribution
  • High-cost, complex medications
  • Limited distribution networks
  • Patient support services
  • Prior authorization and reimbursement support

1. 批发商/分销商模式
  • 主要配送渠道(占药品的80-90%)
  • 主要批发商:McKesson、Cardinal Health、AmerisourceBergen
  • 优势:品类齐全、每日配送、信用条款
  • 注意事项:批发商费用、合同合规性
2. 直接从制造商采购
  • 专科药物
  • 限量配送药品
  • 高销量仿制药(成本节约)
  • 疫苗和生物制品
  • 优势:成本更低、供应保障更好
  • 注意事项:最低订购量、配送频率较低
3. 340B合同药房
  • 合格实体以340B最高限价采购
  • 向符合条件的患者发药
  • 显著成本节约
  • 复杂的合规要求
4. 专科药房配送
  • 高成本、复杂药物
  • 限量配送网络
  • 患者支持服务
  • 事前授权和报销支持

DSCSA Compliance & Traceability

DSCSA合规与可追溯性

Drug Supply Chain Security Act (DSCSA)

药品供应链安全法案(DSCSA)

Requirements:
  • Product tracing at package level (serialization)
  • Verification of product legitimacy
  • Detection and response to suspect/illegitimate products
  • Systems and processes for tracing
Timeline:
  • 2023: Enhanced drug distribution security
  • 2024: Full electronic, interoperable tracing (November 2024)
Implementation:
python
import hashlib
from dataclasses import dataclass
from datetime import datetime
from typing import List, Optional

@dataclass
class ProductIdentifier:
    """
    DSCSA-compliant product identifier
    """
    gtin: str  # Global Trade Item Number (NDC in GTIN-14 format)
    serial_number: str
    lot_number: str
    expiration_date: datetime

    def to_serialized_string(self):
        """Convert to DSCSA format"""
        exp_date = self.expiration_date.strftime("%y%m%d")
        return f"(01){self.gtin}(21){self.serial_number}(10){self.lot_number}(17){exp_date}"

    @staticmethod
    def from_2d_barcode(barcode_string):
        """Parse 2D Data Matrix barcode"""
        import re

        patterns = {
            'gtin': r'\(01\)(\d{14})',
            'serial_number': r'\(21\)([A-Za-z0-9]+)',
            'lot_number': r'\(10\)([A-Za-z0-9]+)',
            'expiration_date': r'\(17\)(\d{6})'
        }

        data = {}
        for field, pattern in patterns.items():
            match = re.search(pattern, barcode_string)
            if match:
                value = match.group(1)
                if field == 'expiration_date':
                    data[field] = datetime.strptime(value, "%y%m%d")
                else:
                    data[field] = value

        return ProductIdentifier(**data) if data else None

@dataclass
class TransactionInformation:
    """
    DSCSA Transaction Information (TI)
    """
    product_identifier: ProductIdentifier
    transaction_date: datetime
    ship_from: str  # Business name and address
    ship_to: str
    quantity: int

@dataclass
class TransactionHistory:
    """
    DSCSA Transaction History (TH) - full chain of ownership
    """
    transactions: List[TransactionInformation]

    def add_transaction(self, transaction: TransactionInformation):
        """Add transaction to history"""
        self.transactions.append(transaction)

    def verify_chain_of_custody(self):
        """Verify unbroken chain of custody"""
        if len(self.transactions) < 2:
            return True

        for i in range(len(self.transactions) - 1):
            current = self.transactions[i]
            next_trans = self.transactions[i + 1]

            # Verify ship_to of current matches ship_from of next
            if current.ship_to != next_trans.ship_from:
                return False

        return True

@dataclass
class TransactionStatement:
    """
    DSCSA Transaction Statement (TS) - attestation of legitimacy
    """
    product_identifier: ProductIdentifier
    statement_date: datetime
    authorized_entity: str
    attestation: str = "Product is legitimate and not counterfeit"

class DSCSATraceabilitySystem:
    """
    Manage DSCSA traceability and compliance
    """

    def __init__(self, business_name, dea_number, license_number):
        self.business_name = business_name
        self.dea_number = dea_number
        self.license_number = license_number
        self.inventory = {}
        self.transactions = []

    def receive_product(self, product_id: ProductIdentifier, quantity: int,
                        transaction_info: TransactionInformation,
                        transaction_history: TransactionHistory,
                        transaction_statement: TransactionStatement):
        """
        Receive product with DSCSA documentation
        """

        # Verify transaction history
        if not transaction_history.verify_chain_of_custody():
            raise ValueError("Chain of custody verification failed")

        # Verify product identifier matches
        if product_id.serial_number != transaction_info.product_identifier.serial_number:
            raise ValueError("Product identifier mismatch")

        # Store product in inventory with TI/TH/TS
        inventory_key = f"{product_id.gtin}-{product_id.serial_number}"

        self.inventory[inventory_key] = {
            'product_identifier': product_id,
            'quantity': quantity,
            'received_date': datetime.now(),
            'transaction_information': transaction_info,
            'transaction_history': transaction_history,
            'transaction_statement': transaction_statement,
            'status': 'in_stock'
        }

        return inventory_key

    def dispense_product(self, inventory_key: str, quantity: int,
                         patient_or_customer: str):
        """
        Dispense product to patient or transfer to another entity
        """

        if inventory_key not in self.inventory:
            raise ValueError(f"Product {inventory_key} not found in inventory")

        product_record = self.inventory[inventory_key]

        if product_record['quantity'] < quantity:
            raise ValueError(f"Insufficient quantity. Available: {product_record['quantity']}")

        # Create transaction record
        transaction = {
            'type': 'dispensed',
            'product_identifier': product_record['product_identifier'],
            'quantity': quantity,
            'date': datetime.now(),
            'recipient': patient_or_customer
        }

        self.transactions.append(transaction)

        # Update inventory
        product_record['quantity'] -= quantity

        if product_record['quantity'] == 0:
            product_record['status'] = 'dispensed'

        return transaction

    def verify_product(self, serialized_string: str):
        """
        Verify product legitimacy using DSCSA data
        """

        product_id = ProductIdentifier.from_2d_barcode(serialized_string)

        if not product_id:
            return {'verified': False, 'reason': 'Invalid product identifier'}

        inventory_key = f"{product_id.gtin}-{product_id.serial_number}"

        if inventory_key in self.inventory:
            product = self.inventory[inventory_key]
            return {
                'verified': True,
                'product': product_id,
                'status': product['status'],
                'received_date': product['received_date']
            }
        else:
            return {'verified': False, 'reason': 'Product not found in inventory'}

    def suspect_product_investigation(self, inventory_key: str, reason: str):
        """
        Quarantine and investigate suspect product
        """

        if inventory_key not in self.inventory:
            raise ValueError(f"Product {inventory_key} not found")

        product = self.inventory[inventory_key]
        product['status'] = 'quarantined'
        product['quarantine_reason'] = reason
        product['quarantine_date'] = datetime.now()

        # Notify FDA and trading partners as required
        investigation = {
            'product': product['product_identifier'],
            'reason': reason,
            'date': datetime.now(),
            'actions_taken': 'Product quarantined, investigation initiated'
        }

        return investigation
要求:
  • 包装级别的产品追踪(序列化)
  • 验证产品合法性
  • 检测并响应可疑/非法产品
  • 用于追踪的系统和流程
时间线:
  • 2023年:增强药品配送安全性
  • 2024年:全面实现电子、可互操作的追踪(2024年11月)
实现代码:
python
import hashlib
from dataclasses import dataclass
from datetime import datetime
from typing import List, Optional

@dataclass
class ProductIdentifier:
    """
    DSCSA-compliant product identifier
    """
    gtin: str  # Global Trade Item Number (NDC in GTIN-14 format)
    serial_number: str
    lot_number: str
    expiration_date: datetime

    def to_serialized_string(self):
        """Convert to DSCSA format"""
        exp_date = self.expiration_date.strftime("%y%m%d")
        return f"(01){self.gtin}(21){self.serial_number}(10){self.lot_number}(17){exp_date}"

    @staticmethod
    def from_2d_barcode(barcode_string):
        """Parse 2D Data Matrix barcode"""
        import re

        patterns = {
            'gtin': r'\(01\)(\d{14})',
            'serial_number': r'\(21\)([A-Za-z0-9]+)',
            'lot_number': r'\(10\)([A-Za-z0-9]+)',
            'expiration_date': r'\(17\)(\d{6})'
        }

        data = {}
        for field, pattern in patterns.items():
            match = re.search(pattern, barcode_string)
            if match:
                value = match.group(1)
                if field == 'expiration_date':
                    data[field] = datetime.strptime(value, "%y%m%d")
                else:
                    data[field] = value

        return ProductIdentifier(**data) if data else None

@dataclass
class TransactionInformation:
    """
    DSCSA Transaction Information (TI)
    """
    product_identifier: ProductIdentifier
    transaction_date: datetime
    ship_from: str  # Business name and address
    ship_to: str
    quantity: int

@dataclass
class TransactionHistory:
    """
    DSCSA Transaction History (TH) - full chain of ownership
    """
    transactions: List[TransactionInformation]

    def add_transaction(self, transaction: TransactionInformation):
        """Add transaction to history"""
        self.transactions.append(transaction)

    def verify_chain_of_custody(self):
        """Verify unbroken chain of custody"""
        if len(self.transactions) < 2:
            return True

        for i in range(len(self.transactions) - 1):
            current = self.transactions[i]
            next_trans = self.transactions[i + 1]

            # Verify ship_to of current matches ship_from of next
            if current.ship_to != next_trans.ship_from:
                return False

        return True

@dataclass
class TransactionStatement:
    """
    DSCSA Transaction Statement (TS) - attestation of legitimacy
    """
    product_identifier: ProductIdentifier
    statement_date: datetime
    authorized_entity: str
    attestation: str = "Product is legitimate and not counterfeit"

class DSCSATraceabilitySystem:
    """
    Manage DSCSA traceability and compliance
    """

    def __init__(self, business_name, dea_number, license_number):
        self.business_name = business_name
        self.dea_number = dea_number
        self.license_number = license_number
        self.inventory = {}
        self.transactions = []

    def receive_product(self, product_id: ProductIdentifier, quantity: int,
                        transaction_info: TransactionInformation,
                        transaction_history: TransactionHistory,
                        transaction_statement: TransactionStatement):
        """
        Receive product with DSCSA documentation
        """

        # Verify transaction history
        if not transaction_history.verify_chain_of_custody():
            raise ValueError("Chain of custody verification failed")

        # Verify product identifier matches
        if product_id.serial_number != transaction_info.product_identifier.serial_number:
            raise ValueError("Product identifier mismatch")

        # Store product in inventory with TI/TH/TS
        inventory_key = f"{product_id.gtin}-{product_id.serial_number}"

        self.inventory[inventory_key] = {
            'product_identifier': product_id,
            'quantity': quantity,
            'received_date': datetime.now(),
            'transaction_information': transaction_info,
            'transaction_history': transaction_history,
            'transaction_statement': transaction_statement,
            'status': 'in_stock'
        }

        return inventory_key

    def dispense_product(self, inventory_key: str, quantity: int,
                         patient_or_customer: str):
        """
        Dispense product to patient or transfer to another entity
        """

        if inventory_key not in self.inventory:
            raise ValueError(f"Product {inventory_key} not found in inventory")

        product_record = self.inventory[inventory_key]

        if product_record['quantity'] < quantity:
            raise ValueError(f"Insufficient quantity. Available: {product_record['quantity']}")

        # Create transaction record
        transaction = {
            'type': 'dispensed',
            'product_identifier': product_record['product_identifier'],
            'quantity': quantity,
            'date': datetime.now(),
            'recipient': patient_or_customer
        }

        self.transactions.append(transaction)

        # Update inventory
        product_record['quantity'] -= quantity

        if product_record['quantity'] == 0:
            product_record['status'] = 'dispensed'

        return transaction

    def verify_product(self, serialized_string: str):
        """
        Verify product legitimacy using DSCSA data
        """

        product_id = ProductIdentifier.from_2d_barcode(serialized_string)

        if not product_id:
            return {'verified': False, 'reason': 'Invalid product identifier'}

        inventory_key = f"{product_id.gtin}-{product_id.serial_number}"

        if inventory_key in self.inventory:
            product = self.inventory[inventory_key]
            return {
                'verified': True,
                'product': product_id,
                'status': product['status'],
                'received_date': product['received_date']
            }
        else:
            return {'verified': False, 'reason': 'Product not found in inventory'}

    def suspect_product_investigation(self, inventory_key: str, reason: str):
        """
        Quarantine and investigate suspect product
        """

        if inventory_key not in self.inventory:
            raise ValueError(f"Product {inventory_key} not found")

        product = self.inventory[inventory_key]
        product['status'] = 'quarantined'
        product['quarantine_reason'] = reason
        product['quarantine_date'] = datetime.now()

        # Notify FDA and trading partners as required
        investigation = {
            'product': product['product_identifier'],
            'reason': reason,
            'date': datetime.now(),
            'actions_taken': 'Product quarantined, investigation initiated'
        }

        return investigation

Example usage

Example usage

dscsa_system = DSCSATraceabilitySystem( business_name="Memorial Hospital Pharmacy", dea_number="FM1234563", license_number="PHY-12345" )
dscsa_system = DSCSATraceabilitySystem( business_name="Memorial Hospital Pharmacy", dea_number="FM1234563", license_number="PHY-12345" )

Create product identifier

Create product identifier

product = ProductIdentifier( gtin="00300123456789", # NDC in GTIN-14 format serial_number="ABC123XYZ789", lot_number="LOT2024-A", expiration_date=datetime(2026, 12, 31) )
product = ProductIdentifier( gtin="00300123456789", # NDC in GTIN-14 format serial_number="ABC123XYZ789", lot_number="LOT2024-A", expiration_date=datetime(2026, 12, 31) )

Transaction information

Transaction information

trans_info = TransactionInformation( product_identifier=product, transaction_date=datetime.now(), ship_from="McKesson Corporation, 1234 Distributor Way", ship_to="Memorial Hospital Pharmacy, 5678 Hospital Blvd", quantity=100 )
trans_info = TransactionInformation( product_identifier=product, transaction_date=datetime.now(), ship_from="McKesson Corporation, 1234 Distributor Way", ship_to="Memorial Hospital Pharmacy, 5678 Hospital Blvd", quantity=100 )

Transaction history

Transaction history

trans_history = TransactionHistory(transactions=[trans_info])
trans_history = TransactionHistory(transactions=[trans_info])

Transaction statement

Transaction statement

trans_statement = TransactionStatement( product_identifier=product, statement_date=datetime.now(), authorized_entity="McKesson Corporation" )
trans_statement = TransactionStatement( product_identifier=product, statement_date=datetime.now(), authorized_entity="McKesson Corporation" )

Receive product

Receive product

inventory_key = dscsa_system.receive_product( product_id=product, quantity=100, transaction_info=trans_info, transaction_history=trans_history, transaction_statement=trans_statement )
print(f"Product received: {inventory_key}")
inventory_key = dscsa_system.receive_product( product_id=product, quantity=100, transaction_info=trans_info, transaction_history=trans_history, transaction_statement=trans_statement )
print(f"Product received: {inventory_key}")

Verify product

Verify product

barcode = product.to_serialized_string() verification = dscsa_system.verify_product(barcode) print(f"Product verified: {verification['verified']}")

---
barcode = product.to_serialized_string() verification = dscsa_system.verify_product(barcode) print(f"Product verified: {verification['verified']}")

---

Controlled Substance Management

受控物质管理

DEA Controlled Substance Schedules

DEA受控物质分级

Schedule I: No accepted medical use, high abuse potential
  • Examples: Heroin, LSD, marijuana (federally)
  • Not typically in pharmacy
Schedule II: High abuse potential, accepted medical use
  • Examples: Oxycodone, morphine, fentanyl, amphetamine, cocaine
  • Requirements: Written prescription (with exceptions), no refills, secure storage
Schedule III: Moderate abuse potential
  • Examples: Codeine/acetaminophen, ketamine, testosterone
  • Requirements: Written or electronic Rx, up to 5 refills in 6 months
Schedule IV: Low abuse potential
  • Examples: Alprazolam, diazepam, tramadol, zolpidem
  • Requirements: Written or electronic Rx, up to 5 refills in 6 months
Schedule V: Lowest abuse potential
  • Examples: Cough preparations with <200mg codeine
  • Requirements: May have OTC availability in some states
Schedule I: 无公认医疗用途,滥用潜力高
  • 示例:海洛因、LSD、大麻(联邦层面)
  • 通常不在药房中
Schedule II: 滥用潜力高,有公认医疗用途
  • 示例:羟考酮、吗啡、芬太尼、苯丙胺、可卡因
  • 要求:书面处方(有例外),不得续方,安全存储
Schedule III: 滥用潜力中等
  • 示例:可待因/对乙酰氨基酚、氯胺酮、睾酮
  • 要求:书面或电子处方,6个月内最多续方5次
Schedule IV: 滥用潜力低
  • 示例:阿普唑仑、地西泮、曲马多、唑吡坦
  • 要求:书面或电子处方,6个月内最多续方5次
Schedule V: 滥用潜力最低
  • 示例:含<200mg可待因的止咳制剂
  • 要求:部分州可作为非处方药销售

Perpetual Inventory System

永续库存系统

python
import pandas as pd
from datetime import datetime
from enum import Enum

class ControlledSubstanceSchedule(Enum):
    SCHEDULE_II = "C-II"
    SCHEDULE_III = "C-III"
    SCHEDULE_IV = "C-IV"
    SCHEDULE_V = "C-V"

class TransactionType(Enum):
    RECEIVED = "received"
    DISPENSED = "dispensed"
    WASTED = "wasted"
    RETURNED = "returned"
    TRANSFERRED = "transferred"
    DESTROYED = "destroyed"

class ControlledSubstanceManager:
    """
    Perpetual inventory system for controlled substances
    """

    def __init__(self, pharmacy_name, dea_number):
        self.pharmacy_name = pharmacy_name
        self.dea_number = dea_number
        self.inventory = {}
        self.transactions = []

    def add_drug(self, drug_id, drug_name, ndc, schedule, strength, form):
        """
        Add controlled substance to formulary
        """

        self.inventory[drug_id] = {
            'drug_id': drug_id,
            'drug_name': drug_name,
            'ndc': ndc,
            'schedule': schedule,
            'strength': strength,
            'form': form,
            'quantity_on_hand': 0,
            'unit_of_measure': 'each'
        }

    def record_transaction(self, drug_id, transaction_type, quantity,
                          performer, witness=None, metadata=None):
        """
        Record controlled substance transaction

        Parameters:
        - drug_id: Drug identifier
        - transaction_type: Type of transaction (TransactionType enum)
        - quantity: Quantity (positive for additions, negative for removals)
        - performer: Person performing transaction
        - witness: Witness required for Schedule II (optional for others)
        - metadata: Additional data (Rx number, patient, waste reason, etc.)
        """

        if drug_id not in self.inventory:
            raise ValueError(f"Drug {drug_id} not in inventory")

        drug = self.inventory[drug_id]

        # Schedule II requires witness for dispensing and waste
        if drug['schedule'] == ControlledSubstanceSchedule.SCHEDULE_II:
            if transaction_type in [TransactionType.DISPENSED, TransactionType.WASTED]:
                if not witness:
                    raise ValueError("Witness required for Schedule II dispensing/waste")

        # Create transaction record
        transaction = {
            'transaction_id': len(self.transactions) + 1,
            'timestamp': datetime.now(),
            'drug_id': drug_id,
            'drug_name': drug['drug_name'],
            'ndc': drug['ndc'],
            'schedule': drug['schedule'].value,
            'transaction_type': transaction_type.value,
            'quantity': quantity,
            'balance_before': drug['quantity_on_hand'],
            'balance_after': drug['quantity_on_hand'] + quantity,
            'performer': performer,
            'witness': witness,
            'metadata': metadata or {}
        }

        # Update inventory
        drug['quantity_on_hand'] += quantity

        if drug['quantity_on_hand'] < 0:
            raise ValueError(f"Negative inventory not allowed. Current: {drug['quantity_on_hand']}")

        # Store transaction
        self.transactions.append(transaction)

        return transaction

    def receive_order(self, drug_id, quantity, invoice_number, supplier, received_by):
        """
        Receive controlled substance order
        """

        return self.record_transaction(
            drug_id=drug_id,
            transaction_type=TransactionType.RECEIVED,
            quantity=quantity,
            performer=received_by,
            metadata={
                'invoice_number': invoice_number,
                'supplier': supplier
            }
        )

    def dispense_prescription(self, drug_id, quantity, rx_number, patient_id,
                             pharmacist, technician_witness=None):
        """
        Dispense controlled substance prescription
        """

        return self.record_transaction(
            drug_id=drug_id,
            transaction_type=TransactionType.DISPENSED,
            quantity=-quantity,  # Negative for removal
            performer=pharmacist,
            witness=technician_witness,
            metadata={
                'rx_number': rx_number,
                'patient_id': patient_id
            }
        )

    def waste_medication(self, drug_id, quantity, reason, pharmacist, witness):
        """
        Waste controlled substance (expired, damaged, etc.)
        """

        return self.record_transaction(
            drug_id=drug_id,
            transaction_type=TransactionType.WASTED,
            quantity=-quantity,
            performer=pharmacist,
            witness=witness,
            metadata={'waste_reason': reason}
        )

    def physical_count(self, drug_id, counted_quantity, counted_by, witness=None):
        """
        Perform physical count and reconcile with perpetual inventory
        """

        if drug_id not in self.inventory:
            raise ValueError(f"Drug {drug_id} not in inventory")

        drug = self.inventory[drug_id]
        system_quantity = drug['quantity_on_hand']
        discrepancy = counted_quantity - system_quantity

        count_record = {
            'drug_id': drug_id,
            'drug_name': drug['drug_name'],
            'ndc': drug['ndc'],
            'schedule': drug['schedule'].value,
            'count_date': datetime.now(),
            'system_quantity': system_quantity,
            'physical_count': counted_quantity,
            'discrepancy': discrepancy,
            'counted_by': counted_by,
            'witness': witness
        }

        return count_record

    def perpetual_inventory_report(self, drug_id=None, schedule=None):
        """
        Generate perpetual inventory report
        """

        transactions_df = pd.DataFrame(self.transactions)

        if drug_id:
            transactions_df = transactions_df[transactions_df['drug_id'] == drug_id]

        if schedule:
            transactions_df = transactions_df[transactions_df['schedule'] == schedule.value]

        return transactions_df

    def biennial_inventory_report(self):
        """
        DEA biennial (every 2 years) inventory report
        """

        inventory_list = []

        for drug_id, drug in self.inventory.items():
            inventory_list.append({
                'drug_name': drug['drug_name'],
                'ndc': drug['ndc'],
                'schedule': drug['schedule'].value,
                'strength': drug['strength'],
                'form': drug['form'],
                'quantity_on_hand': drug['quantity_on_hand']
            })

        inventory_df = pd.DataFrame(inventory_list)
        inventory_df = inventory_df.sort_values(['schedule', 'drug_name'])

        report = {
            'pharmacy_name': self.pharmacy_name,
            'dea_number': self.dea_number,
            'report_date': datetime.now(),
            'inventory': inventory_df
        }

        return report
python
import pandas as pd
from datetime import datetime
from enum import Enum

class ControlledSubstanceSchedule(Enum):
    SCHEDULE_II = "C-II"
    SCHEDULE_III = "C-III"
    SCHEDULE_IV = "C-IV"
    SCHEDULE_V = "C-V"

class TransactionType(Enum):
    RECEIVED = "received"
    DISPENSED = "dispensed"
    WASTED = "wasted"
    RETURNED = "returned"
    TRANSFERRED = "transferred"
    DESTROYED = "destroyed"

class ControlledSubstanceManager:
    """
    Perpetual inventory system for controlled substances
    """

    def __init__(self, pharmacy_name, dea_number):
        self.pharmacy_name = pharmacy_name
        self.dea_number = dea_number
        self.inventory = {}
        self.transactions = []

    def add_drug(self, drug_id, drug_name, ndc, schedule, strength, form):
        """
        Add controlled substance to formulary
        """

        self.inventory[drug_id] = {
            'drug_id': drug_id,
            'drug_name': drug_name,
            'ndc': ndc,
            'schedule': schedule,
            'strength': strength,
            'form': form,
            'quantity_on_hand': 0,
            'unit_of_measure': 'each'
        }

    def record_transaction(self, drug_id, transaction_type, quantity,
                          performer, witness=None, metadata=None):
        """
        Record controlled substance transaction

        Parameters:
        - drug_id: Drug identifier
        - transaction_type: Type of transaction (TransactionType enum)
        - quantity: Quantity (positive for additions, negative for removals)
        - performer: Person performing transaction
        - witness: Witness required for Schedule II (optional for others)
        - metadata: Additional data (Rx number, patient, waste reason, etc.)
        """

        if drug_id not in self.inventory:
            raise ValueError(f"Drug {drug_id} not in inventory")

        drug = self.inventory[drug_id]

        # Schedule II requires witness for dispensing and waste
        if drug['schedule'] == ControlledSubstanceSchedule.SCHEDULE_II:
            if transaction_type in [TransactionType.DISPENSED, TransactionType.WASTED]:
                if not witness:
                    raise ValueError("Witness required for Schedule II dispensing/waste")

        # Create transaction record
        transaction = {
            'transaction_id': len(self.transactions) + 1,
            'timestamp': datetime.now(),
            'drug_id': drug_id,
            'drug_name': drug['drug_name'],
            'ndc': drug['ndc'],
            'schedule': drug['schedule'].value,
            'transaction_type': transaction_type.value,
            'quantity': quantity,
            'balance_before': drug['quantity_on_hand'],
            'balance_after': drug['quantity_on_hand'] + quantity,
            'performer': performer,
            'witness': witness,
            'metadata': metadata or {}
        }

        # Update inventory
        drug['quantity_on_hand'] += quantity

        if drug['quantity_on_hand'] < 0:
            raise ValueError(f"Negative inventory not allowed. Current: {drug['quantity_on_hand']}")

        # Store transaction
        self.transactions.append(transaction)

        return transaction

    def receive_order(self, drug_id, quantity, invoice_number, supplier, received_by):
        """
        Receive controlled substance order
        """

        return self.record_transaction(
            drug_id=drug_id,
            transaction_type=TransactionType.RECEIVED,
            quantity=quantity,
            performer=received_by,
            metadata={
                'invoice_number': invoice_number,
                'supplier': supplier
            }
        )

    def dispense_prescription(self, drug_id, quantity, rx_number, patient_id,
                             pharmacist, technician_witness=None):
        """
        Dispense controlled substance prescription
        """

        return self.record_transaction(
            drug_id=drug_id,
            transaction_type=TransactionType.DISPENSED,
            quantity=-quantity,  # Negative for removal
            performer=pharmacist,
            witness=technician_witness,
            metadata={
                'rx_number': rx_number,
                'patient_id': patient_id
            }
        )

    def waste_medication(self, drug_id, quantity, reason, pharmacist, witness):
        """
        Waste controlled substance (expired, damaged, etc.)
        """

        return self.record_transaction(
            drug_id=drug_id,
            transaction_type=TransactionType.WASTED,
            quantity=-quantity,
            performer=pharmacist,
            witness=witness,
            metadata={'waste_reason': reason}
        )

    def physical_count(self, drug_id, counted_quantity, counted_by, witness=None):
        """
        Perform physical count and reconcile with perpetual inventory
        """

        if drug_id not in self.inventory:
            raise ValueError(f"Drug {drug_id} not in inventory")

        drug = self.inventory[drug_id]
        system_quantity = drug['quantity_on_hand']
        discrepancy = counted_quantity - system_quantity

        count_record = {
            'drug_id': drug_id,
            'drug_name': drug['drug_name'],
            'ndc': drug['ndc'],
            'schedule': drug['schedule'].value,
            'count_date': datetime.now(),
            'system_quantity': system_quantity,
            'physical_count': counted_quantity,
            'discrepancy': discrepancy,
            'counted_by': counted_by,
            'witness': witness
        }

        return count_record

    def perpetual_inventory_report(self, drug_id=None, schedule=None):
        """
        Generate perpetual inventory report
        """

        transactions_df = pd.DataFrame(self.transactions)

        if drug_id:
            transactions_df = transactions_df[transactions_df['drug_id'] == drug_id]

        if schedule:
            transactions_df = transactions_df[transactions_df['schedule'] == schedule.value]

        return transactions_df

    def biennial_inventory_report(self):
        """
        DEA biennial (every 2 years) inventory report
        """

        inventory_list = []

        for drug_id, drug in self.inventory.items():
            inventory_list.append({
                'drug_name': drug['drug_name'],
                'ndc': drug['ndc'],
                'schedule': drug['schedule'].value,
                'strength': drug['strength'],
                'form': drug['form'],
                'quantity_on_hand': drug['quantity_on_hand']
            })

        inventory_df = pd.DataFrame(inventory_list)
        inventory_df = inventory_df.sort_values(['schedule', 'drug_name'])

        report = {
            'pharmacy_name': self.pharmacy_name,
            'dea_number': self.dea_number,
            'report_date': datetime.now(),
            'inventory': inventory_df
        }

        return report

Example usage

Example usage

cs_manager = ControlledSubstanceManager( pharmacy_name="Memorial Hospital Pharmacy", dea_number="FM1234563" )
cs_manager = ControlledSubstanceManager( pharmacy_name="Memorial Hospital Pharmacy", dea_number="FM1234563" )

Add controlled substances to formulary

Add controlled substances to formulary

cs_manager.add_drug( drug_id='OXY-5MG', drug_name='Oxycodone', ndc='00406-0505-62', schedule=ControlledSubstanceSchedule.SCHEDULE_II, strength='5mg', form='Tablet' )
cs_manager.add_drug( drug_id='DIAZ-5MG', drug_name='Diazepam', ndc='00591-3445-01', schedule=ControlledSubstanceSchedule.SCHEDULE_IV, strength='5mg', form='Tablet' )
cs_manager.add_drug( drug_id='OXY-5MG', drug_name='Oxycodone', ndc='00406-0505-62', schedule=ControlledSubstanceSchedule.SCHEDULE_II, strength='5mg', form='Tablet' )
cs_manager.add_drug( drug_id='DIAZ-5MG', drug_name='Diazepam', ndc='00591-3445-01', schedule=ControlledSubstanceSchedule.SCHEDULE_IV, strength='5mg', form='Tablet' )

Receive order

Receive order

cs_manager.receive_order( drug_id='OXY-5MG', quantity=500, invoice_number='INV-123456', supplier='McKesson', received_by='RPh John Smith' )
cs_manager.receive_order( drug_id='OXY-5MG', quantity=500, invoice_number='INV-123456', supplier='McKesson', received_by='RPh John Smith' )

Dispense prescriptions

Dispense prescriptions

cs_manager.dispense_prescription( drug_id='OXY-5MG', quantity=30, rx_number='RX-001234', patient_id='PT-567890', pharmacist='RPh John Smith', technician_witness='Tech Jane Doe' # Schedule II requires witness )
cs_manager.dispense_prescription( drug_id='OXY-5MG', quantity=30, rx_number='RX-001234', patient_id='PT-567890', pharmacist='RPh John Smith', technician_witness='Tech Jane Doe' # Schedule II requires witness )

Waste expired medication

Waste expired medication

cs_manager.waste_medication( drug_id='OXY-5MG', quantity=10, reason='Expired', pharmacist='RPh John Smith', witness='RPh Mary Johnson' )
cs_manager.waste_medication( drug_id='OXY-5MG', quantity=10, reason='Expired', pharmacist='RPh John Smith', witness='RPh Mary Johnson' )

Physical count

Physical count

count = cs_manager.physical_count( drug_id='OXY-5MG', counted_quantity=460, counted_by='RPh John Smith', witness='RPh Mary Johnson' )
print(f"Physical Count - Expected: {count['system_quantity']}, Counted: {count['physical_count']}, Discrepancy: {count['discrepancy']}")
count = cs_manager.physical_count( drug_id='OXY-5MG', counted_quantity=460, counted_by='RPh John Smith', witness='RPh Mary Johnson' )
print(f"Physical Count - Expected: {count['system_quantity']}, Counted: {count['physical_count']}, Discrepancy: {count['discrepancy']}")

Generate perpetual inventory report

Generate perpetual inventory report

report = cs_manager.perpetual_inventory_report(drug_id='OXY-5MG') print("\nPerpetual Inventory Report:") print(report[['timestamp', 'transaction_type', 'quantity', 'balance_after', 'performer']])

---
report = cs_manager.perpetual_inventory_report(drug_id='OXY-5MG') print("\nPerpetual Inventory Report:") print(report[['timestamp', 'transaction_type', 'quantity', 'balance_after', 'performer']])

---

340B Program Compliance

340B项目合规

340B Drug Pricing Program

340B药品定价项目

Overview:
  • Federal program requiring manufacturers to provide outpatient drugs at reduced prices
  • Eligible entities: Safety-net providers (hospitals, FQHCs, Ryan White clinics)
  • Savings can be 20-50% off wholesale acquisition cost
  • Complex compliance requirements
Key Compliance Requirements:
  1. Patient eligibility determination
  2. Drug diversion prevention
  3. Duplicate discount prevention
  4. Accurate record-keeping
  5. Contract pharmacy compliance
python
class Patient340BEligibility:
    """
    Determine 340B patient eligibility
    """

    def __init__(self, covered_entity_id, entity_type):
        self.covered_entity_id = covered_entity_id
        self.entity_type = entity_type  # DSH, PED, CAH, FQHC, etc.

    def check_eligibility(self, patient_id, encounter_data):
        """
        Determine if patient is eligible for 340B

        Patient must meet all criteria:
        1. Established relationship with covered entity
        2. Received healthcare service from covered entity
        3. Covered entity has responsibility for care
        4. Drug prescribed by provider of covered entity
        5. Drug dispensed by eligible pharmacy
        """

        criteria = {
            'established_patient': self._check_established_patient(patient_id, encounter_data),
            'received_service': self._check_service_received(encounter_data),
            'provider_responsibility': self._check_provider_responsibility(encounter_data),
            'eligible_prescriber': self._check_eligible_prescriber(encounter_data),
            'eligible_pharmacy': self._check_eligible_pharmacy(encounter_data)
        }

        # All criteria must be met
        eligible = all(criteria.values())

        return {
            'eligible': eligible,
            'criteria_results': criteria,
            'reason': self._eligibility_reason(criteria) if not eligible else 'Meets all criteria'
        }

    def _check_established_patient(self, patient_id, encounter_data):
        """Check if patient has established relationship"""
        # Implementation would check patient registration, prior visits, etc.
        return encounter_data.get('established_patient', False)

    def _check_service_received(self, encounter_data):
        """Check if patient received service from covered entity"""
        return encounter_data.get('service_location') == self.covered_entity_id

    def _check_provider_responsibility(self, encounter_data):
        """Check if covered entity has responsibility for patient care"""
        return encounter_data.get('responsible_entity') == self.covered_entity_id

    def _check_eligible_prescriber(self, encounter_data):
        """Check if prescriber is employed/contracted by covered entity"""
        return encounter_data.get('prescriber_entity') == self.covered_entity_id

    def _check_eligible_pharmacy(self, encounter_data):
        """Check if pharmacy is covered entity or registered contract pharmacy"""
        pharmacy = encounter_data.get('dispensing_pharmacy')
        return pharmacy in [self.covered_entity_id] or \
               pharmacy in self._get_contract_pharmacies()

    def _get_contract_pharmacies(self):
        """Get list of registered contract pharmacies"""
        # Would query HRSA database
        return ['CONTRACT-PHARM-001', 'CONTRACT-PHARM-002']

    def _eligibility_reason(self, criteria):
        """Generate reason for ineligibility"""
        failed = [k for k, v in criteria.items() if not v]
        return f"Failed criteria: {', '.join(failed)}"

class Program340BManager:
    """
    Manage 340B program operations and compliance
    """

    def __init__(self, covered_entity_id):
        self.covered_entity_id = covered_entity_id
        self.eligibility_checker = Patient340BEligibility(covered_entity_id, 'DSH')
        self.purchases = []
        self.dispenses = []

    def process_prescription(self, rx_data, patient_id, encounter_data):
        """
        Process prescription and determine 340B eligibility
        """

        # Check patient eligibility
        eligibility = self.eligibility_checker.check_eligibility(patient_id, encounter_data)

        # Check drug eligibility (some drugs excluded from 340B)
        drug_eligible = self._check_drug_eligibility(rx_data['ndc'])

        # Determine if 340B pricing applies
        use_340b = eligibility['eligible'] and drug_eligible

        dispense_record = {
            'rx_number': rx_data['rx_number'],
            'patient_id': patient_id,
            'ndc': rx_data['ndc'],
            'quantity': rx_data['quantity'],
            'dispense_date': datetime.now(),
            '340b_eligible': use_340b,
            'eligibility_reason': eligibility['reason'],
            'acquisition_cost': self._get_acquisition_cost(rx_data['ndc'], use_340b)
        }

        self.dispenses.append(dispense_record)

        return dispense_record

    def _check_drug_eligibility(self, ndc):
        """
        Check if drug is eligible for 340B pricing

        Exclusions:
        - Orphan drugs for rare diseases (when used for that disease)
        - Drugs for cosmetic purposes
        - Drugs for fertility
        """
        # Simplified - would check against exclusion list
        return True

    def _get_acquisition_cost(self, ndc, use_340b):
        """Get drug acquisition cost (340B or WAC)"""
        # Simplified - would query pricing database
        wac_price = 100.00
        price_340b = wac_price * 0.60  # Typical 40% discount

        return price_340b if use_340b else wac_price

    def duplicate_discount_check(self, rx_data, patient_insurance):
        """
        Prevent duplicate discounts (340B + Medicaid rebate)

        Covered entities cannot receive 340B discount AND Medicaid rebate
        """

        is_medicaid = patient_insurance.get('payer_type') == 'Medicaid'
        is_340b = rx_data.get('340b_eligible', False)

        if is_medicaid and is_340b:
            # Options:
            # 1. Carve-out: Don't bill Medicaid, use 340B
            # 2. Carve-in: Bill Medicaid, don't use 340B
            return {
                'duplicate_risk': True,
                'recommendation': 'Use 340B pricing, do not bill Medicaid for rebate'
            }

        return {'duplicate_risk': False}

    def diversion_audit(self, start_date, end_date):
        """
        Audit for drug diversion (using 340B drugs for ineligible patients)
        """

        dispenses_df = pd.DataFrame(self.dispenses)

        # Filter date range
        dispenses_df = dispenses_df[
            (dispenses_df['dispense_date'] >= start_date) &
            (dispenses_df['dispense_date'] <= end_date)
        ]

        # Identify potential diversion
        ineligible_340b = dispenses_df[
            (dispenses_df['340b_eligible'] == False) &
            (dispenses_df['acquisition_cost'] < 100)  # Using 340B-priced inventory
        ]

        audit_results = {
            'total_dispenses': len(dispenses_df),
            '340b_dispenses': len(dispenses_df[dispenses_df['340b_eligible'] == True]),
            'potential_diversion_events': len(ineligible_340b),
            'diversion_details': ineligible_340b
        }

        return audit_results
概述:
  • 联邦项目,要求制造商以优惠价格提供门诊药品
  • 合格实体:安全网提供者(医院、FQHC、Ryan White诊所)
  • 可节省批发采购成本的20-50%
  • 复杂的合规要求
关键合规要求:
  1. 患者资格判定
  2. 药品 diversion 预防
  3. 重复折扣预防
  4. 准确记录保存
  5. 合同药房合规
python
class Patient340BEligibility:
    """
    Determine 340B patient eligibility
    """

    def __init__(self, covered_entity_id, entity_type):
        self.covered_entity_id = covered_entity_id
        self.entity_type = entity_type  # DSH, PED, CAH, FQHC, etc.

    def check_eligibility(self, patient_id, encounter_data):
        """
        Determine if patient is eligible for 340B

        Patient must meet all criteria:
        1. Established relationship with covered entity
        2. Received healthcare service from covered entity
        3. Covered entity has responsibility for care
        4. Drug prescribed by provider of covered entity
        5. Drug dispensed by eligible pharmacy
        """

        criteria = {
            'established_patient': self._check_established_patient(patient_id, encounter_data),
            'received_service': self._check_service_received(encounter_data),
            'provider_responsibility': self._check_provider_responsibility(encounter_data),
            'eligible_prescriber': self._check_eligible_prescriber(encounter_data),
            'eligible_pharmacy': self._check_eligible_pharmacy(encounter_data)
        }

        # All criteria must be met
        eligible = all(criteria.values())

        return {
            'eligible': eligible,
            'criteria_results': criteria,
            'reason': self._eligibility_reason(criteria) if not eligible else 'Meets all criteria'
        }

    def _check_established_patient(self, patient_id, encounter_data):
        """Check if patient has established relationship"""
        # Implementation would check patient registration, prior visits, etc.
        return encounter_data.get('established_patient', False)

    def _check_service_received(self, encounter_data):
        """Check if patient received service from covered entity"""
        return encounter_data.get('service_location') == self.covered_entity_id

    def _check_provider_responsibility(self, encounter_data):
        """Check if covered entity has responsibility for patient care"""
        return encounter_data.get('responsible_entity') == self.covered_entity_id

    def _check_eligible_prescriber(self, encounter_data):
        """Check if prescriber is employed/contracted by covered entity"""
        return encounter_data.get('prescriber_entity') == self.covered_entity_id

    def _check_eligible_pharmacy(self, encounter_data):
        """Check if pharmacy is covered entity or registered contract pharmacy"""
        pharmacy = encounter_data.get('dispensing_pharmacy')
        return pharmacy in [self.covered_entity_id] or \
               pharmacy in self._get_contract_pharmacies()

    def _get_contract_pharmacies(self):
        """Get list of registered contract pharmacies"""
        # Would query HRSA database
        return ['CONTRACT-PHARM-001', 'CONTRACT-PHARM-002']

    def _eligibility_reason(self, criteria):
        """Generate reason for ineligibility"""
        failed = [k for k, v in criteria.items() if not v]
        return f"Failed criteria: {', '.join(failed)}"

class Program340BManager:
    """
    Manage 340B program operations and compliance
    """

    def __init__(self, covered_entity_id):
        self.covered_entity_id = covered_entity_id
        self.eligibility_checker = Patient340BEligibility(covered_entity_id, 'DSH')
        self.purchases = []
        self.dispenses = []

    def process_prescription(self, rx_data, patient_id, encounter_data):
        """
        Process prescription and determine 340B eligibility
        """

        # Check patient eligibility
        eligibility = self.eligibility_checker.check_eligibility(patient_id, encounter_data)

        # Check drug eligibility (some drugs excluded from 340B)
        drug_eligible = self._check_drug_eligibility(rx_data['ndc'])

        # Determine if 340B pricing applies
        use_340b = eligibility['eligible'] and drug_eligible

        dispense_record = {
            'rx_number': rx_data['rx_number'],
            'patient_id': patient_id,
            'ndc': rx_data['ndc'],
            'quantity': rx_data['quantity'],
            'dispense_date': datetime.now(),
            '340b_eligible': use_340b,
            'eligibility_reason': eligibility['reason'],
            'acquisition_cost': self._get_acquisition_cost(rx_data['ndc'], use_340b)
        }

        self.dispenses.append(dispense_record)

        return dispense_record

    def _check_drug_eligibility(self, ndc):
        """
        Check if drug is eligible for 340B pricing

        Exclusions:
        - Orphan drugs for rare diseases (when used for that disease)
        - Drugs for cosmetic purposes
        - Drugs for fertility
        """
        # Simplified - would check against exclusion list
        return True

    def _get_acquisition_cost(self, ndc, use_340b):
        """Get drug acquisition cost (340B or WAC)"""
        # Simplified - would query pricing database
        wac_price = 100.00
        price_340b = wac_price * 0.60  # Typical 40% discount

        return price_340b if use_340b else wac_price

    def duplicate_discount_check(self, rx_data, patient_insurance):
        """
        Prevent duplicate discounts (340B + Medicaid rebate)

        Covered entities cannot receive 340B discount AND Medicaid rebate
        """

        is_medicaid = patient_insurance.get('payer_type') == 'Medicaid'
        is_340b = rx_data.get('340b_eligible', False)

        if is_medicaid and is_340b:
            # Options:
            # 1. Carve-out: Don't bill Medicaid, use 340B
            # 2. Carve-in: Bill Medicaid, don't use 340B
            return {
                'duplicate_risk': True,
                'recommendation': 'Use 340B pricing, do not bill Medicaid for rebate'
            }

        return {'duplicate_risk': False}

    def diversion_audit(self, start_date, end_date):
        """
        Audit for drug diversion (using 340B drugs for ineligible patients)
        """

        dispenses_df = pd.DataFrame(self.dispenses)

        # Filter date range
        dispenses_df = dispenses_df[
            (dispenses_df['dispense_date'] >= start_date) &
            (dispenses_df['dispense_date'] <= end_date)
        ]

        # Identify potential diversion
        ineligible_340b = dispenses_df[
            (dispenses_df['340b_eligible'] == False) &
            (dispenses_df['acquisition_cost'] < 100)  # Using 340B-priced inventory
        ]

        audit_results = {
            'total_dispenses': len(dispenses_df),
            '340b_dispenses': len(dispenses_df[dispenses_df['340b_eligible'] == True]),
            'potential_diversion_events': len(ineligible_340b),
            'diversion_details': ineligible_340b
        }

        return audit_results

Example usage

Example usage

program_340b = Program340BManager(covered_entity_id='CE-001')
program_340b = Program340BManager(covered_entity_id='CE-001')

Process prescription

Process prescription

rx = { 'rx_number': 'RX-123456', 'ndc': '00406-0505-62', 'quantity': 30 }
encounter = { 'established_patient': True, 'service_location': 'CE-001', 'responsible_entity': 'CE-001', 'prescriber_entity': 'CE-001', 'dispensing_pharmacy': 'CE-001' }
dispense = program_340b.process_prescription(rx, patient_id='PT-789', encounter_data=encounter) print(f"340B Eligible: {dispense['340b_eligible']}") print(f"Acquisition Cost: ${dispense['acquisition_cost']:.2f}")
rx = { 'rx_number': 'RX-123456', 'ndc': '00406-0505-62', 'quantity': 30 }
encounter = { 'established_patient': True, 'service_location': 'CE-001', 'responsible_entity': 'CE-001', 'prescriber_entity': 'CE-001', 'dispensing_pharmacy': 'CE-001' }
dispense = program_340b.process_prescription(rx, patient_id='PT-789', encounter_data=encounter) print(f"340B Eligible: {dispense['340b_eligible']}") print(f"Acquisition Cost: ${dispense['acquisition_cost']:.2f}")

Duplicate discount check

Duplicate discount check

insurance = {'payer_type': 'Medicaid', 'member_id': 'MCD123456'} duplicate_check = program_340b.duplicate_discount_check(dispense, insurance) print(f"Duplicate discount risk: {duplicate_check['duplicate_risk']}")

---
insurance = {'payer_type': 'Medicaid', 'member_id': 'MCD123456'} duplicate_check = program_340b.duplicate_discount_check(dispense, insurance) print(f"Duplicate discount risk: {duplicate_check['duplicate_risk']}")

---

Drug Shortage Management

药品短缺管理

Shortage Response Framework

短缺响应框架

python
import pandas as pd
from datetime import datetime, timedelta

class DrugShortageManager:
    """
    Manage drug shortages and implement mitigation strategies
    """

    def __init__(self, pharmacy_name):
        self.pharmacy_name = pharmacy_name
        self.shortages = []
        self.inventory = {}

    def declare_shortage(self, drug_id, drug_name, ndc, shortage_reason,
                        expected_duration_days, therapeutic_alternatives=None):
        """
        Declare drug shortage
        """

        shortage = {
            'shortage_id': f"SHORT-{len(self.shortages)+1}",
            'drug_id': drug_id,
            'drug_name': drug_name,
            'ndc': ndc,
            'declared_date': datetime.now(),
            'shortage_reason': shortage_reason,
            'expected_resolution': datetime.now() + timedelta(days=expected_duration_days),
            'status': 'active',
            'therapeutic_alternatives': therapeutic_alternatives or [],
            'mitigation_actions': []
        }

        self.shortages.append(shortage)

        return shortage

    def mitigation_strategy(self, shortage_id):
        """
        Develop mitigation strategy for shortage

        Strategies:
        1. Therapeutic substitution
        2. Dosage form modification
        3. Conservation (restrict to critical patients)
        4. Alternative suppliers
        5. Compounding
        """

        shortage = next((s for s in self.shortages if s['shortage_id'] == shortage_id), None)

        if not shortage:
            raise ValueError(f"Shortage {shortage_id} not found")

        strategies = []

        # Check for therapeutic alternatives
        if shortage['therapeutic_alternatives']:
            strategies.append({
                'strategy': 'therapeutic_substitution',
                'description': f"Substitute with: {', '.join(shortage['therapeutic_alternatives'])}",
                'priority': 1
            })

        # Check current inventory
        current_qty = self.inventory.get(shortage['drug_id'], {}).get('quantity', 0)
        days_supply = self._calculate_days_supply(shortage['drug_id'], current_qty)

        if days_supply < 7:
            strategies.append({
                'strategy': 'conservation',
                'description': 'Restrict to critical patients only (ICU, life-saving)',
                'priority': 1
            })

        # Alternative sourcing
        strategies.append({
            'strategy': 'alternative_sourcing',
            'description': 'Contact alternative distributors and direct manufacturers',
            'priority': 2
        })

        # Compounding option (if appropriate)
        if self._can_compound(shortage['drug_id']):
            strategies.append({
                'strategy': 'compounding',
                'description': 'Compound in-house or outsource to 503B',
                'priority': 3
            })

        shortage['mitigation_actions'] = strategies

        return strategies

    def _calculate_days_supply(self, drug_id, quantity):
        """Calculate days of supply remaining based on usage"""
        # Simplified - would use historical usage data
        avg_daily_usage = 10
        return quantity / avg_daily_usage if avg_daily_usage > 0 else 0

    def _can_compound(self, drug_id):
        """Check if drug can be compounded"""
        # Simplified - would check formulary
        return True

    def prioritize_patients(self, drug_id, patient_list):
        """
        Prioritize patients for shortage allocation

        Priority levels:
        1. Life-saving/critical care
        2. Prevent serious morbidity
        3. Symptomatic relief
        """

        prioritized = []

        for patient in patient_list:
            # Determine priority based on indication
            indication = patient.get('indication', '')

            if any(critical in indication.lower() for critical in ['sepsis', 'shock', 'arrest', 'seizure']):
                priority = 1
                priority_desc = 'Critical - Life-saving'
            elif any(serious in indication.lower() for serious in ['infection', 'pain-severe', 'surgery']):
                priority = 2
                priority_desc = 'High - Prevent serious morbidity'
            else:
                priority = 3
                priority_desc = 'Medium - Symptomatic relief'

            prioritized.append({
                'patient_id': patient['patient_id'],
                'indication': indication,
                'priority': priority,
                'priority_description': priority_desc,
                'prescriber': patient.get('prescriber'),
                'requested_quantity': patient.get('quantity')
            })

        # Sort by priority
        prioritized.sort(key=lambda x: x['priority'])

        return pd.DataFrame(prioritized)

    def shortage_report(self):
        """
        Generate active shortages report
        """

        active_shortages = [s for s in self.shortages if s['status'] == 'active']

        if not active_shortages:
            return None

        report = []

        for shortage in active_shortages:
            current_qty = self.inventory.get(shortage['drug_id'], {}).get('quantity', 0)
            days_supply = self._calculate_days_supply(shortage['drug_id'], current_qty)

            report.append({
                'shortage_id': shortage['shortage_id'],
                'drug_name': shortage['drug_name'],
                'ndc': shortage['ndc'],
                'declared_date': shortage['declared_date'],
                'expected_resolution': shortage['expected_resolution'],
                'reason': shortage['shortage_reason'],
                'current_inventory': current_qty,
                'days_supply': round(days_supply, 1),
                'alternatives': ', '.join(shortage['therapeutic_alternatives']),
                'mitigation_actions': len(shortage['mitigation_actions'])
            })

        return pd.DataFrame(report)
python
import pandas as pd
from datetime import datetime, timedelta

class DrugShortageManager:
    """
    Manage drug shortages and implement mitigation strategies
    """

    def __init__(self, pharmacy_name):
        self.pharmacy_name = pharmacy_name
        self.shortages = []
        self.inventory = {}

    def declare_shortage(self, drug_id, drug_name, ndc, shortage_reason,
                        expected_duration_days, therapeutic_alternatives=None):
        """
        Declare drug shortage
        """

        shortage = {
            'shortage_id': f"SHORT-{len(self.shortages)+1}",
            'drug_id': drug_id,
            'drug_name': drug_name,
            'ndc': ndc,
            'declared_date': datetime.now(),
            'shortage_reason': shortage_reason,
            'expected_resolution': datetime.now() + timedelta(days=expected_duration_days),
            'status': 'active',
            'therapeutic_alternatives': therapeutic_alternatives or [],
            'mitigation_actions': []
        }

        self.shortages.append(shortage)

        return shortage

    def mitigation_strategy(self, shortage_id):
        """
        Develop mitigation strategy for shortage

        Strategies:
        1. Therapeutic substitution
        2. Dosage form modification
        3. Conservation (restrict to critical patients)
        4. Alternative suppliers
        5. Compounding
        """

        shortage = next((s for s in self.shortages if s['shortage_id'] == shortage_id), None)

        if not shortage:
            raise ValueError(f"Shortage {shortage_id} not found")

        strategies = []

        # Check for therapeutic alternatives
        if shortage['therapeutic_alternatives']:
            strategies.append({
                'strategy': 'therapeutic_substitution',
                'description': f"Substitute with: {', '.join(shortage['therapeutic_alternatives'])}",
                'priority': 1
            })

        # Check current inventory
        current_qty = self.inventory.get(shortage['drug_id'], {}).get('quantity', 0)
        days_supply = self._calculate_days_supply(shortage['drug_id'], current_qty)

        if days_supply < 7:
            strategies.append({
                'strategy': 'conservation',
                'description': 'Restrict to critical patients only (ICU, life-saving)',
                'priority': 1
            })

        # Alternative sourcing
        strategies.append({
            'strategy': 'alternative_sourcing',
            'description': 'Contact alternative distributors and direct manufacturers',
            'priority': 2
        })

        # Compounding option (if appropriate)
        if self._can_compound(shortage['drug_id']):
            strategies.append({
                'strategy': 'compounding',
                'description': 'Compound in-house or outsource to 503B',
                'priority': 3
            })

        shortage['mitigation_actions'] = strategies

        return strategies

    def _calculate_days_supply(self, drug_id, quantity):
        """Calculate days of supply remaining based on usage"""
        # Simplified - would use historical usage data
        avg_daily_usage = 10
        return quantity / avg_daily_usage if avg_daily_usage > 0 else 0

    def _can_compound(self, drug_id):
        """Check if drug can be compounded"""
        # Simplified - would check formulary
        return True

    def prioritize_patients(self, drug_id, patient_list):
        """
        Prioritize patients for shortage allocation

        Priority levels:
        1. Life-saving/critical care
        2. Prevent serious morbidity
        3. Symptomatic relief
        """

        prioritized = []

        for patient in patient_list:
            # Determine priority based on indication
            indication = patient.get('indication', '')

            if any(critical in indication.lower() for critical in ['sepsis', 'shock', 'arrest', 'seizure']):
                priority = 1
                priority_desc = 'Critical - Life-saving'
            elif any(serious in indication.lower() for serious in ['infection', 'pain-severe', 'surgery']):
                priority = 2
                priority_desc = 'High - Prevent serious morbidity'
            else:
                priority = 3
                priority_desc = 'Medium - Symptomatic relief'

            prioritized.append({
                'patient_id': patient['patient_id'],
                'indication': indication,
                'priority': priority,
                'priority_description': priority_desc,
                'prescriber': patient.get('prescriber'),
                'requested_quantity': patient.get('quantity')
            })

        # Sort by priority
        prioritized.sort(key=lambda x: x['priority'])

        return pd.DataFrame(prioritized)

    def shortage_report(self):
        """
        Generate active shortages report
        """

        active_shortages = [s for s in self.shortages if s['status'] == 'active']

        if not active_shortages:
            return None

        report = []

        for shortage in active_shortages:
            current_qty = self.inventory.get(shortage['drug_id'], {}).get('quantity', 0)
            days_supply = self._calculate_days_supply(shortage['drug_id'], current_qty)

            report.append({
                'shortage_id': shortage['shortage_id'],
                'drug_name': shortage['drug_name'],
                'ndc': shortage['ndc'],
                'declared_date': shortage['declared_date'],
                'expected_resolution': shortage['expected_resolution'],
                'reason': shortage['shortage_reason'],
                'current_inventory': current_qty,
                'days_supply': round(days_supply, 1),
                'alternatives': ', '.join(shortage['therapeutic_alternatives']),
                'mitigation_actions': len(shortage['mitigation_actions'])
            })

        return pd.DataFrame(report)

Example usage

Example usage

shortage_mgr = DrugShortageManager("Memorial Hospital Pharmacy")
shortage_mgr = DrugShortageManager("Memorial Hospital Pharmacy")

Add inventory

Add inventory

shortage_mgr.inventory['PROP-100MG'] = {'quantity': 50}
shortage_mgr.inventory['PROP-100MG'] = {'quantity': 50}

Declare shortage

Declare shortage

shortage = shortage_mgr.declare_shortage( drug_id='PROP-100MG', drug_name='Propofol 100mg/10mL', ndc='63323-0269-10', shortage_reason='Manufacturing delay at primary supplier', expected_duration_days=45, therapeutic_alternatives=['Etomidate', 'Ketamine'] )
print(f"Shortage declared: {shortage['shortage_id']}")
shortage = shortage_mgr.declare_shortage( drug_id='PROP-100MG', drug_name='Propofol 100mg/10mL', ndc='63323-0269-10', shortage_reason='Manufacturing delay at primary supplier', expected_duration_days=45, therapeutic_alternatives=['Etomidate', 'Ketamine'] )
print(f"Shortage declared: {shortage['shortage_id']}")

Develop mitigation strategy

Develop mitigation strategy

strategies = shortage_mgr.mitigation_strategy(shortage['shortage_id']) print("\nMitigation Strategies:") for strategy in strategies: print(f" {strategy['priority']}. {strategy['strategy']}: {strategy['description']}")
strategies = shortage_mgr.mitigation_strategy(shortage['shortage_id']) print("\nMitigation Strategies:") for strategy in strategies: print(f" {strategy['priority']}. {strategy['strategy']}: {strategy['description']}")

Prioritize patients

Prioritize patients

patients = [ {'patient_id': 'PT-001', 'indication': 'Septic shock - ICU', 'prescriber': 'Dr. Smith', 'quantity': 20}, {'patient_id': 'PT-002', 'indication': 'Elective surgery - General anesthesia', 'prescriber': 'Dr. Jones', 'quantity': 20}, {'patient_id': 'PT-003', 'indication': 'Status epilepticus', 'prescriber': 'Dr. Brown', 'quantity': 10} ]
prioritized = shortage_mgr.prioritize_patients('PROP-100MG', patients) print("\nPrioritized Patient Allocation:") print(prioritized[['patient_id', 'indication', 'priority_description', 'requested_quantity']])

---
patients = [ {'patient_id': 'PT-001', 'indication': 'Septic shock - ICU', 'prescriber': 'Dr. Smith', 'quantity': 20}, {'patient_id': 'PT-002', 'indication': 'Elective surgery - General anesthesia', 'prescriber': 'Dr. Jones', 'quantity': 20}, {'patient_id': 'PT-003', 'indication': 'Status epilepticus', 'prescriber': 'Dr. Brown', 'quantity': 10} ]
prioritized = shortage_mgr.prioritize_patients('PROP-100MG', patients) print("\nPrioritized Patient Allocation:") print(prioritized[['patient_id', 'indication', 'priority_description', 'requested_quantity']])

---

Specialty Pharmacy Operations

专科药房运营

High-Cost Medication Management

高成本药物管理

python
class SpecialtyPharmacyManager:
    """
    Manage specialty pharmacy operations for high-cost medications
    """

    def __init__(self, pharmacy_name):
        self.pharmacy_name = pharmacy_name
        self.specialty_drugs = {}
        self.prior_authorizations = {}

    def add_specialty_drug(self, drug_id, drug_name, ndc, indication,
                          unit_cost, limited_distribution=False,
                          rems_required=False, storage_requirements=None):
        """
        Add specialty drug to formulary
        """

        self.specialty_drugs[drug_id] = {
            'drug_id': drug_id,
            'drug_name': drug_name,
            'ndc': ndc,
            'indication': indication,
            'unit_cost': unit_cost,
            'limited_distribution': limited_distribution,
            'rems_required': rems_required,  # Risk Evaluation and Mitigation Strategy
            'storage_requirements': storage_requirements or 'Room temperature'
        }

    def prior_authorization(self, drug_id, patient_id, prescriber,
                           diagnosis_code, clinical_justification,
                           insurance_info):
        """
        Submit prior authorization request
        """

        pa_id = f"PA-{len(self.prior_authorizations)+1}"

        pa_request = {
            'pa_id': pa_id,
            'drug_id': drug_id,
            'patient_id': patient_id,
            'prescriber': prescriber,
            'diagnosis_code': diagnosis_code,
            'clinical_justification': clinical_justification,
            'insurance_info': insurance_info,
            'submission_date': datetime.now(),
            'status': 'pending',
            'determination': None,
            'determination_date': None
        }

        self.prior_authorizations[pa_id] = pa_request

        return pa_request

    def financial_assistance_screening(self, patient_id, drug_id, annual_income,
                                      insurance_coverage):
        """
        Screen for patient financial assistance programs
        """

        drug = self.specialty_drugs.get(drug_id)

        if not drug:
            raise ValueError(f"Drug {drug_id} not found")

        # Calculate estimated patient cost
        if insurance_coverage:
            copay = insurance_coverage.get('copay', drug['unit_cost'] * 0.30)
            coinsurance_pct = insurance_coverage.get('coinsurance', 0)
        else:
            copay = drug['unit_cost']
            coinsurance_pct = 100

        estimated_annual_cost = copay * 12  # Assuming monthly therapy

        # Assistance program eligibility (simplified)
        assistance_programs = []

        # Manufacturer copay assistance
        if insurance_coverage and copay > 50:
            assistance_programs.append({
                'program': 'Manufacturer Copay Card',
                'estimated_savings': min(copay * 0.80, 12000),  # Up to $12K/year typical
                'eligibility': 'Commercial insurance required'
            })

        # Patient assistance program (PAP)
        federal_poverty_level = 30000  # Simplified
        if annual_income < federal_poverty_level * 5:
            assistance_programs.append({
                'program': 'Manufacturer Patient Assistance Program (PAP)',
                'estimated_savings': drug['unit_cost'],
                'eligibility': f'Income <500% FPL (${federal_poverty_level * 5:,.0f})'
            })

        # Foundation assistance
        if estimated_annual_cost > annual_income * 0.10:  # >10% of income
            assistance_programs.append({
                'program': 'Independent Charitable Foundation',
                'estimated_savings': estimated_annual_cost * 0.50,
                'eligibility': 'Disease-specific, income-based'
            })

        return {
            'patient_id': patient_id,
            'drug_name': drug['drug_name'],
            'estimated_annual_cost': round(estimated_annual_cost, 2),
            'pct_of_income': round(estimated_annual_cost / annual_income * 100, 1) if annual_income > 0 else 0,
            'assistance_programs': assistance_programs
        }
python
class SpecialtyPharmacyManager:
    """
    Manage specialty pharmacy operations for high-cost medications
    """

    def __init__(self, pharmacy_name):
        self.pharmacy_name = pharmacy_name
        self.specialty_drugs = {}
        self.prior_authorizations = {}

    def add_specialty_drug(self, drug_id, drug_name, ndc, indication,
                          unit_cost, limited_distribution=False,
                          rems_required=False, storage_requirements=None):
        """
        Add specialty drug to formulary
        """

        self.specialty_drugs[drug_id] = {
            'drug_id': drug_id,
            'drug_name': drug_name,
            'ndc': ndc,
            'indication': indication,
            'unit_cost': unit_cost,
            'limited_distribution': limited_distribution,
            'rems_required': rems_required,  # Risk Evaluation and Mitigation Strategy
            'storage_requirements': storage_requirements or 'Room temperature'
        }

    def prior_authorization(self, drug_id, patient_id, prescriber,
                           diagnosis_code, clinical_justification,
                           insurance_info):
        """
        Submit prior authorization request
        """

        pa_id = f"PA-{len(self.prior_authorizations)+1}"

        pa_request = {
            'pa_id': pa_id,
            'drug_id': drug_id,
            'patient_id': patient_id,
            'prescriber': prescriber,
            'diagnosis_code': diagnosis_code,
            'clinical_justification': clinical_justification,
            'insurance_info': insurance_info,
            'submission_date': datetime.now(),
            'status': 'pending',
            'determination': None,
            'determination_date': None
        }

        self.prior_authorizations[pa_id] = pa_request

        return pa_request

    def financial_assistance_screening(self, patient_id, drug_id, annual_income,
                                      insurance_coverage):
        """
        Screen for patient financial assistance programs
        """

        drug = self.specialty_drugs.get(drug_id)

        if not drug:
            raise ValueError(f"Drug {drug_id} not found")

        # Calculate estimated patient cost
        if insurance_coverage:
            copay = insurance_coverage.get('copay', drug['unit_cost'] * 0.30)
            coinsurance_pct = insurance_coverage.get('coinsurance', 0)
        else:
            copay = drug['unit_cost']
            coinsurance_pct = 100

        estimated_annual_cost = copay * 12  # Assuming monthly therapy

        # Assistance program eligibility (simplified)
        assistance_programs = []

        # Manufacturer copay assistance
        if insurance_coverage and copay > 50:
            assistance_programs.append({
                'program': 'Manufacturer Copay Card',
                'estimated_savings': min(copay * 0.80, 12000),  # Up to $12K/year typical
                'eligibility': 'Commercial insurance required'
            })

        # Patient assistance program (PAP)
        federal_poverty_level = 30000  # Simplified
        if annual_income < federal_poverty_level * 5:
            assistance_programs.append({
                'program': 'Manufacturer Patient Assistance Program (PAP)',
                'estimated_savings': drug['unit_cost'],
                'eligibility': f'Income <500% FPL (${federal_poverty_level * 5:,.0f})'
            })

        # Foundation assistance
        if estimated_annual_cost > annual_income * 0.10:  # >10% of income
            assistance_programs.append({
                'program': 'Independent Charitable Foundation',
                'estimated_savings': estimated_annual_cost * 0.50,
                'eligibility': 'Disease-specific, income-based'
            })

        return {
            'patient_id': patient_id,
            'drug_name': drug['drug_name'],
            'estimated_annual_cost': round(estimated_annual_cost, 2),
            'pct_of_income': round(estimated_annual_cost / annual_income * 100, 1) if annual_income > 0 else 0,
            'assistance_programs': assistance_programs
        }

Example usage

Example usage

specialty_pharm = SpecialtyPharmacyManager("Memorial Specialty Pharmacy")
specialty_pharm = SpecialtyPharmacyManager("Memorial Specialty Pharmacy")

Add specialty drug

Add specialty drug

specialty_pharm.add_specialty_drug( drug_id='HUMIRA-40MG', drug_name='Adalimumab (Humira)', ndc='00074-4339-02', indication='Rheumatoid Arthritis, Crohn's Disease', unit_cost=6000, limited_distribution=False, rems_required=False, storage_requirements='Refrigerated 2-8°C' )
specialty_pharm.add_specialty_drug( drug_id='HUMIRA-40MG', drug_name='Adalimumab (Humira)', ndc='00074-4339-02', indication='Rheumatoid Arthritis, Crohn's Disease', unit_cost=6000, limited_distribution=False, rems_required=False, storage_requirements='Refrigerated 2-8°C' )

Prior authorization

Prior authorization

pa = specialty_pharm.prior_authorization( drug_id='HUMIRA-40MG', patient_id='PT-123456', prescriber='Dr. Williams', diagnosis_code='M05.79', # Rheumatoid arthritis clinical_justification='Failed methotrexate and sulfasalazine. Significant disease activity.', insurance_info={'payer': 'Blue Cross', 'plan': 'PPO', 'member_id': 'BC123456'} )
print(f"PA submitted: {pa['pa_id']}, Status: {pa['status']}")
pa = specialty_pharm.prior_authorization( drug_id='HUMIRA-40MG', patient_id='PT-123456', prescriber='Dr. Williams', diagnosis_code='M05.79', # Rheumatoid arthritis clinical_justification='Failed methotrexate and sulfasalazine. Significant disease activity.', insurance_info={'payer': 'Blue Cross', 'plan': 'PPO', 'member_id': 'BC123456'} )
print(f"PA submitted: {pa['pa_id']}, Status: {pa['status']}")

Financial assistance screening

Financial assistance screening

insurance = {'copay': 500, 'coinsurance': 20} assistance = specialty_pharm.financial_assistance_screening( patient_id='PT-123456', drug_id='HUMIRA-40MG', annual_income=45000, insurance_coverage=insurance )
print(f"\nEstimated annual cost: ${assistance['estimated_annual_cost']:,.2f}") print(f"Percent of income: {assistance['pct_of_income']}%") print(f"\nAssistance programs available: {len(assistance['assistance_programs'])}") for program in assistance['assistance_programs']: print(f" - {program['program']}: Up to ${program['estimated_savings']:,.0f}")

---
insurance = {'copay': 500, 'coinsurance': 20} assistance = specialty_pharm.financial_assistance_screening( patient_id='PT-123456', drug_id='HUMIRA-40MG', annual_income=45000, insurance_coverage=insurance )
print(f"\nEstimated annual cost: ${assistance['estimated_annual_cost']:,.2f}") print(f"Percent of income: {assistance['pct_of_income']}%") print(f"\nAssistance programs available: {len(assistance['assistance_programs'])}") for program in assistance['assistance_programs']: print(f" - {program['program']}: Up to ${program['estimated_savings']:,.0f}")

---

Pharmacy Performance Metrics

药房绩效指标

Key Performance Indicators

关键绩效指标

python
def calculate_pharmacy_kpis(rx_data_df, inventory_data_df, cs_data_df=None):
    """
    Calculate pharmacy supply chain KPIs

    Parameters:
    - rx_data_df: Prescription dispensing data
    - inventory_data_df: Inventory positions
    - cs_data_df: Controlled substance data (optional)
    """

    kpis = {}

    # Fill rate / Service level
    if 'filled' in rx_data_df.columns:
        kpis['fill_rate'] = (rx_data_df['filled'].sum() / len(rx_data_df) * 100)

    # Inventory turns
    if all(col in inventory_data_df.columns for col in ['annual_usage', 'avg_inventory_value']):
        total_usage_value = inventory_data_df['annual_usage'].sum()
        total_avg_inventory = inventory_data_df['avg_inventory_value'].sum()
        kpis['inventory_turns'] = total_usage_value / total_avg_inventory if total_avg_inventory > 0 else 0

    # Expiry waste rate
    if 'expired' in inventory_data_df.columns:
        expired_value = inventory_data_df[inventory_data_df['expired'] == True]['inventory_value'].sum()
        total_value = inventory_data_df['inventory_value'].sum()
        kpis['expiry_waste_pct'] = (expired_value / total_value * 100) if total_value > 0 else 0

    # Generic dispensing rate (cost savings)
    if 'generic' in rx_data_df.columns:
        kpis['generic_dispensing_rate'] = (rx_data_df['generic'].sum() / len(rx_data_df) * 100)

    # Prescription turnaround time
    if 'turnaround_minutes' in rx_data_df.columns:
        kpis['avg_turnaround_minutes'] = rx_data_df['turnaround_minutes'].mean()

    # 340B capture rate (if applicable)
    if '340b_eligible' in rx_data_df.columns and '340b_used' in rx_data_df.columns:
        eligible = rx_data_df['340b_eligible'].sum()
        used = rx_data_df['340b_used'].sum()
        kpis['340b_capture_rate'] = (used / eligible * 100) if eligible > 0 else 0

    # Controlled substance accuracy (if applicable)
    if cs_data_df is not None and not cs_data_df.empty:
        if 'discrepancy' in cs_data_df.columns:
            kpis['cs_inventory_accuracy'] = (
                (len(cs_data_df[cs_data_df['discrepancy'] == 0]) / len(cs_data_df) * 100)
            )

    # DSCSA compliance rate
    if 'dscsa_compliant' in rx_data_df.columns:
        kpis['dscsa_compliance_rate'] = (rx_data_df['dscsa_compliant'].sum() / len(rx_data_df) * 100)

    # Format KPIs
    for key in kpis:
        if 'rate' in key or 'pct' in key or 'accuracy' in key:
            kpis[key] = round(kpis[key], 2)
        elif 'turns' in key:
            kpis[key] = round(kpis[key], 2)
        else:
            kpis[key] = round(kpis[key], 1)

    return kpis
python
def calculate_pharmacy_kpis(rx_data_df, inventory_data_df, cs_data_df=None):
    """
    Calculate pharmacy supply chain KPIs

    Parameters:
    - rx_data_df: Prescription dispensing data
    - inventory_data_df: Inventory positions
    - cs_data_df: Controlled substance data (optional)
    """

    kpis = {}

    # Fill rate / Service level
    if 'filled' in rx_data_df.columns:
        kpis['fill_rate'] = (rx_data_df['filled'].sum() / len(rx_data_df) * 100)

    # Inventory turns
    if all(col in inventory_data_df.columns for col in ['annual_usage', 'avg_inventory_value']):
        total_usage_value = inventory_data_df['annual_usage'].sum()
        total_avg_inventory = inventory_data_df['avg_inventory_value'].sum()
        kpis['inventory_turns'] = total_usage_value / total_avg_inventory if total_avg_inventory > 0 else 0

    # Expiry waste rate
    if 'expired' in inventory_data_df.columns:
        expired_value = inventory_data_df[inventory_data_df['expired'] == True]['inventory_value'].sum()
        total_value = inventory_data_df['inventory_value'].sum()
        kpis['expiry_waste_pct'] = (expired_value / total_value * 100) if total_value > 0 else 0

    # Generic dispensing rate (cost savings)
    if 'generic' in rx_data_df.columns:
        kpis['generic_dispensing_rate'] = (rx_data_df['generic'].sum() / len(rx_data_df) * 100)

    # Prescription turnaround time
    if 'turnaround_minutes' in rx_data_df.columns:
        kpis['avg_turnaround_minutes'] = rx_data_df['turnaround_minutes'].mean()

    # 340B capture rate (if applicable)
    if '340b_eligible' in rx_data_df.columns and '340b_used' in rx_data_df.columns:
        eligible = rx_data_df['340b_eligible'].sum()
        used = rx_data_df['340b_used'].sum()
        kpis['340b_capture_rate'] = (used / eligible * 100) if eligible > 0 else 0

    # Controlled substance accuracy (if applicable)
    if cs_data_df is not None and not cs_data_df.empty:
        if 'discrepancy' in cs_data_df.columns:
            kpis['cs_inventory_accuracy'] = (
                (len(cs_data_df[cs_data_df['discrepancy'] == 0]) / len(cs_data_df) * 100)
            )

    # DSCSA compliance rate
    if 'dscsa_compliant' in rx_data_df.columns:
        kpis['dscsa_compliance_rate'] = (rx_data_df['dscsa_compliant'].sum() / len(rx_data_df) * 100)

    # Format KPIs
    for key in kpis:
        if 'rate' in key or 'pct' in key or 'accuracy' in key:
            kpis[key] = round(kpis[key], 2)
        elif 'turns' in key:
            kpis[key] = round(kpis[key], 2)
        else:
            kpis[key] = round(kpis[key], 1)

    return kpis

Example data

Example data

rx_data = pd.DataFrame({ 'rx_number': range(1, 1001), 'filled': [True] * 980 + [False] * 20, 'generic': np.random.choice([True, False], 1000, p=[0.85, 0.15]), 'turnaround_minutes': np.random.normal(20, 5, 1000), '340b_eligible': np.random.choice([True, False], 1000, p=[0.40, 0.60]), '340b_used': np.random.choice([True, False], 1000, p=[0.35, 0.65]), 'dscsa_compliant': np.random.choice([True, False], 1000, p=[0.98, 0.02]) })
rx_data = pd.DataFrame({ 'rx_number': range(1, 1001), 'filled': [True] * 980 + [False] * 20, 'generic': np.random.choice([True, False], 1000, p=[0.85, 0.15]), 'turnaround_minutes': np.random.normal(20, 5, 1000), '340b_eligible': np.random.choice([True, False], 1000, p=[0.40, 0.60]), '340b_used': np.random.choice([True, False], 1000, p=[0.35, 0.65]), 'dscsa_compliant': np.random.choice([True, False], 1000, p=[0.98, 0.02]) })

Fix 340B logic (can only use if eligible)

Fix 340B logic (can only use if eligible)

rx_data.loc[~rx_data['340b_eligible'], '340b_used'] = False
inventory_data = pd.DataFrame({ 'drug_id': range(1, 501), 'annual_usage': np.random.randint(1000, 50000, 500), 'avg_inventory_value': np.random.randint(500, 10000, 500), 'inventory_value': np.random.randint(500, 10000, 500), 'expired': np.random.choice([True, False], 500, p=[0.02, 0.98]) })
kpis = calculate_pharmacy_kpis(rx_data, inventory_data)
print("Pharmacy Supply Chain KPIs:") for metric, value in kpis.items(): suffix = '%' if any(x in metric for x in ['rate', 'pct', 'accuracy']) else '' print(f" {metric}: {value}{suffix}")

---
rx_data.loc[~rx_data['340b_eligible'], '340b_used'] = False
inventory_data = pd.DataFrame({ 'drug_id': range(1, 501), 'annual_usage': np.random.randint(1000, 50000, 500), 'avg_inventory_value': np.random.randint(500, 10000, 500), 'inventory_value': np.random.randint(500, 10000, 500), 'expired': np.random.choice([True, False], 500, p=[0.02, 0.98]) })
kpis = calculate_pharmacy_kpis(rx_data, inventory_data)
print("Pharmacy Supply Chain KPIs:") for metric, value in kpis.items(): suffix = '%' if any(x in metric for x in ['rate', 'pct', 'accuracy']) else '' print(f" {metric}: {value}{suffix}")

---

Tools & Libraries

工具与库

Pharmacy Management Systems

药房管理系统

ERP/Pharmacy Systems:
  • EPIC Willow Pharmacy: Integrated with Epic EHR
  • Cerner PharmNet: Pharmacy management module
  • Omnicell: Automated dispensing cabinets
  • BD Pyxis: Medication management system
  • McKesson Pharmacy Systems: STAR, EnterpriseRx
  • QS/1: Independent pharmacy management
Controlled Substance Tracking:
  • Omnicell ControlledRx: CS management
  • BD Pyxis CII Safe: Controlled substance vault
  • Kit Check: Medication tracking and diversion monitoring
  • Protenus: AI-powered drug diversion detection
340B Management:
  • Kalderos: 340B claim identification
  • Macro Helix: 340B program management
  • Verity Solutions: 340B split-billing
  • RxStrategies: 340B optimization
DSCSA Compliance:
  • TraceLink: DSCSA compliance platform
  • SAP Information Collaboration Hub for Life Sciences
  • rfxcel: Serialization and traceability
  • Systech UniSecure: Product authentication
ERP/药房系统:
  • EPIC Willow Pharmacy:与Epic EHR集成
  • Cerner PharmNet:药房管理模块
  • Omnicell:自动发药柜
  • BD Pyxis:药品管理系统
  • McKesson Pharmacy Systems:STAR、EnterpriseRx
  • QS/1:独立药房管理系统
受控物质追踪:
  • Omnicell ControlledRx:受控物质管理
  • BD Pyxis CII Safe:受控物质保险柜
  • Kit Check:药品追踪与 diversion 监控
  • Protenus:AI驱动的药品 diversion 检测
340B管理:
  • Kalderos:340B索赔识别
  • Macro Helix:340B项目管理
  • Verity Solutions:340B拆分计费
  • RxStrategies:340B优化
DSCSA合规:
  • TraceLink:DSCSA合规平台
  • SAP Information Collaboration Hub for Life Sciences
  • rfxcel:序列化与可追溯性
  • Systech UniSecure:产品认证

Python Libraries

Python库

Data Analysis:
  • pandas
    : Data manipulation
  • numpy
    : Numerical analysis
  • scipy
    : Statistical functions
Regulatory Compliance:
  • python-barcode
    : Barcode generation (NDC)
  • qrcode
    : 2D barcode generation
  • hashlib
    : Data integrity verification
Optimization:
  • pulp
    : Linear programming (inventory optimization)
  • scipy.optimize
    : Optimization algorithms
Visualization:
  • matplotlib
    ,
    seaborn
    : Charts and graphs
  • plotly
    : Interactive dashboards

数据分析:
  • pandas
    :数据处理
  • numpy
    :数值分析
  • scipy
    :统计函数
监管合规:
  • python-barcode
    :条码生成(NDC)
  • qrcode
    :二维条码生成
  • hashlib
    :数据完整性验证
优化:
  • pulp
    :线性规划(库存优化)
  • scipy.optimize
    :优化算法
可视化:
  • matplotlib
    seaborn
    :图表与图形
  • plotly
    :交互式仪表盘

Common Challenges & Solutions

常见挑战与解决方案

Challenge: DSCSA Compliance by November 2024

挑战:2024年11月前实现DSCSA合规

Problem:
  • Electronic, interoperable tracing required
  • Legacy systems not compliant
  • Trading partner integration
  • Serialization at package level
Solutions:
  • Implement DSCSA-compliant software platform
  • Test trading partner connections early
  • Staff training on scanning requirements
  • Develop suspect product investigation protocols
  • Regular compliance audits
  • Join industry pilot programs
问题:
  • 要求电子、可互操作的追踪
  • legacy系统不符合要求
  • 贸易伙伴集成
  • 包装级序列化
解决方案:
  • 实施符合DSCSA要求的软件平台
  • 尽早测试贸易伙伴连接
  • 员工扫描要求培训
  • 制定可疑产品调查协议
  • 定期合规审计
  • 加入行业试点项目

Challenge: Controlled Substance Diversion

挑战:受控物质Diversion

Problem:
  • Employee diversion risk
  • Documentation gaps
  • Inventory discrepancies
  • Regulatory penalties
Solutions:
  • Automated perpetual inventory system
  • Two-person verification for Schedule II
  • Regular random audits and cycle counts
  • Analytics to detect unusual patterns
  • Background checks and monitoring
  • Clear policies and disciplinary actions
  • Confidential reporting mechanisms
问题:
  • 员工 diversion 风险
  • 文档缺口
  • 库存差异
  • 监管处罚
解决方案:
  • 自动化永续库存系统
  • Schedule II药品需双人验证
  • 定期随机审计和循环盘点
  • 分析异常模式
  • 背景调查与监控
  • 明确政策和纪律处分
  • 保密报告机制

Challenge: 340B Compliance and Audits

挑战:340B合规与审计

Problem:
  • Complex patient eligibility rules
  • Contract pharmacy compliance
  • Duplicate discount prevention
  • HRSA audits
Solutions:
  • Automated patient eligibility system
  • Electronic health record integration
  • Split-billing for Medicaid
  • Regular internal compliance audits
  • Staff training on eligibility criteria
  • Detailed documentation and audit trails
  • Work with 340B consultant/expert
问题:
  • 复杂的患者资格规则
  • 合同药房合规
  • 重复折扣预防
  • HRSA审计
解决方案:
  • 自动化患者资格系统
  • 电子健康记录集成
  • Medicaid拆分计费
  • 定期内部合规审计
  • 员工资格标准培训
  • 详细文档和审计追踪
  • 与340B顾问/专家合作

Challenge: Drug Shortages

挑战:药品短缺

Problem:
  • Critical medications unavailable
  • Patient care impact
  • Therapeutic substitution complexity
  • Cost increases from alternatives
Solutions:
  • Multi-source purchasing strategy
  • Early warning monitoring (FDA shortage list)
  • Therapeutic substitution protocols
  • Conservation strategies for critical patients
  • Compounding alternatives (where appropriate)
  • Communication with prescribers
  • Group purchasing organization leverage
问题:
  • 关键药品缺货
  • 影响患者护理
  • 治疗替代复杂性
  • 替代药品成本上升
解决方案:
  • 多来源采购策略
  • 早期预警监控(FDA短缺列表)
  • 治疗替代方案
  • 关键患者节约策略
  • 复合替代方案(如适用)
  • 与处方医生沟通
  • 利用集团采购组织

Challenge: Specialty Medication Costs

挑战:专科药品成本

Problem:
  • Extremely high acquisition costs
  • Prior authorization delays
  • Patient affordability
  • Waste from failed PA or non-compliance
Solutions:
  • Proactive prior authorization
  • Financial assistance program navigation
  • Buy-and-bill vs. white bagging analysis
  • Limited dispensing quantities initially
  • Patient adherence support services
  • Manufacturer assistance program enrollment
  • Specialty pharmacy accreditation
问题:
  • 极高的采购成本
  • 事前授权延迟
  • 患者负担能力
  • 事前授权失败或不依从导致的浪费
解决方案:
  • 主动事前授权
  • 财务援助项目导航
  • 购买计费 vs 白袋分析
  • 初始限量发药
  • 患者依从性支持服务
  • 制造商援助项目注册
  • 专科药房认证

Challenge: Expiry and Waste

挑战:过期与浪费

Problem:
  • Short-dated products
  • Slow-moving items
  • Storage errors
  • Compounded medications
Solutions:
  • FEFO (first-expired, first-out) enforcement
  • Automated expiry alerts
  • Right-sizing inventory (data-driven PAR levels)
  • Vendor return programs
  • Transfer slow-movers between locations
  • Just-in-time ordering for slow items
  • Beyond-use date (BUD) optimization for compounding

问题:
  • 近效期产品
  • 滞销品
  • 存储错误
  • 复合药品
解决方案:
  • 执行FEFO(先到期先出)
  • 自动化过期提醒
  • 合理调整库存(数据驱动的PAR水平)
  • 供应商退货计划
  • 滞销品在门店间转移
  • 滞销品准时制订购
  • 复合药品使用期限(BUD)优化

Output Format

输出格式

Pharmacy Supply Chain Report

药房供应链报告

Executive Summary:
  • Pharmacy overview and scope
  • Key performance metrics vs. benchmarks
  • Major compliance initiatives
  • Financial impact and opportunities
Inventory Optimization:
Drug CategoryItemsInventory ValueAnnual TurnsDays on HandExpiry RateOptimization Opportunity
Antibiotics145$125,00015.2240.5%Reduce safety stock
Specialty42$850,0008.1451.2%Buy-and-bill vs. white bag
Controlled Substances38$45,00024.3150.1%Appropriate
Generic Oral1,250$180,00018.5201.8%Standardization
340B Program Performance:
MetricResultTargetStatus
Eligible Prescriptions2,450/month--
340B Capture Rate92.3%95%
Annual 340B Savings$1,850,000$2,000,000
Contract Pharmacy Compliance98.5%100%
Duplicate Discount Events00
Controlled Substance Compliance:
ScheduleItemsPerpetual Inv AccuracyPhysical Count FrequencyDiscrepancies YTDStatus
Schedule II1599.8%Daily2
Schedule III1299.5%Weekly3
Schedule IV2399.2%Weekly5
Active Drug Shortages:
Drug NameNDCDeclared DateCurrent StockDays SupplyMitigation StrategyStatus
Propofol 100mg63323-0269-102024-01-1550 vials5 daysAlternative sourcing, therapeutic subCritical
Cefazolin 1g00409-1964-502024-02-01200 vials20 daysConservation protocolMonitoring
Key Performance Indicators:
MetricCurrentTargetTrend
Fill Rate98.2%98%
Inventory Turns12.512.0
Generic Dispensing Rate89.3%85%
Expiry Waste %1.2%<1.5%
340B Capture Rate92.3%95%
DSCSA Compliance98.1%100%
Controlled Substance Accuracy99.5%99%
Action Items:
  1. Improve 340B capture rate through enhanced eligibility screening
  2. Complete DSCSA compliance for remaining 1.9% of transactions
  3. Implement automated shortage monitoring system
  4. Reduce specialty medication waste through limited initial fills
  5. Optimize inventory for slow-moving antibiotics

执行摘要:
  • 药房概述与范围
  • 关键绩效指标 vs 基准
  • 主要合规举措
  • 财务影响与机遇
库存优化:
药品类别品种数库存价值年周转次数库存天数过期率优化机会
抗生素145$125,00015.2240.5%降低安全库存
专科药品42$850,0008.1451.2%购买计费 vs 白袋
受控物质38$45,00024.3150.1%保持当前水平
口服仿制药1,250$180,00018.5201.8%标准化
340B项目绩效:
指标结果目标状态
合格处方量2,450张/月--
340B捕获率92.3%95%
年度340B节约额$1,850,000$2,000,000
合同药房合规率98.5%100%
重复折扣事件00
受控物质合规:
管控级别品种数永续库存准确率实物盘点频率年度差异数状态
Schedule II1599.8%每日2
Schedule III1299.5%每周3
Schedule IV2399.2%每周5
活跃药品短缺:
药品名称NDC宣布日期当前库存供应天数缓解策略状态
Propofol 100mg63323-0269-102024-01-1550瓶5天替代采购、治疗替代危急
Cefazolin 1g00409-1964-502024-02-01200瓶20天节约方案监控中
关键绩效指标:
指标当前值目标值趋势
处方填充率98.2%98%
库存周转次数12.512.0
仿制药处方率89.3%85%
过期浪费率1.2%<1.5%
340B捕获率92.3%95%
DSCSA合规率98.1%100%
受控物质库存准确率99.5%99%
行动项:
  1. 通过增强资格筛查提高340B捕获率
  2. 完成剩余1.9%交易的DSCSA合规
  3. 实施自动化短缺监控系统
  4. 通过初始限量发药减少专科药品浪费
  5. 优化滞销抗生素的库存

Questions to Ask

需询问的问题

If you need more context:
  1. What type of pharmacy? (hospital, retail, specialty, mail-order)
  2. Are you a 340B covered entity?
  3. What's your DSCSA compliance status?
  4. What controlled substance schedules do you handle?
  5. What's the current inventory investment and turnover?
  6. Are you experiencing specific drug shortages?
  7. What pharmacy management system is in use?
  8. What are the biggest compliance concerns?
  9. Do you dispense specialty medications?
  10. What wholesaler/distributor relationships do you have?

如需更多背景信息:
  1. 药房类型?(医院、零售、专科、邮购)
  2. 是否为340B合格实体?
  3. DSCSA合规状态如何?
  4. 处理哪些级别的受控物质?
  5. 当前库存投入和周转情况?
  6. 是否面临特定药品短缺?
  7. 使用何种药房管理系统?
  8. 最大的合规顾虑是什么?
  9. 是否配送专科药品?
  10. 与哪些批发商/分销商有合作关系?

Related Skills

相关技能

  • hospital-logistics: Hospital materials management
  • medical-device-distribution: Medical device logistics
  • clinical-trial-logistics: Clinical trial supply chain
  • inventory-optimization: Inventory optimization techniques
  • demand-forecasting: Forecasting for inventory planning
  • compliance-management: Regulatory compliance systems
  • track-and-trace: Product traceability and serialization
  • value-analysis: Value analysis and cost reduction
  • quality-management: Quality management systems
  • hospital-logistics:医院物资管理
  • medical-device-distribution:医疗设备物流
  • clinical-trial-logistics:临床试验供应链
  • inventory-optimization:库存优化技术
  • demand-forecasting:库存规划预测
  • compliance-management:监管合规系统
  • track-and-trace:产品可追溯性与序列化
  • value-analysis:价值分析与成本降低
  • quality-management:质量管理系统