diff --git a/custom/code_types.inc.php b/custom/code_types.inc.php index 07d230c4f54..c8e6177bb8e 100644 --- a/custom/code_types.inc.php +++ b/custom/code_types.inc.php @@ -1,75 +1,67 @@ -// -// This program 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 2 -// of the License, or (at your option) any later version. - -// This array provides abstraction of billing code types. This is desirable -// because different countries or fields of practice use different methods for -// coding diagnoses, procedures and supplies. Fees will not be relevant where -// medical care is socialized. Attribues are: -// -// id - the numeric identifier of this code type in the codes table -// fee - 1 if fees are used, else 0 -// mod - the maximum length of a modifier, 0 if modifiers are not used -// just - the code type used for justification, empty if none -// rel - 1 if other billing codes may be "related" to this code type -// nofs - 1 if this code type should NOT appear in the Fee Sheet -// diag - 1 if this code type is for diagnosis -// active - 1 if this code type is activated -// label - label used for code type -// external - 0 for storing codes in the code table -// 1 for storing codes in external ICD10 tables -// 2 for storing codes in external SNOMED (RF1) tables -// 3 for storing codes in external SNOMED (RF2) tables -// 4 for storing codes in external ICD9 tables -// - -/********************************************************************* -if ($GLOBALS['ippf_specific']) { - // IPPF: - $code_types = array( - 'ICD9' => array('id' => 2, 'fee' => 0, 'mod' => 0, 'just' => '', 'rel' => 0, 'nofs' => 0, 'diag' => TRUE), - 'MA' => array('id' => 12, 'fee' => 1, 'mod' => 0, 'just' => '', 'rel' => 1, 'nofs' => 0), - 'IPPF' => array('id' => 11, 'fee' => 0, 'mod' => 0, 'just' => '', 'rel' => 0, 'nofs' => 1), - 'ACCT' => array('id' => 13, 'fee' => 0, 'mod' => 0, 'just' => '', 'rel' => 0, 'nofs' => 1), - ); - $default_search_type = 'MA'; -} -else if ($GLOBALS['athletic_team']) { - // UK Sports Medicine: - $code_types = array( - 'OSICS10' => array('id' => 9, 'fee' => 0, 'mod' => 4, 'just' => '', 'rel' => 0, 'nofs' => 0, 'diag' => TRUE), - 'OPCS' => array('id' => 6, 'fee' => 0, 'mod' => 0, 'just' => '', 'rel' => 0, 'nofs' => 0), - 'PTCJ' => array('id' => 7, 'fee' => 0, 'mod' => 0, 'just' => '', 'rel' => 0, 'nofs' => 0), - 'CPT4' => array('id' => 1, 'fee' => 0, 'mod' => 0, 'just' => '', 'rel' => 0, 'nofs' => 0), - 'SMPC' => array('id' => 10, 'fee' => 0, 'mod' => 0, 'just' => '', 'rel' => 0, 'nofs' => 0), - ); - $default_search_type = 'OSICS10'; -} -else { - // USA Clinics: - $code_types = array( - 'ICD9' => array('id' => 2, 'fee' => 0, 'mod' => 2, 'just' => '' , 'rel' => 0, 'nofs' => 0, 'diag' => TRUE), - 'CPT4' => array('id' => 1, 'fee' => 1, 'mod' => 2, 'just' => 'ICD9', 'rel' => 0, 'nofs' => 0), - 'HCPCS' => array('id' => 3, 'fee' => 1, 'mod' => 2, 'just' => 'ICD9', 'rel' => 0, 'nofs' => 0), - ); - $default_search_type = 'ICD9'; -} -*********************************************************************/ +/** + * Library to manage Code Types and code type lookups. + * + * The $code_types array is built from the code_types sql table and provides + * abstraction of diagnosis/billing code types. This is desirable + * because different countries or fields of practice use different methods for + * coding diagnoses, procedures and supplies. Fees will not be relevant where + * medical care is socialized. Attribues are: + * id - the numeric identifier of this code type in the codes table + * fee - 1 if fees are used, else 0 + * mod - the maximum length of a modifier, 0 if modifiers are not used + * just - the code type used for justification, empty if none + * rel - 1 if other billing codes may be "related" to this code type + * nofs - 1 if this code type should NOT appear in the Fee Sheet + * diag - 1 if this code type is for diagnosis + * active - 1 if this code type is activated + * label - label used for code type + * external - 0 for storing codes in the code table + * 1 for storing codes in external ICD10 Diagnosis tables + * 2 for storing codes in external SNOMED (RF1) Diagnosis tables + * 3 for storing codes in external SNOMED (RF2) Diagnosis tables + * 4 for storing codes in external ICD9 Diagnosis tables + * 5 for storing codes in external ICD9 Procedure/Service tables + * 6 for storing codes in external ICD10 Procedure/Service tables + * + * Copyright (C) 2006-2010 Rod Roark + * + * LICENSE: This program 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 2 + * of the License, or (at your option) any later version. + * This program 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. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see ;. + * + * @package OpenEMR + * @author Rod Roark + * @author Brady Miller + * @link http://www.open-emr.org + */ +/** + * This array stores the external table options. See above for option listings. + * @var array + */ $cd_external_options = array( '0' => xl('No'), - '1' => xl('ICD10'), - '2' => xl('SNOMED (RF1)'), - '3' => xl('SNOMED (RF2)'), - '4' => xl('ICD9') + '4' => xl('ICD9 Diagnosis'), + '5' => xl('ICD9 Procedure/Service'), + '1' => xl('ICD10 Diagnosis'), + '6' => xl('ICD10 Procedure/Service'), + '2' => xl('SNOMED (RF1) Diagnosis'), + '3' => xl('SNOMED (RF2) Diagnosis'), ); -// Code types are now stored in the database. -// +/** + * This array is built from the code_types sql table and provides + * abstraction of the diagnosis/billing code types. + * @var array + */ $code_types = array(); $default_search_type = ''; $ctres = sqlStatement("SELECT * FROM code_types WHERE ct_active=1 ORDER BY ct_seq, ct_key"); @@ -89,14 +81,24 @@ if ($default_search_type === '') $default_search_type = $ctrow['ct_key']; } -/********************************************************************/ - +/** + * Checks is fee are applicable to any of the code types. + * + * @return boolean + */ function fees_are_used() { global $code_types; foreach ($code_types as $value) { if ($value['fee']) return true; } return false; } +/** + * Checks is modifiers are applicable to any of the code types. + * (If a code type is not set to show in the fee sheet, then is ignored) + * + * @param boolean $fee_sheet Will ignore code types that are not shown in the fee sheet + * @return boolean + */ function modifiers_are_used($fee_sheet=false) { global $code_types; foreach ($code_types as $value) { @@ -106,13 +108,23 @@ function modifiers_are_used($fee_sheet=false) { return false; } +/** + * Checks is related codes are applicable to any of the code types. + * + * @return boolean + */ function related_codes_are_used() { global $code_types; foreach ($code_types as $value) { if ($value['rel']) return true; } return false; } -// Convert a code type id to a key +/** + * Convert a code type id (ct_id) to the key string (ct_key) + * + * @param integer $id + * @return string + */ function convert_type_id_to_key($id) { global $code_types; foreach ($code_types as $key => $value) { @@ -120,15 +132,23 @@ function convert_type_id_to_key($id) { } } -// Main code set searching function -// $form_code_type - code set key (special keywords are PROD and --ALL--) -// $search_term - search term -// $count - if true, then will only return the number of entries -// $active - if true, then will only return active entries (not pertinent for PROD or external code sets) -// $return_only_one - if true, then will only return one perfect matching item -// $start - Query start limit -// $number - Query number returned -// $filter_elements - Array that contains elements to filter +/** + * Main code set searching function. + * + * Function is able to search a variety of code sets. See the 'external' items in the comments at top + * of this page for a listing of the code sets supported. Also note that Products (using PROD as code type) + * is also supported. + * + * @param string $form_code_type code set key (special keywords are PROD and --ALL--) + * @param string $search_term search term + * @param boolean $count if true, then will only return the number of entries + * @param boolean $active if true, then will only return active entries (not pertinent for PROD code sets) + * @param boolean $return_only_one if true, then will only return one perfect matching item + * @param integer $start Query start limit + * @param integer $number Query number returned + * @param array $filter_elements Array that contains elements to filter + * @return recordset + */ function code_set_search($form_code_type,$search_term="",$count=false,$active=true,$return_only_one=false,$start=NULL,$number=NULL,$filter_elements=array()) { global $code_types; @@ -144,7 +164,7 @@ function code_set_search($form_code_type,$search_term="",$count=false,$active=tr $query_filter_elements=""; if (!empty($filter_elements)) { foreach ($filter_elements as $key => $element) { - $query_filter_elements .= " AND codes." . add_escape_custom($key) . "=" . "'" . add_escape_custom($element) . "' "; + $query_filter_elements .= " AND c." . add_escape_custom($key) . "=" . "'" . add_escape_custom($element) . "' "; } } @@ -162,16 +182,16 @@ function code_set_search($form_code_type,$search_term="",$count=false,$active=tr $active_query = ''; if ($active) { // Only filter for active codes - $active_query=" AND codes.active = 1 "; + $active_query=" AND c.active = 1 "; } - $query = "SELECT `id`, `code_text`, `code_text_short`, `code`, `code_type`, `modifier`, `units`, `fee`, " . - "`superbill`, `related_code`, `taxrates`, `cyp_factor`, `active`, `reportable`, `financial_reporting`, " . - "code_types.ct_key as code_type_name " . - "FROM `codes` " . - "LEFT OUTER JOIN `code_types` " . - "ON codes.code_type = code_types.ct_id " . - "WHERE (codes.code_text LIKE ? OR " . - "codes.code LIKE ?) AND code_types.ct_external = '0' " . + $query = "SELECT c.id, c.code_text, c.code_text_short, c.code, c.code_type, c.modifier, c.units, c.fee, " . + "c.superbill, c.related_code, c.taxrates, c.cyp_factor, c.active, c.reportable, c.financial_reporting, " . + "ct.ct_key as code_type_name " . + "FROM `codes` as c " . + "LEFT OUTER JOIN `code_types` as ct " . + "ON c.code_type = ct.ct_id " . + "WHERE (c.code_text LIKE ? OR " . + "c.code LIKE ?) AND ct.ct_external = '0' " . " $active_query " . " $query_filter_elements " . "ORDER BY code_type,code+0,code $limit_query"; @@ -181,121 +201,184 @@ function code_set_search($form_code_type,$search_term="",$count=false,$active=tr $active_query = ''; if ($active) { // Only filter for active codes - $active_query=" AND codes.active = 1 "; + $active_query=" AND c.active = 1 "; } $sql_bind_array = array(); - $query = "SELECT `id`, `code_text`, `code_text_short`, `code`, `code_type`, `modifier`, `units`, `fee`, " . - "`superbill`, `related_code`, `taxrates`, `cyp_factor`, `active`, `reportable`, `financial_reporting`, " . + $query = "SELECT c.id, c.code_text, c.code_text_short, c.code, c.code_type, c.modifier, c.units, c.fee, " . + "c.superbill, c.related_code, c.taxrates, c.cyp_factor, c.active, c.reportable, c.financial_reporting, " . "'" . add_escape_custom($form_code_type) . "' as code_type_name " . - "FROM `codes` "; + "FROM `codes` as c "; if ($return_only_one) { - $query .= "WHERE codes.code = ? "; + $query .= "WHERE c.code = ? "; array_push($sql_bind_array,$search_term); } else { - $query .= "WHERE (codes.code_text LIKE ? OR codes.code LIKE ?) "; + $query .= "WHERE (c.code_text LIKE ? OR c.code LIKE ?) "; array_push($sql_bind_array,"%".$search_term."%", "%".$search_term."%"); } - $query .= "AND code_type = ? $active_query $query_filter_elements " . - "ORDER BY code+0,code $limit_query"; + $query .= "AND c.code_type = ? $active_query $query_filter_elements " . + "ORDER BY c.code+0,c.code $limit_query"; array_push($sql_bind_array,$code_types[$form_code_type]['id']); $res = sqlStatement($query,$sql_bind_array); } - else if ($code_types[$form_code_type]['external'] == 1 ) { // Search from ICD10 codeset tables + else if ($code_types[$form_code_type]['external'] == 1 ) { // Search from ICD10 diagnosis codeset tables $active_query = ''; if ($active) { // Only filter for active codes // If there is no entry in codes sql table, then default to active // (this is reason for including NULL below) - $active_query=" AND (codes.active = 1 || codes.active IS NULL) "; + $active_query=" AND (c.active = 1 || c.active IS NULL) "; } // Ensure the icd10_dx_order_code sql table exists $check_table = sqlQuery("SHOW TABLES LIKE 'icd10_dx_order_code'"); if ( !(empty($check_table)) ) { $sql_bind_array = array(); - $query = "SELECT icd10_dx_order_code.formatted_dx_code as code, icd10_dx_order_code.long_desc as code_text, " . - "codes.id, codes.code_type, codes.modifier, codes.units, codes.fee, " . - "codes.superbill, codes.related_code, codes.taxrates, codes.cyp_factor, codes.active, codes.reportable, codes.financial_reporting, " . + $query = "SELECT ref.formatted_dx_code as code, ref.long_desc as code_text, " . + "c.id, c.code_type, c.modifier, c.units, c.fee, " . + "c.superbill, c.related_code, c.taxrates, c.cyp_factor, c.active, c.reportable, c.financial_reporting, " . "'" . add_escape_custom($form_code_type) . "' as code_type_name " . - "FROM `icd10_dx_order_code` " . - "LEFT OUTER JOIN `codes` " . - "ON icd10_dx_order_code.formatted_dx_code = codes.code AND codes.code_type = ? "; + "FROM `icd10_dx_order_code` as ref " . + "LEFT OUTER JOIN `codes` as c " . + "ON ref.formatted_dx_code = c.code AND c.code_type = ? "; array_push($sql_bind_array,$code_types[$form_code_type]['id']); if ($return_only_one) { - $query .= "WHERE icd10_dx_order_code.formatted_dx_code = ? AND icd10_dx_order_code.valid_for_coding = '1' $active_query $query_filter_elements "; + $query .= "WHERE ref.formatted_dx_code = ? AND ref.valid_for_coding = '1' $active_query $query_filter_elements "; array_push($sql_bind_array,$search_term); } else { - $query .= "WHERE (icd10_dx_order_code.long_desc LIKE ? OR icd10_dx_order_code.formatted_dx_code LIKE ?) AND icd10_dx_order_code.valid_for_coding = '1' $active_query $query_filter_elements"; + $query .= "WHERE (ref.long_desc LIKE ? OR ref.formatted_dx_code LIKE ?) AND ref.valid_for_coding = '1' $active_query $query_filter_elements"; array_push($sql_bind_array,"%".$search_term."%","%".$search_term."%"); } - $query .= "ORDER BY `formatted_dx_code`+0, `formatted_dx_code` $limit_query"; + $query .= "ORDER BY ref.formatted_dx_code+0, ref.formatted_dx_code $limit_query"; $res = sqlStatement($query,$sql_bind_array); } } - else if ($code_types[$form_code_type]['external'] == 2 ) { // Search from SNOMED (RF1) codeset tables + else if ($code_types[$form_code_type]['external'] == 2 ) { // Search from SNOMED (RF1) diagnosis codeset tables if ($active) { // Only filter for active codes // If there is no entry in codes sql table, then default to active // (this is reason for including NULL below) - $active_query=" AND (codes.active = 1 || codes.active IS NULL) "; + $active_query=" AND (c.active = 1 || c.active IS NULL) "; } // Ensure the sct_concepts sql table exists $check_table = sqlQuery("SHOW TABLES LIKE 'sct_concepts'"); if ( !(empty($check_table)) ) { $sql_bind_array = array(); - $query = "SELECT `ConceptId` as code, `FullySpecifiedName` as code_text, " . - "codes.id, codes.code_type, codes.modifier, codes.units, codes.fee, " . - "codes.superbill, codes.related_code, codes.taxrates, codes.cyp_factor, codes.active, codes.reportable, codes.financial_reporting, " . + $query = "SELECT ref.ConceptId as code, ref.FullySpecifiedName as code_text, " . + "c.id, c.code_type, c.modifier, c.units, c.fee, " . + "c.superbill, c.related_code, c.taxrates, c.cyp_factor, c.active, c.reportable, c.financial_reporting, " . "'" . add_escape_custom($form_code_type) . "' as code_type_name " . - "FROM `sct_concepts` " . - "LEFT OUTER JOIN `codes` " . - "ON sct_concepts.ConceptId = codes.code AND codes.code_type = ? "; + "FROM `sct_concepts` as ref " . + "LEFT OUTER JOIN `codes` as c " . + "ON ref.ConceptId = c.code AND c.code_type = ? "; array_push($sql_bind_array,$code_types[$form_code_type]['id']); if ($return_only_one) { - $query .= "WHERE (`ConceptId` = ? AND `FullySpecifiedName` LIKE '%(disorder)') $active_query $query_filter_elements "; + $query .= "WHERE (ref.ConceptId = ? AND ref.FullySpecifiedName LIKE '%(disorder)') $active_query $query_filter_elements "; array_push($sql_bind_array,$search_term); } else { - $query .= "WHERE ((`FullySpecifiedName` LIKE ? OR `ConceptId` LIKE ?) AND `FullySpecifiedName` LIKE '%(disorder)') $active_query $query_filter_elements "; + $query .= "WHERE ((ref.FullySpecifiedName LIKE ? OR ref.ConceptId LIKE ?) AND ref.FullySpecifiedName LIKE '%(disorder)') $active_query $query_filter_elements "; array_push($sql_bind_array,"%".$search_term."%","%".$search_term."%"); } - $query .= "AND `ConceptStatus` = 0 " . - "ORDER BY `ConceptId` $limit_query"; + $query .= "AND ref.ConceptStatus = 0 " . + "ORDER BY ref.ConceptId $limit_query"; $res = sqlStatement($query,$sql_bind_array); } } - else if ($code_types[$form_code_type]['external'] == 3 ) { // Search from SNOMED (RF2) codeset tables + else if ($code_types[$form_code_type]['external'] == 3 ) { // Search from SNOMED (RF2) diagnosis codeset tables //placeholder } - else if ($code_types[$form_code_type]['external'] == 4 ) { // Search from ICD9 codeset tables + else if ($code_types[$form_code_type]['external'] == 4 ) { // Search from ICD9 diagnosis codeset tables if ($active) { // Only filter for active codes // If there is no entry in codes sql table, then default to active // (this is reason for including NULL below) - $active_query=" AND (codes.active = 1 || codes.active IS NULL) "; + $active_query=" AND (c.active = 1 || c.active IS NULL) "; } // Ensure the icd9_dx_code sql table exists $check_table = sqlQuery("SHOW TABLES LIKE 'icd9_dx_code'"); if ( !(empty($check_table)) ) { $sql_bind_array = array(); - $query = "SELECT icd9_dx_code.formatted_dx_code as code, icd9_dx_code.long_desc as code_text, " . - "codes.id, codes.code_type, codes.modifier, codes.units, codes.fee, " . - "codes.superbill, codes.related_code, codes.taxrates, codes.cyp_factor, codes.active, codes.reportable, codes.financial_reporting, " . + $query = "SELECT ref.formatted_dx_code as code, ref.long_desc as code_text, " . + "c.id, c.code_type, c.modifier, c.units, c.fee, " . + "c.superbill, c.related_code, c.taxrates, c.cyp_factor, c.active, c.reportable, c.financial_reporting, " . + "'" . add_escape_custom($form_code_type) . "' as code_type_name " . + "FROM `icd9_dx_code` as ref " . + "LEFT OUTER JOIN `codes` as c " . + "ON ref.formatted_dx_code = c.code AND c.code_type = ? "; + array_push($sql_bind_array,$code_types[$form_code_type]['id']); + if ($return_only_one) { + $query .= "WHERE ref.formatted_dx_code = ? $active_query $query_filter_elements "; + array_push($sql_bind_array,$search_term); + } + else { + $query .= "WHERE (ref.long_desc LIKE ? OR ref.formatted_dx_code LIKE ?) $active_query $query_filter_elements "; + array_push($sql_bind_array,"%".$search_term."%","%".$search_term."%"); + } + $query .= "ORDER BY ref.formatted_dx_code+0, ref.formatted_dx_code $limit_query"; + $res = sqlStatement($query,$sql_bind_array); + } + } + else if ($code_types[$form_code_type]['external'] == 5 ) { // Search from ICD9 Procedure/Service codeset tables + if ($active) { + // Only filter for active codes + // If there is no entry in codes sql table, then default to active + // (this is reason for including NULL below) + $active_query=" AND (c.active = 1 || c.active IS NULL) "; + } + // Ensure the icd9_sg_code sql table exists + $check_table = sqlQuery("SHOW TABLES LIKE 'icd9_sg_code'"); + if ( !(empty($check_table)) ) { + $sql_bind_array = array(); + $query = "SELECT ref.formatted_sg_code as code, ref.long_desc as code_text, " . + "c.id, c.code_type, c.modifier, c.units, c.fee, " . + "c.superbill, c.related_code, c.taxrates, c.cyp_factor, c.active, c.reportable, " . "'" . add_escape_custom($form_code_type) . "' as code_type_name " . - "FROM `icd9_dx_code` " . - "LEFT OUTER JOIN `codes` " . - "ON icd9_dx_code.formatted_dx_code = codes.code AND codes.code_type = ? "; + "FROM `icd9_sg_code` as ref " . + "LEFT OUTER JOIN `codes` as c " . + "ON ref.formatted_sg_code = c.code AND c.code_type = ? "; array_push($sql_bind_array,$code_types[$form_code_type]['id']); if ($return_only_one) { - $query .= "WHERE icd9_dx_code.formatted_dx_code = ? $active_query $query_filter_elements "; + $query .= "WHERE ref.formatted_sg_code = ? $active_query "; array_push($sql_bind_array,$search_term); } else { - $query .= "WHERE (icd9_dx_code.long_desc LIKE ? OR icd9_dx_code.formatted_dx_code LIKE ?) $active_query $query_filter_elements "; + $query .= "WHERE (ref.long_desc LIKE ? OR ref.formatted_sg_code LIKE ?) $active_query "; array_push($sql_bind_array,"%".$search_term."%","%".$search_term."%"); } - $query .= "ORDER BY `formatted_dx_code`+0, `formatted_dx_code` $limit_query"; + $query .= "ORDER BY ref.formatted_sg_code+0, ref.formatted_sg_code $limit_query"; + $res = sqlStatement($query,$sql_bind_array); + } + } + else if ($code_types[$form_code_type]['external'] == 6 ) { // Search from ICD10 Procedure/Service codeset tables + $active_query = ''; + if ($active) { + // Only filter for active codes + // If there is no entry in codes sql table, then default to active + // (this is reason for including NULL below) + $active_query=" AND (c.active = 1 || c.active IS NULL) "; + } + // Ensure the icd10_dx_order_code sql table exists + $check_table = sqlQuery("SHOW TABLES LIKE 'icd10_pcs_order_code'"); + if ( !(empty($check_table)) ) { + $sql_bind_array = array(); + $query = "SELECT ref.pcs_code as code, ref.long_desc as code_text, " . + "c.id, c.code_type, c.modifier, c.units, c.fee, " . + "c.superbill, c.related_code, c.taxrates, c.cyp_factor, c.active, c.reportable, " . + "'" . add_escape_custom($form_code_type) . "' as code_type_name " . + "FROM `icd10_pcs_order_code` as ref " . + "LEFT OUTER JOIN `codes` as c " . + "ON ref.pcs_code = c.code AND c.code_type = ? "; + array_push($sql_bind_array,$code_types[$form_code_type]['id']); + if ($return_only_one) { + $query .= "WHERE ref.pcs_code = ? AND ref.valid_for_coding = '1' $active_query "; + array_push($sql_bind_array,$search_term); + } + else { + $query .= "WHERE (ref.long_desc LIKE ? OR ref.pcs_code LIKE ?) AND ref.valid_for_coding = '1' $active_query "; + array_push($sql_bind_array,"%".$search_term."%","%".$search_term."%"); + } + $query .= "ORDER BY ref.pcs_code+0, ref.pcs_code $limit_query"; $res = sqlStatement($query,$sql_bind_array); } } @@ -314,9 +397,15 @@ function code_set_search($form_code_type,$search_term="",$count=false,$active=tr } } -// Look up descriptions for one or more billing codes. Input is of the -// form "type:code;type:code; etc.". -// +/** + * Lookup Code Descriptions for one or more billing codes. + * + * Function is able to lookup code descriptions from a variety of code sets. See the 'external' + * items in the comments at top of this page for a listing of the code sets supported. + * + * @param string $codes Is of the form "type:code;type:code; etc.". + * @return string Is of the form "description;description; etc.". + */ function lookup_code_descriptions($codes) { global $code_types; $code_text = ''; @@ -343,7 +432,7 @@ function lookup_code_descriptions($codes) { $code_text .= $crow['code_text']; } } - else if ($code_types[$codetype]['external'] == 1) { // Collect from ICD10 codeset tables + else if ($code_types[$codetype]['external'] == 1) { // Collect from ICD10 Diagnosis codeset tables // Ensure the icd10_dx_order_code sql table exists $check_table = sqlQuery("SHOW TABLES LIKE 'icd10_dx_order_code'"); if ( !(empty($check_table)) ) { @@ -358,7 +447,7 @@ function lookup_code_descriptions($codes) { } } } - else if ($code_types[$codetype]['external'] == 2) { // Collect from SNOMED (RF1) codeset tables + else if ($code_types[$codetype]['external'] == 2) { // Collect from SNOMED (RF1) Diagnosis codeset tables // Ensure the sct_concepts sql table exists $check_table = sqlQuery("SHOW TABLES LIKE 'sct_concepts'"); if ( !(empty($check_table)) ) { @@ -373,10 +462,10 @@ function lookup_code_descriptions($codes) { } } } - else if ($code_types[$codetype]['external'] == 3) { // Collect from SNOMED (RF2) codeset tables + else if ($code_types[$codetype]['external'] == 3) { // Collect from SNOMED (RF2) Diagnosis codeset tables //placeholder } - else if ($code_types[$codetype]['external'] == 4) { // Collect from ICD9 codeset tables + else if ($code_types[$codetype]['external'] == 4) { // Collect from ICD9 Diagnosis codeset tables // Ensure the icd9_dx_code sql table exists $check_table = sqlQuery("SHOW TABLES LIKE 'icd9_dx_code'"); if ( !(empty($check_table)) ) { @@ -391,6 +480,37 @@ function lookup_code_descriptions($codes) { } } } + else if ($code_types[$codetype]['external'] == 5) { // Collect from ICD9 Procedure/Service codeset tables + // Ensure the icd9_dx_code sql table exists + $check_table = sqlQuery("SHOW TABLES LIKE 'icd9_sg_code'"); + if ( !(empty($check_table)) ) { + if ( !(empty($code)) ) { + $sql = "SELECT `long_desc` FROM `icd9_sg_code` " . + "WHERE `formatted_sg_code` = ? LIMIT 1"; + $crow = sqlQuery($sql, array($code) ); + if (!empty($crow['long_desc'])) { + if ($code_text) $code_text .= '; '; + $code_text .= $crow['long_desc']; + } + } + } + } + else if ($code_types[$codetype]['external'] == 6) { // Collect from ICD10 PRocedure/Service codeset tables + // Ensure the icd10_dx_order_code sql table exists + $check_table = sqlQuery("SHOW TABLES LIKE 'icd10_pcs_order_code'"); + if ( !(empty($check_table)) ) { + if ( !(empty($code)) ) { + $sql = "SELECT `long_desc` FROM `icd10_dx_order_code` " . + "WHERE `pcs_code` = ? LIMIT 1"; + $crow = sqlQuery($sql, array($code) ); + if (!empty($crow['long_desc'])) { + if ($code_text) $code_text .= '; '; + $code_text .= $crow['long_desc']; + } + } + } + } + else { //using an external code that is not yet supported, so skip. } diff --git a/sql/4_1_0-to-4_1_1_upgrade.sql b/sql/4_1_0-to-4_1_1_upgrade.sql index 6fd22f02cf9..b52a7f4e08e 100644 --- a/sql/4_1_0-to-4_1_1_upgrade.sql +++ b/sql/4_1_0-to-4_1_1_upgrade.sql @@ -411,3 +411,63 @@ ALTER TABLE x12_partners ADD COLUMN x12_isa04 VARCHAR( 10 ) NOT NULL DEFAULT ' ALTER TABLE `codes` ADD COLUMN `financial_reporting` TINYINT(1) DEFAULT 0 COMMENT '0 = negative, 1 = considered important code in financial reporting'; #EndIf +#IfNotColumnType codes code_type smallint(6) +ALTER TABLE `codes` CHANGE `code_type` `code_type` SMALLINT(6) default NULL; +#EndIf + +#IfNotIndex codes code_type +CREATE INDEX `code_type` ON `codes` (`code_type`); +#EndIf + +#IfNotColumnType billing code_type varchar(15) +ALTER TABLE `billing` CHANGE `code_type` `code_type` VARCHAR(15) default NULL; +#EndIf + +#IfNotColumnType codes modifier varchar(12) +ALTER TABLE `codes` CHANGE `modifier` `modifier` VARCHAR(12) NOT NULL default ''; +#EndIf + +#IfNotColumnType ar_activity modifier varchar(12) +ALTER TABLE `ar_activity` CHANGE `modifier` `modifier` VARCHAR(12) NOT NULL default ''; +#EndIf + +#IfNotRow code_types ct_key CPTII +DROP TABLE IF EXISTS `temp_table_one`; +CREATE TABLE `temp_table_one` ( + `id` int(11) NOT NULL DEFAULT '0', + `seq` int(11) NOT NULL DEFAULT '0' +) ENGINE=MyISAM ; +INSERT INTO `temp_table_one` (`id`, `seq`) VALUES ( IF( ((SELECT MAX(`ct_id`) FROM `code_types`)>=100), ((SELECT MAX(`ct_id`) FROM `code_types`) + 1), 100 ) , IF( ((SELECT MAX(`ct_seq`) FROM `code_types`)>=100), ((SELECT MAX(`ct_seq`) FROM `code_types`) + 1), 100 ) ); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('CPTII' , (SELECT MAX(`id`) FROM `temp_table_one`), (SELECT MAX(`seq`) FROM `temp_table_one`), 12, 'ICD9', 1, 0, 0, 0, 0, 'CPTII', 0); +DROP TABLE `temp_table_one`; +#EndIf + +#IfNotRow code_types ct_key ICD9-SG +DROP TABLE IF EXISTS `temp_table_one`; +CREATE TABLE `temp_table_one` ( + `id` int(11) NOT NULL DEFAULT '0', + `seq` int(11) NOT NULL DEFAULT '0' +) ENGINE=MyISAM ; +INSERT INTO `temp_table_one` (`id`, `seq`) VALUES ( IF( ((SELECT MAX(`ct_id`) FROM `code_types`)>=100), ((SELECT MAX(`ct_id`) FROM `code_types`) + 1), 100 ) , IF( ((SELECT MAX(`ct_seq`) FROM `code_types`)>=100), ((SELECT MAX(`ct_seq`) FROM `code_types`) + 1), 100 ) ); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('ICD9-SG' , (SELECT MAX(`id`) FROM `temp_table_one`), (SELECT MAX(`seq`) FROM `temp_table_one`), 12, 'ICD9', 1, 0, 0, 0, 0, 'ICD9 Procedure/Service', 5); +DROP TABLE `temp_table_one`; +#EndIf + +#IfNotRow code_types ct_key ICD10-PCS +DROP TABLE IF EXISTS `temp_table_one`; +CREATE TABLE `temp_table_one` ( + `id` int(11) NOT NULL DEFAULT '0', + `seq` int(11) NOT NULL DEFAULT '0' +) ENGINE=MyISAM ; +INSERT INTO `temp_table_one` (`id`, `seq`) VALUES ( IF( ((SELECT MAX(`ct_id`) FROM `code_types`)>=100), ((SELECT MAX(`ct_id`) FROM `code_types`) + 1), 100 ) , IF( ((SELECT MAX(`ct_seq`) FROM `code_types`)>=100), ((SELECT MAX(`ct_seq`) FROM `code_types`) + 1), 100 ) ); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('ICD10-PCS' , (SELECT MAX(`id`) FROM `temp_table_one`), (SELECT MAX(`seq`) FROM `temp_table_one`), 12, 'ICD10', 1, 0, 0, 0, 0, 'ICD10 Procedure/Service', 6); +DROP TABLE `temp_table_one`; +UPDATE `code_types` SET `ct_label`='ICD9 Diagnosis' WHERE `ct_key`='ICD9'; +UPDATE `code_types` SET `ct_label`='CPT4 Procedure/Service' WHERE `ct_key`='CPT4'; +UPDATE `code_types` SET `ct_label`='HCPCS Procedure/Service' WHERE `ct_key`='HCPCS'; +UPDATE `code_types` SET `ct_label`='CVX Immunization' WHERE `ct_key`='CVX'; +UPDATE `code_types` SET `ct_label`='DSMIV Diagnosis' WHERE `ct_key`='DSMIV'; +UPDATE `code_types` SET `ct_label`='ICD10 Diagnosis' WHERE `ct_key`='ICD10'; +UPDATE `code_types` SET `ct_label`='SNOMED Diagnosis' WHERE `ct_key`='SNOMED'; +#EndIf + diff --git a/sql/database.sql b/sql/database.sql index a1558d8e057..a2769a6d656 100644 --- a/sql/database.sql +++ b/sql/database.sql @@ -112,7 +112,7 @@ DROP TABLE IF EXISTS `billing`; CREATE TABLE `billing` ( `id` int(11) NOT NULL auto_increment, `date` datetime default NULL, - `code_type` varchar(7) default NULL, + `code_type` varchar(15) default NULL, `code` varchar(9) default NULL, `pid` int(11) default NULL, `provider_id` int(11) default NULL, @@ -489,8 +489,8 @@ CREATE TABLE `codes` ( `code_text` varchar(255) NOT NULL default '', `code_text_short` varchar(24) NOT NULL default '', `code` varchar(10) NOT NULL default '', - `code_type` tinyint(2) default NULL, - `modifier` varchar(5) NOT NULL default '', + `code_type` smallint(6) default NULL, + `modifier` varchar(12) NOT NULL default '', `units` tinyint(3) default NULL, `fee` decimal(12,2) default NULL, `superbill` varchar(31) NOT NULL default '', @@ -501,7 +501,8 @@ CREATE TABLE `codes` ( `reportable` TINYINT(1) DEFAULT 0 COMMENT '0 = non-reportable, 1 = reportable', `financial_reporting` TINYINT(1) DEFAULT 0 COMMENT '0 = negative, 1 = considered important code in financial reporting', PRIMARY KEY (`id`), - KEY `code` (`code`) + KEY `code` (`code`), + KEY `code_type` (`code_type`) ) ENGINE=MyISAM AUTO_INCREMENT=1 ; -- -------------------------------------------------------- @@ -5021,7 +5022,7 @@ CREATE TABLE ar_activity ( sequence_no int unsigned NOT NULL AUTO_INCREMENT, `code_type` varchar(12) NOT NULL DEFAULT '', code varchar(9) NOT NULL COMMENT 'empty means claim level', - modifier varchar(5) NOT NULL DEFAULT '', + modifier varchar(12) NOT NULL DEFAULT '', payer_type int NOT NULL COMMENT '0=pt, 1=ins1, 2=ins2, etc', post_time datetime NOT NULL, post_user int(11) NOT NULL COMMENT 'references users.id', @@ -5153,13 +5154,16 @@ CREATE TABLE code_types ( ct_external tinyint(1) NOT NULL default 0 COMMENT '0 if stored codes in codes tables, 1 or greater if codes stored in external tables', PRIMARY KEY (ct_key) ) ENGINE=MyISAM; -INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('ICD9' , 2, 1, 0, '' , 0, 0, 0, 1, 1, 'ICD9', 0); -INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('CPT4' , 1, 2, 12, 'ICD9', 1, 0, 0, 0, 1, 'CPT4', 0); -INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('HCPCS', 3, 3, 12, 'ICD9', 1, 0, 0, 0, 1, 'HCPCS', 0); -INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('CVX' , 100, 100, 0, '', 0, 0, 1, 0, 1, 'CVX', 0); -INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('DSMIV' , 101, 101, 0, '', 0, 0, 0, 1, 0, 'DSMIV', 0); -INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('ICD10' , 102, 102, 0, '', 0, 0, 0, 1, 0, 'ICD10', 1); -INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('SNOMED' , 103, 103, 0, '', 0, 0, 0, 1, 0, 'SNOMED', 2); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('ICD9' , 2, 1, 0, '' , 0, 0, 0, 1, 1, 'ICD9 Diagnosis', 0); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('CPT4' , 1, 2, 12, 'ICD9', 1, 0, 0, 0, 1, 'CPT4 Procedure/Service', 0); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('HCPCS', 3, 3, 12, 'ICD9', 1, 0, 0, 0, 1, 'HCPCS Procedure/Service', 0); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('CVX' , 100, 100, 0, '', 0, 0, 1, 0, 1, 'CVX Immunization', 0); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('DSMIV' , 101, 101, 0, '', 0, 0, 0, 1, 0, 'DSMIV Diagnosis', 0); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('ICD10' , 102, 102, 0, '', 0, 0, 0, 1, 0, 'ICD10 Diagnosis', 1); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('SNOMED' , 103, 103, 0, '', 0, 0, 0, 1, 0, 'SNOMED Diagnosis', 2); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('CPTII' , 104, 104, 12, 'ICD9', 1, 0, 0, 0, 0, 'CPTII', 0); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('ICD9-SG' , 105, 105, 12, 'ICD9', 1, 0, 0, 0, 0, 'ICD9 Procedure/Service', 5); +INSERT INTO code_types (ct_key, ct_id, ct_seq, ct_mod, ct_just, ct_fee, ct_rel, ct_nofs, ct_diag, ct_active, ct_label, ct_external ) VALUES ('ICD10-PCS' , 106, 106, 12, 'ICD10', 1, 0, 0, 0, 0, 'ICD10 Procedure/Service', 6); INSERT INTO list_options ( list_id, option_id, title, seq ) VALUES ('lists', 'code_types', 'Code Types', 1); diff --git a/version.php b/version.php index 235018ffe56..c0fad2d0476 100644 --- a/version.php +++ b/version.php @@ -17,5 +17,5 @@ // is a database change in the course of development. It is used // internally to determine when a database upgrade is needed. // -$v_database = 75; +$v_database = 76; ?>