ez7gen 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/bin/ez7gen +6 -0
  3. data/lib/ez7gen.rb +23 -0
  4. data/lib/ez7gen/config/schema/2.4/2.4.HL7.xml +13904 -0
  5. data/lib/ez7gen/config/schema/2.4/VAZ2.4.HL7.xml +3085 -0
  6. data/lib/ez7gen/config/schema/2.4/added/coded-tables.xml +730 -0
  7. data/lib/ez7gen/config/schema/2.4/rules/2.4.HL7.yml +4 -0
  8. data/lib/ez7gen/config/schema/2.4/rules/VAZ2.4.HL7.yml +6 -0
  9. data/lib/ez7gen/config/schema/2.5/2.5.HL7.xml +10008 -0
  10. data/lib/ez7gen/config/schema/2.5/VAZ2.5.HL7.xml +7 -0
  11. data/lib/ez7gen/config/schema/2.5/added/coded-tables.xml +549 -0
  12. data/lib/ez7gen/config/schema/readme.txt +0 -0
  13. data/lib/ez7gen/config/templates/2.4/eiv table update-mfn_m01 20151201.xml +416 -0
  14. data/lib/ez7gen/config/templates/2.4/eiv table update-mfn_y01.xml +416 -0
  15. data/lib/ez7gen/config/templates/2.4/eiv-ec-MFN_X01_reg request 20160126.xml +659 -0
  16. data/lib/ez7gen/config/templates/2.4/examples/ADT_A60.txt +69 -0
  17. data/lib/ez7gen/config/templates/2.4/examples/eiv table update-mfn_m01 20151201.txt +21 -0
  18. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_dss_units-query_qbp_q13-qbp_q13.txt +26 -0
  19. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_ecs_procedures_query_qbp_q13-qbp_q13.txt +26 -0
  20. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_patient eligibility_response-rsp_k11-080714.txt +44 -0
  21. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_standardhl7lib_diagnosis_query_qbp_q11-qbp_q11.txt +21 -0
  22. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_standardhl7lib_diagnosis_response_rsp_k11-rsp_k11.txt +42 -0
  23. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_standardhl7lib_dss_units_response_rtb_k13-rtb_k13.txt +49 -0
  24. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_standardhl7lib_ecs_filer_request_dft_p03-dft_p03-080714.txt +31 -0
  25. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_standardhl7lib_ecs_filer_response_ack_p03-ack_p03.txt +21 -0
  26. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_standardhl7lib_esc_procedures_response_rtb_k13-rtb_k13.txt +40 -0
  27. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_standardhl7lib_patient_eclass_query_qbp_q11-qbp_q11.txt +21 -0
  28. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_standardhl7lib_patient_problems_query_qbp_q11-qbp_q11.txt +21 -0
  29. data/lib/ez7gen/config/templates/2.4/examples/mhvsm_standardhl7lib_patinet_problems_response_rsp_k11-rsp_k11.txt +33 -0
  30. data/lib/ez7gen/config/templates/2.4/examples/orur01rvbecv2.txt +31 -0
  31. data/lib/ez7gen/config/templates/2.4/examples/sqwm vitals-oru_ro1.txt +52 -0
  32. data/lib/ez7gen/config/templates/2.4/examples/vista sqwm-adt_a60.txt +40 -0
  33. data/lib/ez7gen/config/templates/2.4/mhvsm_dss_units_query_qbp_q13-qbp_q13.xml +312 -0
  34. data/lib/ez7gen/config/templates/2.4/mhvsm_ecs_procedures_query_qbp_q13-qbp_q13.xml +314 -0
  35. data/lib/ez7gen/config/templates/2.4/mhvsm_patient eligibility_response-rsp_k11-080714.xml +640 -0
  36. data/lib/ez7gen/config/templates/2.4/mhvsm_standardhl7lib_diagnosis_query_qbp_q11-qbp_q11.xml +284 -0
  37. data/lib/ez7gen/config/templates/2.4/mhvsm_standardhl7lib_diagnosis_response_rsp_k11-rsp_k11-rsp_k11.xml +563 -0
  38. data/lib/ez7gen/config/templates/2.4/mhvsm_standardhl7lib_dss_units_response_rtb_k13-rtb_k13-rtb_k13.xml +365 -0
  39. data/lib/ez7gen/config/templates/2.4/mhvsm_standardhl7lib_ecs_filer_request_dft_p03-dft_p03-080714.xml +2172 -0
  40. data/lib/ez7gen/config/templates/2.4/mhvsm_standardhl7lib_ecs_filer_response_ack_p03-ack_p03.xml +269 -0
  41. data/lib/ez7gen/config/templates/2.4/mhvsm_standardhl7lib_ecs_procedures_response_rtb_k13-rtb_k13-rtb_k13.xml +354 -0
  42. data/lib/ez7gen/config/templates/2.4/mhvsm_standardhl7lib_patient_eclass_query_qbp_q11-qbp_q11.xml +284 -0
  43. data/lib/ez7gen/config/templates/2.4/mhvsm_standardhl7lib_patient_problems_query_qbp_q11-qbp_q11.xml +282 -0
  44. data/lib/ez7gen/config/templates/2.4/mhvsm_standardhl7lib_patient_problems_response_rsp_k11-rsp_k11-rsp_k11.xml +565 -0
  45. data/lib/ez7gen/config/templates/2.4/orur01rvbecv2.xml +1529 -0
  46. data/lib/ez7gen/config/templates/2.4/sqwm vitals-oru_r01.xml +2975 -0
  47. data/lib/ez7gen/config/templates/2.4/vista sqwm-adt_a60.xml +1360 -0
  48. data/lib/ez7gen/message_factory.rb +142 -0
  49. data/lib/ez7gen/msg_error_handler.rb +33 -0
  50. data/lib/ez7gen/profile_parser.rb +321 -0
  51. data/lib/ez7gen/resources/properties-with-comments.yml +51 -0
  52. data/lib/ez7gen/resources/properties.yml +325 -0
  53. data/lib/ez7gen/service/2.4/dynamic_field_generator.rb +45 -0
  54. data/lib/ez7gen/service/2.4/field_generator.rb +1586 -0
  55. data/lib/ez7gen/service/2.5/field_generator.rb +75 -0
  56. data/lib/ez7gen/service/base_field_generator.rb +451 -0
  57. data/lib/ez7gen/service/segment_generator.rb +218 -0
  58. data/lib/ez7gen/service/segment_picker.rb +147 -0
  59. data/lib/ez7gen/service/template_generator.rb +213 -0
  60. data/lib/ez7gen/service/type_aware_field_generator.rb +1583 -0
  61. data/lib/ez7gen/service/utils.rb +75 -0
  62. data/lib/ez7gen/structure_parser.rb +331 -0
  63. data/lib/ez7gen/version.rb +38 -0
  64. data/test/Additional Tables with values_v1.1.txt +1653 -0
  65. data/test/added_shema_test.rb +143 -0
  66. data/test/app-tmp.rb +225 -0
  67. data/test/at.txt +1 -0
  68. data/test/backburner.zip +0 -0
  69. data/test/codes.txt +262 -0
  70. data/test/codes1.txt +1240 -0
  71. data/test/data_types_exploration_test.rb +213 -0
  72. data/test/dynamic_field_generated_test.rb +292 -0
  73. data/test/message_factory_24_custom_test.rb +648 -0
  74. data/test/message_factory_25_test.rb +50 -0
  75. data/test/message_factory_adm_test.rb +558 -0
  76. data/test/message_factory_gen_test.rb +63 -0
  77. data/test/message_factory_lab_test.rb +107 -0
  78. data/test/message_factory_pharm_test.rb +121 -0
  79. data/test/message_factory_template_24_test.rb +730 -0
  80. data/test/message_factory_test.rb +220 -0
  81. data/test/msg_error_handler_test.rb +59 -0
  82. data/test/profile_parser_test.rb +542 -0
  83. data/test/quick_run.rb +880 -0
  84. data/test/segment_generator_test.rb +656 -0
  85. data/test/segment_picker_test.rb +279 -0
  86. data/test/structrure_parser_test.rb +355 -0
  87. data/test/template_generator_test.rb +164 -0
  88. data/test/type_aware_field_generator_test.rb +582 -0
  89. data/test/utils_test.rb +97 -0
  90. metadata +215 -0
@@ -0,0 +1,142 @@
1
+ require 'ruby-hl7'
2
+ require_relative '../ez7gen/profile_parser'
3
+ require_relative '../ez7gen/structure_parser'
4
+ require_relative '../ez7gen/service/segment_generator'
5
+ require_relative '../ez7gen/service/template_generator'
6
+ require_relative '../ez7gen/service/segment_picker'
7
+ require_relative '../ez7gen/service/utils'
8
+
9
+ class MessageFactory
10
+ include Utils
11
+ attr_accessor :templatePath #TODO: refactor
12
+ # attr_accessor :std; :version; :event; :version_store; :loadFactor;
13
+
14
+ def initialize(args)
15
+ @attributes_hash = args
16
+ args.each do |k,v|
17
+ instance_variable_set("@#{k}", v) unless v.nil?
18
+ end
19
+ @loadFactor ||= nil
20
+ # lookup for a template by name if client speified using a template
21
+ @templatePath = (args[:use_template])? self.class.lookup_template_for_event(@std, @use_template):nil
22
+ # @templatePath = self.class.lookup_template_for_event(@std, @event)
23
+
24
+ end
25
+
26
+ # look up for message template file for an event and standard: 2.4, ADT_A60
27
+ def self.lookup_template_for_event(std, template)
28
+ # properties_file = File.expand_path('../resources/properties.yml', __FILE__)
29
+ # yml = YAML.load_file properties_file
30
+ # path = yml['web.install.dir']
31
+ path = File.expand_path('../', __FILE__)
32
+ path = File.join(path, "config/templates/#{std}/#{template}")
33
+ # path = File.join(path, "config/templates/#{std}/*#{event}*")
34
+ # Dir.glob(path, File::FNM_CASEFOLD).sort.last
35
+
36
+ end
37
+
38
+ # main factory method
39
+ def generate(useExVal=false)
40
+ parsers = {}
41
+ # get message structure from the schema file for message type and version
42
+ parsers[PRIMARY] = ProfileParser.new(@attributes_hash)
43
+
44
+ # check if current version is not the base version, find the base version and add use it as a base parser
45
+ if(!is_base?(@version))# version is not standard != '2.4'
46
+ parsers[BASE]= get_base_parser()
47
+ end
48
+
49
+ #useExVal can be passed from the client - future feature
50
+ return (@templatePath)? generate_message_from_template(parsers, templatePath, useExVal) : generate_message(parsers)
51
+ end
52
+
53
+ # factory method to build message using schema
54
+ def generate_message(parsers)
55
+
56
+ # get message structure from the schema file for message type and version
57
+ # use primary parser
58
+ structure = parsers[PRIMARY].get_message_definition()
59
+
60
+ # brake message structure into segments, handle groups of segments
61
+ structParser = StructureParser.new()
62
+ structParser.process_segments(structure)
63
+
64
+ # select segments to build, keep required and z segments, random pick optional segments
65
+ profile = structure.split('~')
66
+ segment_picker = SegmentPicker.new(profile, structParser.encodedSegments, @loadFactor)
67
+ segments = segment_picker.pick_segments_to_build()
68
+
69
+ # configure a segment generator
70
+ baseVersion = @std
71
+ segmentGenerator = SegmentGenerator.new(baseVersion, @event, parsers)
72
+
73
+ # msh segment configured by hand, due to many requirements that only apply for this segment
74
+ hl7Msg = HL7::Message.new
75
+ hl7Msg << segmentGenerator.init_msh
76
+ # hl7Msg << segmentGenerator.init_msh(is_base?(@version))
77
+
78
+ #iterate over selected segments and build the entire message
79
+ segments.each{ |segment|
80
+ segmentGenerator.generate(hl7Msg, segment, parsers)
81
+ }
82
+
83
+ return hl7Msg
84
+ end
85
+
86
+ # factory method to build message using MWB templates
87
+ def generate_message_from_template(parsers, templatePath, useExVal)
88
+
89
+ hl7Msg = HL7::Message.new
90
+
91
+ templateGenerator = TemplateGenerator.new(templatePath, parsers)
92
+
93
+ return templateGenerator.generate(hl7Msg, useExVal)
94
+
95
+ end
96
+
97
+
98
+ def is_base?(version)
99
+ isBase = @version_store.find { |s| s[:std] == @std }[:profiles].find { |p| p[:doc] == version }[:std]
100
+ end
101
+
102
+ # Add parser for base version of schema
103
+ def get_base_parser()
104
+ # find version for base standard version - standard with 'std' attribute
105
+ v_base = @version_store.find { |s| s[:std] == @std }[:profiles].find { |p| p[:std]!=nil }[:doc]
106
+ v_base_hash = @attributes_hash.clone()
107
+ v_base_hash[:version] = v_base
108
+ ProfileParser.new(v_base_hash)
109
+ end
110
+
111
+ def self.to_arr(hl7Msg)
112
+ arr = []
113
+ hl7Msg.each{|it| arr << it.to_s.gsub("\r","\n")}
114
+ return arr
115
+ end
116
+
117
+ # Identify segment as a part of a group
118
+ def in_group?(groups, idx)
119
+ is_in_group = !groups.select { |group| group.cover?(idx) }.empty?
120
+ # p is_in_group
121
+ end
122
+
123
+ #find ranges of groups before segments collection containing groups can be flattened
124
+ def find_Groups(segments)
125
+ offset = 0
126
+ # groups = segments.map.with_index { |it, idx| (it.instance_of? Array) ? ( groupLn=it.size-1;((offset+idx) .. (idx + offset=offset + groupLn)) ) : nil }.compact
127
+
128
+ groups = segments.map.with_index { |it, idx|
129
+ # groups of sequential segments stored as arrays of segments
130
+ if (it.instance_of? Array)
131
+ # calculate group range based on offset that affected flattening arrays of segments
132
+ groupLen = it.size-1
133
+ groupStart = offset + idx
134
+ groupEnd = idx + offset = offset + groupLen # inline var assignment, just cause I can..
135
+ (groupStart..groupEnd) # group range
136
+ end
137
+ }
138
+ # get rid of nils
139
+ groups.compact()
140
+ end
141
+
142
+ end
@@ -0,0 +1,33 @@
1
+ require 'ruby-hl7'
2
+
3
+ class MsgErrorHandler
4
+
5
+ ERR_HEAD = "ERROR <Ens>ErrGeneral:"
6
+
7
+ def handle(resp)
8
+ # segs = message
9
+ #segs = resp.split("\r")
10
+ resp.chomp!()
11
+
12
+ # msg = HL7::Message.new(segs)
13
+ # msg = HL7::Message.parse(message)
14
+ # seg = msg[:ERR]
15
+ if(! resp.include?(ERR_HEAD))
16
+ return nil
17
+ end
18
+
19
+ # if there are errors, make response easy on the eye
20
+ resp.gsub!("\\X0D\\\\X0A\\", "\r")
21
+ resp.gsub!("\r+\r", "\r")
22
+ resp.gsub!(ERR_HEAD, "\r"+ERR_HEAD)
23
+ resp.gsub!("\r\r","\r") # remove empty lines
24
+
25
+ # get errors for toaster display
26
+ errors = resp.split(ERR_HEAD).reject {|e| e.empty?}
27
+ errors.delete_at(0) # remove part of the message before errors
28
+
29
+ return errors
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,321 @@
1
+ require 'ox'
2
+ require 'yaml'
3
+ require_relative 'service/utils'
4
+
5
+ class ProfileParser
6
+ include Utils
7
+
8
+ #instance attributes
9
+ attr_reader :base,:xml;
10
+ alias_method :base?, :base;
11
+
12
+ # attr_reader :xml;
13
+
14
+ @@FILTER_ALL = {filter: '.*', group: 'All'}
15
+ FILTER_ADM = {filter: 'ADT_A|QBP_Q2|RSP_K2[1-4]', group: 'Admissions'}
16
+ FILTER_FM = {filter: 'DFT_P03|DFT_P11|DFT_X03', group: 'Financial Management'}
17
+ FILTER_GEN = {filter: 'OSR_Q06|OSQ_Q06|ORG_O20|OMG_O19', group: 'General'}
18
+ FILTER_LAB = {filter: 'ORL_O22|OML_O21|QRY_R02|OUL_R21|ORU_R01', group: 'Laboratory'}
19
+ FILTER_MSR = {filter: 'MFN_M01|MFN_X01|MFN_Y01', group: 'Master Files'}
20
+ FILTER_OBS = {filter: 'OMS_O05', group: 'Order'}
21
+ FILTER_PH = {filter: 'OMP_|ORP_|RDE_|RRE_|RDS_|RRD_|RGV_|RRG_|RAS_|RRA_', group: 'Pharmacy'}
22
+
23
+ # attr_accessor :std; :version; :event; :xml; :version_store;
24
+ # @@HL7_VERSIONS = {'2.4'=>'2.4/2.4-schema.xml', 'vaz2.4'=>'vaz2.4/vaz2.4-schema.xml'}
25
+ #class attribute
26
+ # @@segment_patern = /\[([^\[\]]*)\]/
27
+ @@segment_patern = /\[([^\[\]]*)\]|\{([^\[\]]*)\}/
28
+
29
+ # Child class has a wrapper TODO: Refactor
30
+ # def initialize(version=nil, event=nil)
31
+ def initialize(args)
32
+ args.each do |k,v|
33
+ instance_variable_set("@#{k}", v) unless v.nil?
34
+ end
35
+ # set to false if it has not been set already
36
+ # @base ||= false
37
+
38
+ profile, path = nil
39
+ # if(@version_store)
40
+ profile = @version_store.find{|v| v[:std] == @std}[:profiles].find{|p| p[:doc] == @version }[:path]
41
+ path = @version_store.detect{|v| v[:std] == @std}[:path]
42
+ # else
43
+ # # path = self.class.get_schema_location
44
+ # # profile = File.path(path+ @@HL7_VERSIONS[@version])
45
+ # end
46
+
47
+ @xml = Ox.parse(IO.read(profile))
48
+
49
+ # added = File.path(path+'added.xml')
50
+ begin
51
+ added = File.path(path+'/added/coded-tables.xml')
52
+ @added = Ox.parse(IO.read(added))
53
+ rescue => e
54
+ # puts e.message
55
+ $log.error ("#{self.class.to_s}:#{__method__.to_s}") { e.message }
56
+
57
+
58
+ end
59
+
60
+ # set flag if this is base or custom schema
61
+ @base = (@xml.Export.Document.Category.attributes[:std] == '1')
62
+
63
+ end
64
+
65
+ # instance methods
66
+ def self.get_schema_location
67
+ #properties_file = File.expand_path('../resources/properties.yml', __FILE__)
68
+ #yml = YAML.load_file properties_file
69
+ #path = yml['web.install.dir'] # set when run intall gem with argument, example: gem install 'c:/ez7Gen/ez7gen-web/config/resources/'
70
+ path = File.expand_path('../', __FILE__)
71
+ path = File.join(path, 'config/schema/')
72
+ #puts path + ' : self.get_schema_location'
73
+ # path = path<<'config/schema/'
74
+ # path = path<<'config/resources/'
75
+ end
76
+
77
+ def self.lookup_versions
78
+ path = self.get_schema_location
79
+ puts path + " self.lookup_versions"
80
+ names = Dir.glob("#{path}*").select {|f| File.directory? f}
81
+ versions = names.map{|it| { std: it.sub(path,''), path: it}}
82
+ # for each version
83
+ # look get list of .xml files, except added,own directory for added?
84
+ versions.each{|version|
85
+ profiles = []
86
+
87
+ Dir.glob("#{version[:path]}/**").select {|file| !File.directory? file}.each{|path|
88
+ xml = Ox.parse(IO.read(path))
89
+ # for each schema collect metadata
90
+ profile = xml.Export.Document.attributes
91
+ profile[:doc] = profile.delete(:name) # resolve collision with same keys
92
+ profile.merge!(xml.Export.Document.Category.attributes)
93
+ profile[:path] = path
94
+ profiles << profile
95
+ }
96
+ version[:profiles] = profiles
97
+ }
98
+ end
99
+
100
+ def self.getExclusionFilterRule(std, version)
101
+ path = self.get_schema_location
102
+ rules_file = "#{path}#{std}/rules/#{version}.yml"
103
+
104
+ if File.exists? (rules_file)
105
+ yml = YAML.load_file rules_file
106
+ all = []
107
+ all += (yml['exclusion.errors'])?yml['exclusion.errors']:[]
108
+ all += (yml['exclusion.blacklist'])?yml['exclusion.blacklist']:[]
109
+ else
110
+ []
111
+ end
112
+
113
+ end
114
+ def self.getVersionUrlRule(std, version)
115
+ path = self.get_schema_location
116
+ rules_file = "#{path}#{std}/rules/#{version}.yml"
117
+
118
+ if File.exists? (rules_file)
119
+ yml = YAML.load_file rules_file
120
+ (yml['version.url'])?yml['version.url']:nil
121
+ else
122
+ nil
123
+ end
124
+
125
+ end
126
+
127
+ # find message structure by event type
128
+ def get_message_definition
129
+ msg_type = get_message_structure(@event)
130
+ # p msg_type
131
+ $log.info("#{self.class.to_s}:#{__method__.to_s}") { msg_type }
132
+ definition = @xml.Export.Document.Category.locate('MessageStructure').select{|it| it.attributes[:name] == msg_type }.first.attributes[:definition]
133
+ post_process(definition)
134
+ end
135
+
136
+ # helper method to handle corner cases
137
+ def post_process(definition)
138
+
139
+ if(@base && (@event == 'OSR_Q06'))
140
+ # 1.If the OSQ_O06 query is about the status of the general messages OMG_O19 General Clinical Order and OML_O21 Lab Order, which only have the OBR segment, then the OSR_O06 should only have the OBR segment in its Order Detail Segment < >.
141
+ # 2.If the OSQ_O06 query is about the status of the Pharmacy order messages (OMP_O09, RDE_O11) that do not have OBR segment, but have RXO segment, then the OSR_O06 Order Detail Segment < > should only contain RXO.
142
+ # definition.sub!(/<(.*?)>/,['OBR','RXO'].sample())
143
+ # puts definition
144
+ definition = definition.sub!(/<(.*?)>/,['OBR','RXO'].sample())
145
+ # puts definition
146
+ elsif(@base && (@event == 'ORL_O22'))
147
+ # work around for Ensemble issue where repeating group causes error in validation, remove repeating {} tag
148
+ # MSH~MSA~[~ERR~]~[~{~NTE~}~]~[~[~PID~{~[~SAC~[~{~OBX~}~]~]~[~{~ORC~[~OBR~[~{~SAC~}~]~]~}~]~}~]~]
149
+ # 'MSH~MSA~[~ERR~]~[~{~NTE~}~]~[~PID~{~[~SAC~[~{~OBX~}~]~]~[~{~ORC~[~OBR~[~{~SAC~}~]~]~}~]~}~]' #simplified
150
+ # 'MSH~MSA~[~ERR~]~[~{~NTE~}~]~[~PID~[~[~SAC~[~{~OBX~}~]~]~[~{~ORC~[~OBR~[~{~SAC~}~]~]~}~]~]~]' #changed
151
+ definition = 'MSH~MSA~[~ERR~]~[~{~NTE~}~]~[~PID~[~[~SAC~[~{~OBX~}~]~]~[~{~ORC~[~OBR~[~{~SAC~}~]~]~}~]~]~]'
152
+ # definition.sub('[~{~ORC~[~OBR~[~{~SAC~}~]~]~}~]', '[~ORC~[~OBR~[~{~SAC~}~]~]~]')
153
+ else
154
+ definition
155
+ end
156
+ return definition
157
+ end
158
+
159
+ def get_message_structure(event)
160
+ msg_type = @xml.Export.Document.Category.locate('MessageType').select { |it| it.attributes[:name] == event }.first.attributes[:structure]
161
+ end
162
+
163
+
164
+ #get hash of attributes for codeTable values
165
+ def get_code_table(tableName)
166
+ #exclude 361,362 sending/receiving app and facility
167
+ #if(tableName in ['72','88','132','264','269','471','9999']){
168
+ # println tableName
169
+ #}
170
+
171
+ #empty hash if no table name
172
+ return [] if blank?(tableName)
173
+
174
+ attributes = lookup_code_table(tableName, @xml)
175
+
176
+ if(blank?(attributes))||(attributes.size == 1 && attributes[0][:value] =='...')
177
+ attributes = lookup_code_table(tableName, @added)
178
+ end
179
+
180
+ # Per Galina, code table values with special characters. Ensemble validation fails.
181
+ # Filter out codes which have html encoded characters - Ensemble has problem handling it.
182
+ # a bit of awkward logic - if either description or value has html encoded chars, remove the item
183
+ attributes.select!{|a| (has_html_encoded_ch?(a[:description]) || has_html_encoded_ch?(a[:value]))?false:true }
184
+
185
+ return attributes
186
+ end
187
+
188
+ def lookup_code_table(tableName, path)
189
+ tbl = path.Export.Document.Category.locate('CodeTable').select { |it| it.attributes[:name] == tableName }
190
+ (!blank?(tbl)) ? tbl.first.locate('Enumerate').map { |it| it.attributes } : [Utils::DATA_LOOKUP_MIS]
191
+ end
192
+
193
+ def get_segment_structure(segment)
194
+ segmentName = get_segment_name(segment)
195
+ # $log.info (segment)
196
+ $log.info("#{self.class.to_s}:#{__method__.to_s}") { segment }
197
+ # node = export.Document.Category.SegmentStructure.find{ it.@name == segmentName}
198
+ # values = @xml.elements.collect("Export/Document/Category/SegmentStructure[@name ='#{segmentName}']/SegmentSubStructure"){|x| x.attributes}
199
+ @xml.Export.Document.Category.locate('SegmentStructure').select{|it| it.attributes[:name] == segmentName }.first.locate('SegmentSubStructure').map{|it| it.attributes}
200
+ #values.each {|it| puts it}
201
+ end
202
+
203
+ def lookup_message_types(map=nil, exclusion=nil)
204
+ # match everything if no filter defined
205
+ map ||= @@FILTER_ALL
206
+
207
+ filter = map[:filter]
208
+ messageTypeColl = @xml.Export.Document.Category.locate('MessageType').select{|it| it.attributes[:name] =~/#{filter}/}.map!{|it| it.attributes[:name]}
209
+ if(!blank?(exclusion))
210
+ messageTypeColl = messageTypeColl - exclusion
211
+ end
212
+ messages = messageTypeColl.map{ |el|
213
+ event = (el.split('_')).last
214
+ {
215
+ name: el,
216
+ #chek if there is a match otherwise use the segment name
217
+ code: ((e = @xml.Export.Document.Category.locate('MessageEvent').select{|it| it.attributes[:name] == event}); e!=[] )? (e.first().attributes[:description]): el,
218
+ group: map[:group]
219
+ }
220
+ }
221
+ return messages
222
+ end
223
+
224
+ def lookup_events(params)
225
+
226
+ #all events for version
227
+ events = @xml.Export.Document.Category.locate('MessageType').map!{|it| it.attributes[:name]}
228
+
229
+ #if there are exclusion rule, remove the exclusions
230
+ if(!blank?(params[:exclusions]))
231
+ events -= params[:exclusions]
232
+ end
233
+
234
+ path = params[:templates_path]
235
+
236
+ templates = (!blank?(path))? get_templates(path) : []
237
+
238
+ # go over the events and build attributes of the array
239
+ events_with_attr = events.map{ |el|
240
+ build_event_attributes(el, templates, path)
241
+ }
242
+
243
+ #events_with_attr
244
+ end
245
+
246
+ # build all the details for event type including template information
247
+ def build_event_attributes(event, templates, path)
248
+
249
+ attr = {}
250
+ attr[:name] = event
251
+ #chek if there is a match otherwise use the segment name
252
+ attr[:code] = get_message_event_desc(event)
253
+
254
+ # check if this event has matching template files
255
+ # event_templates = templates.collect { |template| template =~/#{event}/ } unless blank?(templates)
256
+ # attr[:templates] = templates unless blank?(event_templates)
257
+ if (!blank?(templates))
258
+ # try to match templates to an event by name
259
+ event_templates = templates.select { |template| template =~/#{event}/i }
260
+ # if found set event attribute with template names
261
+ if(!blank?(event_templates))
262
+
263
+ # attr[:templates] = []
264
+ #update event code with template count
265
+ #code = "<b> +#{event_templates.size}" << (event_templates.size == 1) ? "TEMPLATE" : "TEMPLATES" << "</b>"
266
+ # attr[:code] += "<div><b><font color=#337ab7>#{event_templates.size} #{(event_templates.size == 1) ? 'TEMPLATE' : 'TEMPLATES'}</font></b></div>"
267
+ attr[:code] += "<small><b><font color=#337ab7> (#{event_templates.size}#{(event_templates.size == 1) ? 'TEMPLATE' : 'TEMPLATES'})</font></b></small>"
268
+ # if (event_templates.size == 1) then code.chop! end
269
+ # attr[:code] += "#{code}"
270
+
271
+ # if (event_templates.size == 1) then attr[:code].chop! end
272
+
273
+ attr[:templates] = event_templates.collect{ |tmpl|
274
+ desc = Ox.parse(IO.read("#{path}/#{tmpl}")).HL7v2xConformanceProfile.HL7v2xStaticDef.attributes[:EventDesc]
275
+ # desc = (!blank?(desc)) ? desc : "Custom #{event}"
276
+ desc = (!blank?(desc)) ? desc : tmpl.gsub('_',' ').sub('.xml','')
277
+ {:desc => desc.upcase , :file => tmpl}
278
+ }
279
+ end
280
+
281
+ end
282
+
283
+
284
+ return attr
285
+ end
286
+
287
+ # # look up for message template files in a specified directory
288
+ def get_templates(path)
289
+ begin
290
+ Dir.entries(path).select {|f| f =~/.xml/i}.sort
291
+ # rescue => e
292
+ rescue
293
+ [] # handle case when dir is missing
294
+ end
295
+ end
296
+
297
+ #look up for event description
298
+ def get_message_event_desc(event)
299
+ desc = nil
300
+ tbl = @xml.Export.Document.Category.locate('CodeTable').select { |it| (it.attributes[:description] == 'Event type') }
301
+
302
+ if(!blank?(tbl))
303
+ # get event/message name ex: NO2 for ACK_NO2
304
+ event_name = (event.split('_')).last
305
+ for t in tbl # could be multiple tables, iterate
306
+ desc = (( e = t.locate('Enumerate').select{ |it| it.attributes[:value] == event_name }); e!=[])? (e.first().attributes[:description]) : nil
307
+ if(desc)then break end # brake after first match
308
+ end # for
309
+ end # if
310
+
311
+ return desc || event
312
+ end
313
+
314
+ # helper method to look up messages for specific groups of messages
315
+ def lookup_message_groups (groups)
316
+ messages = []
317
+ groups.each{ |group| messages += lookup_message_types(group) }
318
+ return messages
319
+ end
320
+
321
+ end