Skip to content

Instantly share code, notes, and snippets.

@klippx
Created July 2, 2015 06:49
Show Gist options
  • Save klippx/70aa60403bf6ab5ef7bc to your computer and use it in GitHub Desktop.
Save klippx/70aa60403bf6ab5ef7bc to your computer and use it in GitHub Desktop.
1. Original version
# A pouch order is ordered to a ward for a patient from a prescriber. These
# will be produces as pouches through the HD-Medi system.
class PouchOrder < ActiveRecord::Base
include Workflow
belongs_to :ward
belongs_to :patient
belongs_to :file, class_name: 'MachineFile', foreign_key: 'machine_file_id'
belongs_to :transport_label
has_one :replaced, class_name: 'PouchOrder', foreign_key: 'replacement_id'
belongs_to :replacement, class_name: 'PouchOrder', foreign_key: 'replacement_id'
has_many :lines, class_name: 'PouchOrderLine', foreign_key: 'pouch_order_id', inverse_of: :order, dependent: :destroy
has_many :interactions, dependent: :destroy
has_many :overdoses, dependent: :destroy
validates :ward, :patient, presence: true
validates :number, uniqueness: true
before_save :set_default_delivery_at, on: :create
before_save :calculate_and_set_lock_at, on: :create
scope :sent_to_machine, -> { where(status: 'sent_to_machine') }
delegate :ordering_deadlines, to: :ward
workflow_column :status
audited only: [:status], on: [:update], allow_mass_assignment: true
workflow do
state :new do
event :confirm_receiving, transitions_to: :received
end
state :received do
event :make_interaction, transitions_to: :interaction
event :make_dosage_control, transitions_to: :dosage_control
event :replace, transitions_to: :replaced
end
state :interaction do
event :make_dosage_control, transitions_to: :dosage_control
end
state :dosage_control do
event :confirm_dosage, transitions_to: :awaiting_approval
end
state :awaiting_approval do
event :approve, transitions_to: :approved
event :reject, transitions_to: :rejected
event :replace, transitions_to: :replaced
end
state :approved do
event :upload, transitions_to: :uploading
event :replace, transitions_to: :replaced
end
state :uploading do
event :uploaded, transitions_to: :sent_to_machine
end
state :sent_to_machine do
event :sort, transitions_to: :sorted
end
state :sorted do
event :ship, transitions_to: :shipped
end
state :shipped do
event :unship, transitions_to: :unshipped
end
state :unshipped do
event :ship, transitions_to: :shipped
end
state :rejected
state :replaced
on_transition do |from, to, triggering_event, *event_args|
write_audit(
action: 'update',
audited_changes: {
status: [from, to]
}
)
end
end
def self.from_attachment(attachment)
PouchOrder.new do |order|
order.number = attachment.header.order_number
order.phone_number = attachment.contact_telephone
order.issued_at = attachment.issued_at
order.delivery_at = attachment.delivery_at
parse_patient_for(order, attachment)
parse_ward_for(order, attachment)
parse_items_for(order, attachment)
end
end
def self.auto_approval_enabled?
Settings.pouch_order_auto_approval == "true"
end
def number
super || "apoex_#{self.id}".upcase
end
def loading_dock
ward.loading_dock
end
def contains_licensed_item?
lines.any? { |line| line.item.license_required? }
end
def suitable_transport_label
TransportLabel.with_open_state.where(ward: ward).order(:created_at).last
end
def dangerous_interactions?
interactions.any? { |i| i.dangerous? }
end
def unknown_interactions?
interactions.any? { |i| i.unknown? }
end
def make_interaction
Resque.enqueue(InteractionJob, self.id)
end
def make_dosage_control
Resque.enqueue(DosageControlJob, self.id)
end
def can_be_auto_approved?
return false unless PouchOrder.auto_approval_enabled?
!(self.contains_licensed_item? || self.interactions.any? || self.overdoses.any?)
end
def on_received_entry(new_state, event, *args)
if InteractionService.enabled?
self.make_interaction!
else
self.make_dosage_control!
end
end
def on_awaiting_approval_entry(new_state, event, *args)
self.approve! if can_be_auto_approved?
end
def sort(label)
label.orders << self
end
### Order lock time and replacement
def set_default_delivery_at
self.delivery_at ||= loading_dock.latest_delivery_time
end
def calculate_and_set_lock_at
delivery_time = self.delivery_at.dup
lock_time = ward.loading_dock.ordering_deadlines.for_delivery_time(delivery_time)
self.lock_at = delivery_time.change({ hour: lock_time.hour, min: lock_time.min, sec: lock_time.sec })
end
def self.to_replace(order)
replaceable_at(order.issued_at)
.where.not(id: order.id)
.where.not(status: :replaced)
.find_by(patient: order.patient)
end
def self.replaceable_at(time = Time.now)
where("lock_at > ?", time)
end
def issued_in_time?
!self.locked_at?(self.issued_at)
end
def locked_at?(time = Time.now)
self.lock_at < time
end
def replace(order)
self.replacement = order
self.save!
end
private
def self.parse_patient_for(order, attachment)
patient = Patient.where(ssn: attachment.patient_ssn).first_or_initialize
patient.first_name = attachment.patient_first_name
patient.last_name = attachment.patient_last_name
order.patient = patient
end
def self.parse_ward_for(order, attachment)
ward = Ward.find_by_consignee_gln(attachment.delivery_customer_gln)
order.ward = ward
end
def self.parse_items_for(order, attachment)
attachment.items.group_by(&:periodic_start).each do |date, order_items_on_date|
intakes_on_date = order_items_on_date.flat_map(&:intakes)
intakes_on_date.group_by(&:time).each do |time_string, intake_on_time|
time = Time.parse(time_string)
admin_time = date.change({ hour: time.hour, min: time.min, sec: time.sec })
intake_on_time.each do |intake|
order.lines.new do |line|
line.item = Item.find_by(npl_id: intake.item.npl_id)
line.prescriber_name = intake.item.prescriber_name
line.admin_time = admin_time
line.quantity = intake.quantity
end
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment