#! /usr/bin/perl use strict; no strict 'refs'; use warnings; use DBI; use Date::Calc qw(:all); use File::Temp qw/ tempfile tempdir /; my $version = '1.0'; ############################################################################# # CONTENTS ############################################################################# #Section 1. Description and copyright statement #Section 2. Setup and instructions #Section 3. User definable variables #Section 4. Code ############################################################################# # Section 1. DESCRIPTION AND COPYRIGHT STATEMENT ############################################################################# #this script is used to enter walk in patients into OSCAR EMR # (c) Robbie Coull, 2009 # robbie@coull.net # # This code is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This code is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # see . ############################################################################# # Section 2. SETUP AND INSTRUCTIONS ############################################################################# # Copy this script to a suitable location (eg: /usr/local/scripts) # Make sure that it can be used by any user # sudo chmod 777 /usr/local/scripts/wic.pl #note: must have mysql root password set to '' and the test database created #for this to work and make sure MySQL is running! # sudo apt-get install mysql-server # sudo /etc/init.d/mysql start #For this script to work you need to install perl modules # sudo perl -MCPAN -e shell # cpan> install Bundle::CPAN # cpan> install Bundle::DBI # cpan> install Date::Calc # cpan> install File::Temp # cpan> exit #once the modules are installed, make sure MySQL on the local server is NOT running # sudo /etc/init.d/mysql stop #turn MySQL off in the services section of admin to prevent it starting at boot #if OSCAR is installed on a remote server #then you will need to set up a keychain access to that server #to allow this script to access the upload folders # #eg: ssh -D 8080 -fN $USER@$remoteserver # ssh -nNL 3306:127.0.0.1:3306 $USER@$remoteserver &> /dev/null & # #which provides SSH tunnel access to the server and to the MySQL server #I recommend using three user logins for MySQL (read only, read write, admin) #This helps prevent disasters when the wrong command is issued by accident. #If you do most of your database work from a read only user, then you can't #accidentally delete anything. # #Set up a read-only user and a read-write user as follows: #log in to mysql #mysql -uroot -p # #GRANT all ON oscar_mcmaster.* TO readonly@localhost IDENTIFIED BY '[password]'; #GRANT select ON oscar_mcmaster.* TO readwrite@localhost IDENTIFIED BY '[password]'; # #exit # #You will need to enter the user names and passwords of these two users #in the section below - make sure this script can only be accessed by trusted users! #note on providers #For Walk In Clinics the family physicans should all have the same first #two digits for their provider numbers. This makes selecting a physician from #the list much easier. (eg: 7001, 7002, etc..) #The exception is the 'current provider' (ie: the physician this script is #tied to using the 'current provider' variable below). #If the physicians have mixed provider numbers, then set $use_full_provider_no to 1. ############################################################################# # Section 3. USER VARIABLES ############################################################################# my $province_code = 'PE'; my $province_name = 'PEI'; my $province_phone_code = '902'; my $phn_length = '8'; my $current_provider = '1000'; my $orphan_provider = '8999'; my $program_id = '10015'; my $canada_fee = '30.00'; my $other_fee = '60.00'; my $print_two_invoices = 1; my $use_full_provider_no = qw{}; my $provider_no_prefix = '70'; #this is the provider number for patients of a doctor not currently in the database my $other_doctor = '1000'; my $truncated_other_doctor = '00'; #server details my $serveraddress = 'yourserver.net'; my $serverlogin = getlogin(); my $data_folder = "/home/share/scripts/data"; #set diagnostics on or off my $diagnostic; #$diagnostic = 'on'; my %pref; $pref{mysql_database} = 'oscar_mcmaster'; $pref{mysql_read} = 'read user'; $pref{mysql_read_pass} = 'read password'; $pref{mysql_write} = 'write user'; $pref{mysql_write_pass} = 'write password'; $pref{mysql_host} = '127.0.0.1'; $pref{mysql_port} = '3306'; $pref{mysql_log} = "/home/$serverlogin/oscar_scan_sql.log"; #month variables my %month_names = ( 'JAN' => '1', 'FEB' => '2', 'MAR' => '3', 'APR' => '4', 'MAY' => '5', 'JUN' => '6', 'JUL' => '7', 'AUG' => '8', 'SEP' => '9', 'SEPT' => '9', 'OCT' => '10', 'NOV' => '11', 'DEC' => '12', 'JANUARY' => '1', 'FEBUARY' => '2', 'MARCH' => '3', 'APRIL' => '4', 'MAY' => '5', 'JUNE' => '6', 'JULY' => '7', 'AUGUST' => '8', 'SEPTEMBER' => '9', 'OCTOBER' => '10', 'NOVEMBER' => '11', 'DECEMBER' => '12', ); my $this_month_name; my @month_names = qw( blank Jan Feb Mar Apr May Jun July Aug Sept Oct Nov Dec ); my @day_names = qw( Sunday Monday Tuesday Wednesday Thursday Friday Saturday ); #declare variables my $provider_data; my $family_doctor; my $clinic_start_time = '1'; my $appt_length = '1'; my $this_patient; my $print_line; my $report_number=0; my $tempdir = tempdir(); #declare subroutine variables my $sec; my $min; my $hr; my $mday; my $mon; my $year; my $wday; my $yday; my $isdst; my $longyr; my $fixmo; my $sql_date; my $sql_time; my $sql_datetime; my $string_to_be_padded; my $desired_string_length; my $padding_character; my $right_or_left_justify; my $decimal_places; my $decimals; my $decimal_places_digit; my $missing_digits; my $mysql_user; my $mysql_login; my $mysql_pass; my $dbh_name; my $mysql_preferred_user; my $mysql_original_user; my $dbh_inuse; my $sql; my @mysql_row; my $mysql_query; my $mysql_record; my @mysql_result; my @mysql_insert; my $mysql_update_table; my $mysql_update_table_array; my $mysql_disconnect; my $error; my $this_sql_insert; my $mysql_insert_table; my $sql_data; my $tempath; my $path; my $mysql_result; my $mysql_set_insert; my %mysql_set_insert; ############################################################################# # Section 4. CODE ############################################################################# #get the date time get_time(); #connect to the mysql database mysql_connect(); #get the clinic details my $clinic_details = mysql_hash_query("SELECT * FROM clinic"); #get the list of providers mysql_hash_query("select * from provider where last_name!='' && provider_type='doctor' order by last_name, first_name"); my @providers = @mysql_result; header(); #get the provider_no my $provider_no = mysql_array_query("SELECT provider_no FROM security WHERE user_name='$serverlogin'"); until ($provider_no) { print "USER NAME: [$serverlogin] "; my $login_id=; $login_id=~s/[^A-Z0-9\.\-\_]//gi; unless ($login_id) { $login_id = $serverlogin; } $provider_no = mysql_array_query("SELECT provider_no FROM security WHERE user_name='$login_id'"); unless ($provider_no) { print "\n"; print "Sorry, user name $login_id is not recognised.\n"; print "\n"; } } $provider_data = mysql_hash_query("SELECT * FROM provider WHERE provider_no='$provider_no'"); #get the clinic start time and appt lengths while ($clinic_start_time!~m/^\d{2}\:\d{2}$/) { print "\n\nClinic Start Time: [eg. 10:30] "; $clinic_start_time=; $clinic_start_time=~s/[\.\ \-]/\:/g; $clinic_start_time=~s/[^\d\:]//gi; } (my $clinic_start_hour, my $clinic_start_min) = split (/\:/, $clinic_start_time); my $end_hour; my $end_min; print "\nAppointment length (minutes): [5] "; $appt_length=; $appt_length=~s/[^\d]//gi; unless ($appt_length=~m/^(5|10|15|20|25|30)$/) { $appt_length = 5; } my $continue_loop = 1; while ($continue_loop) { get_time(); my $health_card_valid = qw{}; my $health_card_data = qw{}; my $hin = qw{}; my $hc_prov = qw{}; my $dob = qw{}; my $name = '1'; my $sex = '1'; my $first_name = '1'; my $middle_initial = '1'; my $last_name = '1'; my $parsed_first_name = '1'; my $parsed_last_name = '1'; my $date_of_birth = 'X'; my $month_of_birth = 'X'; my $day_of_birth = 'X'; my $year_of_birth = 'X'; my $hc_expiry_year = 'X'; my $hc_expiry_month = 'X'; my $phone = 'X'; my @first_names = qw(); $family_doctor = 'X'; $this_patient = qw{}; if ($clinic_start_min=~m/^\d$/) { $clinic_start_min="0$clinic_start_min"; } if ($clinic_start_hour=~m/^\d$/) { $clinic_start_hour="0$clinic_start_hour"; } header(); print "Next Appointment: $clinic_start_hour:$clinic_start_min \n\n"; until ($health_card_valid) { print "SWIPE HEALTH CARD\n\n"; print "or enter patient Province Code and Health # [PE 12345678]\n"; print "or enter 'none' if patient does not have a health card\n"; print "or enter new appt time [hh:mm]\n"; print "\n"; print "AB - ALBERTA\n"; print "BC - BRITISH COLUMBIA\n"; print "MB - MANITOBA\n"; print "NB - NEW BRUNSWICK\n"; print "NL - NEWFOUNDLAND LABRADOR\n"; print "NT - NORTHWEST TERRITORIES\n"; print "NS - NOVA SCOTIA\n"; print "NU - NUNAVUT\n"; print "ON - ONTARIO\n"; print "PE - PRINCE EDWARD ISLAND\n"; print "QC - QUEBEC\n"; print "SK - SASKATCHEWAN\n"; print "YT - YUKON\n"; print "US - UNITED STATES\n"; print "ZZ - OUTSIDE US & CANADA\n"; print "\n"; $health_card_data=; chomp $health_card_data; print "\n"; if ($health_card_data=~m/^\d{2}\:\d{2}$/) { ($clinic_start_hour, $clinic_start_min) = split (/\:/, $health_card_data); header(); print "Next Appointment: $clinic_start_hour:$clinic_start_min \n\n"; } elsif ($health_card_data=~m/none/i) { #the user wants to enter the data manually for a user with no health card $health_card_data = "none"; $hin = qw{}; $hc_prov = qw{}; $health_card_valid = 9; } elsif ($health_card_data=~m/^\d{$phn_length}$/) { #the user wants to enter the data manually for a local user $hc_prov = $province_code; $hin = $health_card_data; $health_card_data = "$province_code $health_card_data"; $health_card_valid = 9; } elsif ($health_card_data=~m/^(AB|BC|MB|NB|NL|NT|NS|NU|ON|PE|QC|SK|YT|US|ZZ)[\ \:\-\,\.]?(\d{6,14})$/) { #the user wants to enter the data manually' $health_card_data = "$1 $2"; $hc_prov = $1; $hin = $2; $health_card_valid = 9; } elsif ($health_card_data=~m/^\%(\d{8})\^([\w\ ]{1,200})\^([MF])\^(\d{4})(\d{2})(\d{2})\^(\d{2})(\d{2})\?\;(\d{8})\=(\d{1})\=(\d{4})(\d{2})(\d{2})\=(\d{2})(\d{2})\?$/i) { #this appears to be a valid PEI health card $health_card_valid = 1; $hc_prov = 'PE'; $hin = $1; $name = $2; $sex = $3; $year_of_birth = $4; $month_of_birth = $5; $day_of_birth = $6; $hc_expiry_year = $7; $hc_expiry_month= $8; $date_of_birth = "$year_of_birth-$month_of_birth-$day_of_birth"; my $confirm_hin = $9; my $confirm_sex = $10; my $confirm_year_of_birth = $11; my $confirm_month_of_birth = $12; my $confirm_day_of_birth = $13; my $confirm_hc_expiry_year = $14; my $confirm_hc_expiry_month= $15; #check the confirmation data matches the original card data unless ( ($hin eq $confirm_hin) && ($year_of_birth eq $confirm_year_of_birth) && ($month_of_birth eq $confirm_month_of_birth) && ($day_of_birth eq $confirm_day_of_birth) && ($hc_expiry_year eq $confirm_hc_expiry_year) && ($hc_expiry_month eq $confirm_hc_expiry_month) && (($sex eq 'M' && $confirm_sex eq '1') || ($sex eq 'F' && $confirm_sex eq '0')) ) { #the data does not match, so the card needs to be swiped again $health_card_valid = qw{}; header(); print "Problem reading card - try swiping card again.\n"; print "\n"; } #PEI health cards have a 2 digit expiry year - we need a four digit one $hc_expiry_year = "20$hc_expiry_year"; #Parse out the first and last names ($first_name, $middle_initial, $last_name) = split(/\ /, $name); unless ($last_name) { $last_name = $middle_initial; } if ($first_name=~m/^\w$/) { $first_name = $middle_initial; } } #elsif {$hin=~m/[insert province card regex]/} { #this appears to be a valid [insert province name] health card #$health_card_valid = 1; #$hc_prov = '[insert province code]'; #$hin = $1; #$name = $2; #$sex = $3; #$year_of_birth = $4; #$month_of_birth = $5; #$day_of_birth = $6; #$hc_expiry_year = $7; #$hc_expiry_month= $8; #} else { #this is not a valid PEI health card, so ask for the data again header(); print "Health card data not recognised.\n"; print "-Check that this is a $province_name Health Card.\n"; print "-Try swiping card again.\n"; print "-If problem persists, enter patient data manually.\n"; print "\n"; } } #default province/state is PE unless ($hc_prov) { $hc_prov = ' '; } unless ($hc_prov=~m/^(AB|BC|MB|NB|NL|NT|NS|NU|ON|PE|QC|SK|YT|US|ZZ)$/) { $hc_prov = $province_code; } #try and locate the health number and province codes in the database if ($hin) { $this_patient = mysql_hash_query("SELECT * FROM demographic WHERE hin='$hin' && hc_type='$hc_prov'"); } if ($this_patient) { #patient is in the system header(); print "${$this_patient}{'first_name'} ${$this_patient}{'last_name'}\n"; print "${$this_patient}{'hin'}\n"; print "\n"; print "\n"; #update the health card expiry date if necessary if (($hc_expiry_year) && ($hc_expiry_month)) { mysql_write_simple( "UPDATE demographic SET hc_renew_date='$hc_expiry_year-$hc_expiry_month-01' WHERE demographic_no='${$this_patient}{'demographic_no'}'" ); } #check the patient still has the same family doctor my $this_patients_provider = mysql_hash_query("SELECT * FROM provider WHERE provider_no='${$this_patient}{'provider_no'}'"); print "Is Dr. ${$this_patients_provider}{'first_name'} ${$this_patients_provider}{'last_name'} still this patient\'s family doctor? [Y/N]"; my $same_family_doctor=; chomp $same_family_doctor; #if not the same family doctor, pick a new one and update the database if ($same_family_doctor=~m/^N/i) { family_doctor(); mysql_write_simple( "UPDATE demographic SET provider_no='$family_doctor' WHERE demographic_no='${$this_patient}{'demographic_no'}'" ); } #check the patient still has the same phone number print "Patient's phone number [${$this_patient}{'phone'}]:"; my $same_phone_number=; chomp $same_phone_number; #if phone number entered and not the same as one on file, update the database if ($same_phone_number=~m/^[\d\ \-\(\)]{7,15}$/) { if ($same_phone_number ne ${$this_patient}{'phone'}) { ${$this_patient}{'phone'} = $same_phone_number; mysql_write_simple( "UPDATE demographic SET phone='${$this_patient}{'phone'}' WHERE demographic_no='${$this_patient}{'demographic_no'}'" ); } } #set the variables with this patient's data $last_name = ${$this_patient}{'last_name'}; $first_name = ${$this_patient}{'first_name'}; $phone = ${$this_patient}{'phone'}; $year_of_birth = ${$this_patient}{'year_of_birth'}; $month_of_birth = ${$this_patient}{'month_of_birth'}; $day_of_birth = ${$this_patient}{'date_of_birth'}; $hin = ${$this_patient}{'hin'}; $family_doctor = ${$this_patient}{'provider_no'}; $sex = ${$this_patient}{'sex'}; $hc_prov = ${$this_patient}{'hc_type'}; ($hc_expiry_year, $hc_expiry_month, my $temp) = split (/-/, ${$this_patient}{'eff_date'}); } else { #patient is not in the system #we'll need to get the rest of the data until ($first_name=~m/^[A-Z\ \-]*$/i) { print "First Name: "; $first_name=; $first_name = uc $first_name; chomp $first_name; unless ($first_name) { $first_name = $parsed_first_name; } } until ($last_name=~m/^[A-Z\ \-]*$/i) { print "Last Name: "; $last_name=; $last_name = uc $last_name; chomp $last_name; unless ($last_name) { $last_name = $parsed_last_name; } } until ($date_of_birth=~m/^\d{4}-\d{1,2}-\d{1,2}$/) { print "Date of Birth: [YYYY-MM-DD] "; $date_of_birth=; chomp $date_of_birth; $date_of_birth = uc $date_of_birth; #substitute other separators $date_of_birth=~s/[\ \.\:]/-/g; #separate words from figures if no separator entered if ($date_of_birth=~m/^(\d{1,4})([A-Z]*)(\d{1,4})$/i) { $date_of_birth="$1-$2-$3"; } #look for word versions of months for my $this_month_name (keys %month_names) { $date_of_birth=~s/[\-\ \.]?$this_month_name[\-\ \.]?/\-$month_names{$this_month_name}\-/; } #correct if DD-MM-YYYY format entered if ($date_of_birth=~m/^(\d{1,2})\-(\d{1,2})\-(\d{2,4})$/) { $date_of_birth="$3-$2-$1"; } #swtich month and day if DD-MM format entered if ($date_of_birth=~m/(\d{4})-(\d{1,2})\-(\d{1,2})/) { if ($2 > 12) { $date_of_birth="$1-$3-$2"; } } $date_of_birth=~m/^(\d{4})-(\d{1,2})-(\d{1,2})$/; $year_of_birth = $1; $month_of_birth = $2; $day_of_birth = $3; } until ($sex=~m/^[MF]$/i) { print "Sex: [M/F] "; $sex=; chomp $sex; $sex = uc $sex; } if ($hin) { until ( ($hc_expiry_year=~m/^\d{4}$/i) && ($hc_expiry_year > $longyr-10) && ($hc_expiry_year <= $longyr+10) ) { print "Health Card Exp.Year: [2000] "; $hc_expiry_year=; chomp $hc_expiry_year; unless ($hc_expiry_year) { $hc_expiry_year = '2000'; } } until ( ($hc_expiry_month=~m/^\d{1,2}$/i) && ($hc_expiry_month > 0) && ($hc_expiry_month < 13) ) { print "Health Card Exp.Month: [01] "; $hc_expiry_month=; chomp $hc_expiry_month; unless ($hc_expiry_month) { $hc_expiry_month = '01'; } } } until (($phone=~m/^\(\d{3}\) \d{3}-\d{4}$/i) || ($phone eq 'NONE')) { print "Phone number: "; $phone=; chomp $phone; $phone = uc $phone; unless ($phone) { last; } if ($phone=~m/^\(?(\d{3})\)?[\ \-]?(\d{3})[\ \-]?(\d{4})$/i) { $phone = "($1) $2-$3"; } if ($phone=~m/^(\d{3})\ ?(\d{4})$/i) { $phone = "$1-$2"; } if (($phone=~m/^(\d{3})[\ \-]?(\d{4})$/i) && ($hc_prov eq $province_code)) { $phone = "($province_phone_code) $1-$2"; } } family_doctor(); #insert this patient into the system %mysql_set_insert=( 'last_name' => $last_name, 'first_name' => $first_name, 'phone' => $phone, 'phone2' => '', 'email' => '', 'pin' => '', 'year_of_birth' => $year_of_birth, 'month_of_birth' => $month_of_birth, 'date_of_birth' => $day_of_birth, 'hin' => $hin, 'ver' => '', 'roster_status' => 'NR', 'patient_status' => 'IN', 'date_joined' => $sql_date, 'chart_no' => '', 'provider_no' => $family_doctor, 'sex' => $sex, 'end_date' => '0001-01-01', 'hc_type' => $hc_prov, 'eff_date' => "$hc_expiry_year-$hc_expiry_month-01", 'hc_renew_date' => "$hc_expiry_year-$hc_expiry_month-01", 'family_doctor' => '', 'sin' => '', 'country_of_origin' => '-1', 'newsletter' => 'Unknown' ); mysql_set_insert('demographic'); #reload and double check we now have patient data $this_patient = mysql_hash_query("SELECT * FROM demographic WHERE hin='$hin' && hc_type='$hc_prov' && year_of_birth='$year_of_birth' && month_of_birth='$month_of_birth' && date_of_birth='$day_of_birth' && last_name='$last_name' && first_name='$first_name'"); unless ($this_patient) { print "ERROR: PATIENT DATA NOT STORED PROPERLY\n\n\n"; exit; } #add an admission record linking this patient to the clinic provider %mysql_set_insert=( 'client_id' => ${$this_patient}{'demographic_no'}, 'program_id' => $program_id, 'provider_no' => $current_provider, 'admission_date' => $sql_date, 'admission_from_transfer' => '0', 'discharge_from_transfer' => '0', 'admission_status' => 'current', 'team_id' => '0', 'temporary_admission_flag' => '0', 'radioDischargeReason' => '0', 'clientstatus_id' => '0', 'automatic_discharge' => '0' ); mysql_set_insert('admission'); } #print "\n1. SH=$clinic_start_hour, SM=$clinic_start_min, AL=$appt_length, EH=$end_hour, EM=$end_min\n"; my $actual_end_hour = $end_hour = $clinic_start_hour; $end_min = $clinic_start_min + $appt_length; my $actual_end_min = $end_min -1; if ($actual_end_min > 59) { $actual_end_min = $actual_end_min - 60; ++$actual_end_hour; } if ($end_min > 59) { $end_min = $end_min - 60; ++$end_hour; } #print "2. SH=$clinic_start_hour, SM=$clinic_start_min, AL=$appt_length, EH=$end_hour, EM=$end_min\n"; #now add the appointment to the database %mysql_set_insert=( 'provider_no' => $current_provider, 'appointment_date' => "$longyr-$fixmo-$mday", 'start_time' => "$clinic_start_hour:$clinic_start_min", 'end_time' => "$actual_end_hour:$actual_end_min:00", 'name' => "${$this_patient}{'last_name'}, ${$this_patient}{'first_name'}", 'demographic_no' => "${$this_patient}{'demographic_no'}", 'notes' => '', 'reason' => '#WIC', 'location' => '', 'resources' => '', 'type' => '', 'remarks' => '', 'status' => 'H', 'createdatetime' => $sql_datetime, 'creator' => "${$provider_data}{'last_name'}, ${$provider_data}{'first_name'}" ); mysql_set_insert('appointment'); #print "3. SH=$clinic_start_hour, SM=$clinic_start_min, AL=$appt_length, EH=$end_hour, EM=$end_min\n\n"; my $family_doctor_name = mysql_array_query("SELECT CONCAT(first_name,' ', last_name) AS provider_name FROM provider WHERE provider_no='$family_doctor'"); if ($clinic_start_min < 10) { $clinic_start_min = "0$clinic_start_min"; } header(); print "\n"; print "APPOINTMENT ADDED\n"; print "\n"; print "Appointment time: $clinic_start_hour:$clinic_start_min\n"; print "\n"; print "Name: ${$this_patient}{'first_name'} ${$this_patient}{'last_name'}\n"; print "Phone number: ${$this_patient}{'phone'}\n"; print "Date of birth: ${$this_patient}{'year_of_birth'}-$month_names[${$this_patient}{'month_of_birth'}]-${$this_patient}{'date_of_birth'}\n"; print "Sex ${$this_patient}{'sex'}\n"; print "Family Doctor: $family_doctor_name\n"; print "Health # ${$this_patient}{'hin'}\n"; print "Province: ${$this_patient}{'hc_type'}\n"; print "Exp. date: ${$this_patient}{'eff_date'}\n"; print "\n"; print "\n"; print "\n"; #check if this patient needs to pay. my $fee_due = 1; my $card_expired = 0; my $fee_reason = ' '; if ( (${$this_patient}{'roster_status'} eq 'FS') || ($card_expired) ) { $fee_due = $canada_fee; $fee_reason = 'Fee for Service roster status'; } elsif ( (${$this_patient}{'hc_type'} eq 'QC') || ($card_expired) ) { $fee_due = $canada_fee; $fee_reason = 'Quebec resident'; } elsif ( (${$this_patient}{'hc_type'} eq 'US') || (${$this_patient}{'hc_type'} eq 'ZZ') ) { $fee_reason = 'Foreign resident'; $fee_due = $other_fee; } elsif ( ($hin eq '') || ($hc_expiry_year < $longyr) || ( ($hc_expiry_year == $longyr) && ($hc_expiry_month < $fixmo) ) ) { $card_expired = 1; $fee_reason = 'Health Card Expired/Missing'; } if ($fee_due > 1) { print "######################################################################\n"; print " $fee_reason"; print " FEE DUE: \$$fee_due\n"; print "######################################################################\n"; print "\n"; print "Press enter to print invoice.\n"; my $continue=; my $message2 = "${$clinic_details}{'clinic_name'}\n"; $message2.= "\n"; $message2.= "${$clinic_details}{'clinic_address'}\n"; $message2.= "${$clinic_details}{'clinic_city'}\n"; $message2.= "${$clinic_details}{'clinic_province'} ${$clinic_details}{'clinic_postal'}\n"; $message2.= "\n"; $message2.= "Tel. ${$clinic_details}{'clinic_phone'}\n"; $message2.= "Fax. ${$clinic_details}{'clinic_fax'}\n"; $message2.= "_______________________________________________________________________________________\n"; $message2.= "\n"; $message2.= "DOCTOR: Dr. ${$provider_data}{'first_name'} ${$provider_data}{'last_name'}\n"; $message2.= "BILLING #: ${$provider_data}{'billing_no'}\n"; $message2.= "DATE OF SERVICE: $sql_date\n"; $message2.= "_______________________________________________________________________________________\n"; $message2.= "\n"; $message2.= "PATIENT NAME: ${$this_patient}{'last_name'}, ${$this_patient}{'first_name'}\n"; $message2.= "DoB: ${$this_patient}{'year_of_birth'}-${$this_patient}{'month_of_birth'}-${$this_patient}{'date_of_birth'}\n"; $message2.= "HEALTH #: ${$this_patient}{'hin'}\n"; $message2.= "_______________________________________________________________________________________\n"; $message2.= "\n"; $message2.= "INVOICE FOR MEDICAL CONSULTATION\n"; $message2.= "\n"; $message2.= "REASON FOR FEE: $fee_reason\n"; $message2.= "\n"; $message2.= "FEE PAID: \$$fee_due\n"; $message2.= "\n"; $message2.= "\n"; $message2.= "\n"; $message2.= "\n"; $message2.= "\n"; $message2.= "__________________________________________________________________________________________\n"; $message2.= "OSCAR - the free Canadian Electronic Medical Record - http://blog.oscarpei.net"; #print the billing sheet out ++$report_number; $tempath = "$tempdir/report.$report_number.txt"; open (MESSAGE, ">$tempath"); print MESSAGE $message2; close (MESSAGE); system ("enscript --header-font='Bookman-Demi14' --header='INVOICE||OSCAR ELECTRONIC MEDICAL RECORD' --footer='' --word-wrap $tempath"); if ($print_two_invoices) { ++$report_number; $message2 = "COPY INVOICE\n\n".$message2; $tempath = "$tempdir/report.$report_number.txt"; open (MESSAGE, ">$tempath"); print MESSAGE $message2; close (MESSAGE); system ("enscript --header-font='Bookman-Demi14' --header='COPY INVOICE||OSCAR ELECTRONIC MEDICAL RECORD' --footer='' --word-wrap $tempath"); } print "\n"; print "Report sent to printer.\n"; print "\n"; print "\n"; } #update the clinic start time $clinic_start_hour = $end_hour; $clinic_start_min = $end_min; print "Press 'enter' to add another patient [Q to quit]\n"; my $continue=; if ($continue=~m/Q/i) { print "\n"; print "Are you sure you want to quit? [Y/N]"; my $continue=; if ($continue=~m/Y/i) { print "\n"; print "Goodbye!\n"; print "\n"; exit; } exit; } } #disconnect from the database mysql_disconnect(); print "\n\nGoodbye.\n\n"; exit; ########################### #subroutines ########################### sub family_doctor { until ($family_doctor=~m/^\d{4}$/i) { #with 3 columns, work out how many lines we need my %lines = qw{}; my $current_line = 1; my $add_to_line = qw{}; my $lines_needed = int(scalar(@providers)/3); unless (int(scalar(@providers)/3) == (scalar(@providers)/3)) { ++$lines_needed } #print out a list of providers for my $this_provider (@providers) { if ($use_full_provider_no) { $add_to_line = pad_for_tabulation(${$this_provider}{'provider_no'}, 4, ' ', 'R'); } else { ${$this_provider}{'provider_no'}=~m/(\d{1,2}$)/; my $truncated_provider_no=$1; $add_to_line = pad_for_tabulation($truncated_provider_no, 2, ' ', 'R'); } $add_to_line.= "."; $add_to_line.= pad_for_tabulation("${$this_provider}{'last_name'}", 12, '.', 'L'); $add_to_line.= pad_for_tabulation(${$this_provider}{'first_name'}, 12, ' ', 'L'); $add_to_line.= "|"; $lines{$current_line}.= $add_to_line; ++$current_line; if ($current_line > $lines_needed) { $current_line = 1; } } for ($current_line = 1; $current_line <= $lines_needed; ++$current_line) { print "$lines{$current_line}\n"; } $current_provider=~m/(\d{1,2}$)/; my $truncated_provider_no=$1; print "Family doctor: "; if ($use_full_provider_no) { print "[$other_doctor] "; } else { print " [$truncated_other_doctor] "; } $family_doctor=; chomp $family_doctor; $family_doctor=~s/\D//g; unless ($family_doctor) { $family_doctor = $other_doctor; } if ($family_doctor=~m/^\d{1}$/) { $family_doctor = $provider_no_prefix."0$family_doctor"; } if ($family_doctor=~m/^\d{2}$/) { $family_doctor = "$provider_no_prefix$family_doctor"; } #check the provider is listed if ($family_doctor=~m/^\d{4}$/i) { my $check_family_doctor = mysql_hash_query("select * from provider where provider_no='$family_doctor' && last_name!='' && provider_type='doctor' order by last_name, first_name"); unless (${$check_family_doctor}{'provider_no'}) { $family_doctor = qw{}; } } } } sub header { system ("clear"); print "-------------------------------\n"; print "OSCAR EMR - WALK IN CLINIC\n"; print "-------------------------------\n"; print "\n" ; } sub get_time { #get the date time ( $sec, $min, $hr, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); $longyr = $year + 1900; $fixmo = $mon + 1; if ($isdst == 1) { my $tz = "CDT"; } else { my $tz = "CST"; } if ($hr<10) { $hr="0".$hr; } if ($min<10) { $min="0".$min; } my $sqlmo=$fixmo; if ($sqlmo<10) { $sqlmo="0".$sqlmo; } my $sqlmday=$mday; if ($sqlmday<10) { $sqlmday="0".$sqlmday; } $sql_date="$longyr-$fixmo-$mday"; $sql_time="$hr:$min:$sec"; $sql_datetime="$sql_date $sql_time"; } sub mysql_log { if ($_[0]) { $sql_data=$_[0]; } if ($pref{mysql_log}) { unless ($sql_data) { $sql_data=$sql; } $sql_data=~s/\s/ /g; open (MYSQL,">>$pref{mysql_log}"); flock (MYSQL, 2); print MYSQL "$longyr-$fixmo-$mday $hr:$min:$sec - $sql_data\n"; close (MYSQL); } return; } sub mysql_connect { #set up login and password for this user unless ($mysql_user) { $mysql_user="read"; } $mysql_login="mysql_".$mysql_user; $mysql_pass="mysql_".$mysql_user."_pass"; $dbh_name="dbh_$mysql_user"; # Connect to the database mysql_log("mysql_connect : mysql_user=$mysql_user, dbh_name=$dbh_name, mysql_login=$mysql_login, mysql_pass=$mysql_pass"); ${$dbh_name} = DBI->connect("DBI:mysql:$pref{mysql_database}:$pref{mysql_host}:$pref{mysql_port}","$pref{$mysql_login}","$pref{$mysql_pass}") || ErrorMessage('Could not connect to database'); #record that this database is in use $dbh_inuse="dbh_inuse_$mysql_user"; ${$dbh_inuse}=1; return; } sub mysql_disconnect { # Disconnect the current user ($mysql_user) from the database # but don't disconnect the read-only user #get the passed user name if passed directly if ($_[0]) { $mysql_user=$_[0]; } if (($mysql_user) && ($mysql_user ne "read")) { #check that the user is connected first $dbh_inuse="dbh_inuse_$mysql_user"; if (${$dbh_inuse}) { #this user is connected $dbh_name="dbh_$mysql_user"; mysql_log("mysql_disconnect : mysql_user=$mysql_user, dbh_name=$dbh_name, mysql_login=$mysql_login, mysql_pass=$mysql_pass"); ${$dbh_name}->disconnect || mysql_log('ERROR could not disconnect database'); #record that this database is no longer in use ${$dbh_inuse}=0; } } return; } sub mysql_check_connection { #check that the preferred user is the one currently selected if ($mysql_user eq $mysql_preferred_user) { $mysql_original_user=$mysql_user; } else { $mysql_original_user=$mysql_user; $mysql_user=$mysql_preferred_user; } $dbh_name="dbh_$mysql_user"; $dbh_inuse="dbh_inuse_$mysql_user"; $mysql_disconnect=0; #check that the preferred user is connected unless (${$dbh_inuse}) { #this user is not connected $mysql_disconnect=1; mysql_connect(); } return; } sub mysql_check_connection_finish { #check if this user was only connected for this event if ($mysql_disconnect) { mysql_disconnect(); } #reset the current user to the original user $mysql_user=$mysql_original_user; return $mysql_user; } sub mysql_simple { #this subroutine is passed a full statement as $sql and sends it to the database as a 'read' user #get passed sql string if present if ($_[0]) { $sql=$_[0]; } $mysql_preferred_user="read"; mysql_submit_simple($sql); return 1; } sub mysql_write_simple { #this subroutine is passed a full statement as $sql and sends it to the database as a 'write' user #get passed sql string if present if ($_[0]) { $sql=$_[0]; } #print "\n\n**test mode** sub mysql_write_simple has had mysql_submit_simple($sql) commented out - your data has NOT been saved!\n\n$sql\n\n"; $mysql_preferred_user="write"; mysql_submit_simple($sql); return 1; } sub mysql_submit_simple { #this subroutine is passed a full statement as $sql and sends it to the database as the user $preferred_user #get passed sql string if present if ($_[0]) { $sql=$_[0]; } @mysql_row=(); mysql_check_connection(); mysql_log("mysql_submit_simple : $sql"); $mysql_query = ${$dbh_name}->do ($sql) || ErrorMessage('Could not submit data to the database'); mysql_check_connection_finish(); return 1; } sub mysql_array_query { #get passed sql string if present if ($_[0]) { $sql=$_[0]; } $mysql_preferred_user="read"; mysql_check_connection(); $mysql_query = ${$dbh_name}->prepare ($sql); @mysql_result=(); if (defined($mysql_query)) { mysql_log("mysql_array_query : $sql"); $mysql_query->execute() || ErrorMessage('Could not execute array query on database'); while (@mysql_row = $mysql_query->fetchrow_array()) { @mysql_result=@mysql_row; } } else { mysql_log("mysql_array_query (not found) : $sql"); ErrorMessage('Could not find query to submit to database'); } $mysql_query->finish(); mysql_check_connection_finish(); #pass the first result back as a return value (or undefined, if no result) if ($mysql_result[0]) { return $mysql_result[0]; } return; } sub mysql_hash_query { #get passed sql string if present if ($_[0]) { $sql=$_[0]; } $mysql_preferred_user="read"; mysql_check_connection(); $mysql_query = ${$dbh_name}->prepare ($sql); @mysql_result=(); if (defined($mysql_query)) { mysql_log("mysql_hash_query : $sql"); $mysql_query->execute() || ErrorMessage('Could not execute hash query on database'); @mysql_result=(); while ($mysql_record = $mysql_query->fetchrow_hashref()) { push (@mysql_result, $mysql_record); } } else { mysql_log("mysql_hash_query (not found) : $sql"); ErrorMessage('Could not find hash query to submit to database'); } $mysql_query->finish(); mysql_check_connection_finish(); #return the mysql_result array (containing hash references), or undefined if no result if ($mysql_result[0]) { return $mysql_result[0]; } return; } sub mysql_set_insert { #this subroutine is passed: # 1. the table name ($mysql_update_table) # 2. a hash of elements to include (%mysql_update) #and it then creates a mysql statement ($sql) and sends it to the database as a 'write' user #get the passed table name if passed directly if ($_[0]) { $mysql_insert_table=$_[0]; } $mysql_preferred_user="write"; mysql_check_connection(); #insert this line in the database $error="mysql_insert"; $sql="INSERT INTO $mysql_insert_table SET "; for $this_sql_insert (keys %mysql_set_insert) { $mysql_set_insert{$this_sql_insert}=~s/\'/\`/g; $sql.="$this_sql_insert='$mysql_set_insert{$this_sql_insert}', "; } $sql=~s/, $//; mysql_log("mysql_set_insert : $sql"); mysql_write_simple($sql); mysql_check_connection_finish(); return; } sub pad_for_tabulation { #pads out the string #pass the following variables: #1. the string to be padded - including decimals, decimal places, and thousands separators #2. the desired length #3. the character to use for padding (usually ' ' or '0', defaults to '0') #4. right of left justify ('R' or 'L') #5. the number of decimal places to use, preceeded by T if thousands commas to be used (eg: '2', 'T2' or just'T' to just include thousands) ($string_to_be_padded, $desired_string_length, $padding_character, $right_or_left_justify, $decimal_places) = @_; unless ($padding_character) { $padding_character='0'; } #add decimal places if ($decimal_places) { $decimals=q{}; if ($decimal_places =~m/\d/) { $decimal_places_digit=$decimal_places; $decimal_places_digit=~s/^T//; ($string_to_be_padded, $decimals) = split (/\./, $string_to_be_padded); $decimals.="0"x$decimal_places_digit; $decimals=substr ($decimals, 0, $decimal_places_digit); $decimals=".$decimals"; } #add thousands separators if required if ($decimal_places =~m/T/) { $string_to_be_padded=~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g; } $string_to_be_padded.=$decimals; } #next check if the string is too long, and truncate if required if (length $string_to_be_padded > $desired_string_length) { $string_to_be_padded=substr ($string_to_be_padded, 0, $desired_string_length); } $missing_digits = $desired_string_length - (length $string_to_be_padded); $missing_digits="$padding_character"x$missing_digits; if ($right_or_left_justify eq 'L') { $string_to_be_padded=$string_to_be_padded.$missing_digits; } else { $string_to_be_padded=$missing_digits.$string_to_be_padded; } return $string_to_be_padded; } sub rand_id { my $rand_id_digits = $_[0]; unless ($rand_id_digits) { $rand_id_digits = 5; } my $rand_id=''; while (length $rand_id < $rand_id_digits) { my $ftemp=int(rand 9)+1; $rand_id.=$ftemp; } return $rand_id; } sub ErrorMessage { print "\n"; print "\n"; print "Error: $_\n"; exit; }