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,51 @@
1
+ #web.install.dir: "/Users/romansova/RubymineProjects/ez7gen-staged/"
2
+ #web.install.dir: C:/Web-Ez7Gen/ez7gen-web
3
+ person.names.first: [Odysseus,Xander,Jameson,Brian,Yoshio,Connor,Kasper,Macon,Mannix,Cyrus,Jeremy,Channing,Raja,Daniel,Roth,Ezekiel,Martin,Cameron,Elmo,Omar,Holmes,Ulric,Nissim,Colton,Herman,Luke,Thaddeus,Leroy,Baxter,Tanner,Caleb,Salvador,Adrian,Reuben,Ronan,Burton,Kermit,Kareem,Tobias,Cedric,Flynn,Uriel,Barry,Amal,Orson,Arsenio,Vladimir,Thane,Nissim,Alden,Stewart,Plato,Prescott,Xenos,David,Castor,Carson,Brian,Jarrod,Stuart,Herman,Tobias,Lucius,Fitzgerald,Malachi,Theodore,Eaton,Arsenio,Gannon,Burton,Zahir,Caleb,Preston,Ivor,Martin,Aidan,Octavius,Ali,Aristotle,Ivor,Chadwick,Hilel,Octavius,Victor,Noah,Leo,Cameron,Ross,Lionel,Howard,Armand,Solomon,Darius,Edan,Tad,Forrest,Allen,Macon,Kasimir,Brian]
4
+ person.names.last: [Daugherty,Small,Webster,Reilly,Key,Velazquez,Holder,Larson,Watkins,Holden,Davenport,Kirkland,Decker,Pate,Shepherd,Love,Robles,Strong,Mitchell,Burgess,Hewitt,Rush,Watkins,Merritt,Howell,Munoz,Zimmerman,Hammond,Hickman,Wilkinson,Lane,Koch,Hoover,Stevens,Stephens,Woodward,Blanchard,Vinson,Rodriquez,Oneal,Blake,Pennington,Pittman,Mills,Byers,Gilliam,Browning,Thompson,Patrick,Potts,Zimmerman,Larson,Bullock,Rocha,Prince,Kaufman,Obrien,Bauer,Calderon,Vance,Castillo,Flores,Ford,Mcgee,Leon,Mckee,Carver,Hardy,Mcmillan,Strong,Franks,Cooke,Boyer,Meyer,Gates,Madden,William,Riggs,Walker,Rosa,Simmons,Dunlap,Acosta,Espinoza,Beasley,Ramirez,Farrell,Ratliff,Caldwell,Harper,Wiley,Mendoza,Cain,Blankenship,Buck,Marquez,Stevenson,Gates,Carpenter,Fletcher]
5
+ dmgr.gender: [M,F]
6
+ address.streetNames: [504 Honey Elk Wynd,7608 Silent Glen,7741 Foggy Pond Jetty,7061 Iron Blossom Ridge,5777 Fallen Panda Expressway]
7
+ address.cities: [Oatmeal,Owl,Dollar Settlement,Saint-Quentin,Ragtown]
8
+ address.states: [TN,MS,TN,MS,GA]
9
+ address.states.all: [AL,AK,AZ,AR,CA,CO,CT,DE,FL,GA,HI,ID,IL,IN,IA,KS,KY,LA,ME,MD,MA,MI,MN,MS,MO,MT,NE,NV,NH,NJ,NM,NY,NC,ND,OH,OK,OR,PA,RI,SC,SD,TN,TX,UT,VT,VA,WA,WV,WI,WY]
10
+ address.zips: [37166-9572,38889-6760,37326-6978,39377-7406,39833-8563]
11
+ address.countries: [USA,USA,USA,USA,USA]
12
+ address.phones: [(931)872-7634,(601)110-8688,(731)538-7434,(662)120-6474,(470)446-7282]
13
+
14
+
15
+ #job Titles []Accountant, Application Developer, Attorney, Engineer, Dentist,Nurse Practitioner, Paramedic, Pharmacist, Physician] CT1.49 Job Title
16
+ #Person Class Codes 193200000X Multi-specialty,193400000X Single specialty,208D00000X General practice,207R00000X Internal medicine,208600000X Surgery #ROL.9 Provider Type (both the code and the description need to be populated)
17
+
18
+ #ICD 10 Observation Codes
19
+ #R71.8 Other abnormality of red blood cells,
20
+ #R82.8 Abnormal findings on cytological and histological examination of urine,
21
+ #R81 Glycosuria,
22
+ #R82.99 Other abnormal findings in urine,
23
+ #R79.0 Abnormal level of blood mineral,
24
+ #R03.1 Nonspecific low blood-pressure reading,
25
+ #R78.79 Finding of abnormal level of heavy metals in blood
26
+
27
+
28
+ #OBX.3 Observation Identifier (both the code and the description need to be populated)
29
+ #ICD 10 Allergen Codes
30
+ codes.allergens.icd10:
31
+ T78.40XA: Allergy unspecified initial encounter
32
+ T78.40XD: Allergy unspecified subsequent encounter
33
+ Z91.048: Other nonmedicinal substance allergy status
34
+ Z91.09: Other allergy status, other than to drugs and biological substances
35
+ Z91.013: Allergy to seafood
36
+ Z91.010: Allergy to peanuts
37
+ Z88.0: Allergy status to penicillin
38
+ Z91.038: Other insect allergy status
39
+ Z91.030: Bee Allergy status
40
+
41
+ #AL1.3 Allergen Code/Mnemonic/ Description (both the code and the description need to be populated)
42
+ codes.allergens:
43
+ #ICD 10: Allergy Reaction Codes
44
+ L50.0: Hives
45
+ R11.2: Nausea with vomiting
46
+ R68.2: Dry mouth
47
+ K52.2: Diarrhea
48
+ J30.9: Itching
49
+ #AL1.5 Allergy Reaction Code #(just the code)
50
+ allergens.yn: [Y,N]
51
+
@@ -0,0 +1,325 @@
1
+ ---
2
+ web.install.dir: "../resources"
3
+ logger.level: 2
4
+ logger.comments: "DEBUG = 0; INFO = 1; WARN = 2; ERROR = 3; FATAL = 4; UNKNOWN = 5"
5
+ person.names.first:
6
+ - Odysseus
7
+ - Xander
8
+ - Jameson
9
+ - Brian
10
+ - Yoshio
11
+ - Connor
12
+ - Kasper
13
+ - Macon
14
+ - Mannix
15
+ - Cyrus
16
+ - Jeremy
17
+ - Channing
18
+ - Raja
19
+ - Daniel
20
+ - Roth
21
+ - Ezekiel
22
+ - Martin
23
+ - Cameron
24
+ - Elmo
25
+ - Omar
26
+ - Holmes
27
+ - Ulric
28
+ - Nissim
29
+ - Colton
30
+ - Herman
31
+ - Luke
32
+ - Thaddeus
33
+ - Leroy
34
+ - Baxter
35
+ - Tanner
36
+ - Caleb
37
+ - Salvador
38
+ - Adrian
39
+ - Reuben
40
+ - Ronan
41
+ - Burton
42
+ - Kermit
43
+ - Kareem
44
+ - Tobias
45
+ - Cedric
46
+ - Flynn
47
+ - Uriel
48
+ - Barry
49
+ - Amal
50
+ - Orson
51
+ - Arsenio
52
+ - Vladimir
53
+ - Thane
54
+ - Nissim
55
+ - Alden
56
+ - Stewart
57
+ - Plato
58
+ - Prescott
59
+ - Xenos
60
+ - David
61
+ - Castor
62
+ - Carson
63
+ - Brian
64
+ - Jarrod
65
+ - Stuart
66
+ - Herman
67
+ - Tobias
68
+ - Lucius
69
+ - Fitzgerald
70
+ - Malachi
71
+ - Theodore
72
+ - Eaton
73
+ - Arsenio
74
+ - Gannon
75
+ - Burton
76
+ - Zahir
77
+ - Caleb
78
+ - Preston
79
+ - Ivor
80
+ - Martin
81
+ - Aidan
82
+ - Octavius
83
+ - Ali
84
+ - Aristotle
85
+ - Ivor
86
+ - Chadwick
87
+ - Hilel
88
+ - Octavius
89
+ - Victor
90
+ - Noah
91
+ - Leo
92
+ - Cameron
93
+ - Ross
94
+ - Lionel
95
+ - Howard
96
+ - Armand
97
+ - Solomon
98
+ - Darius
99
+ - Edan
100
+ - Tad
101
+ - Forrest
102
+ - Allen
103
+ - Macon
104
+ - Kasimir
105
+ - Brian
106
+ person.names.last:
107
+ - Daugherty
108
+ - Small
109
+ - Webster
110
+ - Reilly
111
+ - Key
112
+ - Velazquez
113
+ - Holder
114
+ - Larson
115
+ - Watkins
116
+ - Holden
117
+ - Davenport
118
+ - Kirkland
119
+ - Decker
120
+ - Pate
121
+ - Shepherd
122
+ - Love
123
+ - Robles
124
+ - Strong
125
+ - Mitchell
126
+ - Burgess
127
+ - Hewitt
128
+ - Rush
129
+ - Watkins
130
+ - Merritt
131
+ - Howell
132
+ - Munoz
133
+ - Zimmerman
134
+ - Hammond
135
+ - Hickman
136
+ - Wilkinson
137
+ - Lane
138
+ - Koch
139
+ - Hoover
140
+ - Stevens
141
+ - Stephens
142
+ - Woodward
143
+ - Blanchard
144
+ - Vinson
145
+ - Rodriquez
146
+ - Oneal
147
+ - Blake
148
+ - Pennington
149
+ - Pittman
150
+ - Mills
151
+ - Byers
152
+ - Gilliam
153
+ - Browning
154
+ - Thompson
155
+ - Patrick
156
+ - Potts
157
+ - Zimmerman
158
+ - Larson
159
+ - Bullock
160
+ - Rocha
161
+ - Prince
162
+ - Kaufman
163
+ - Obrien
164
+ - Bauer
165
+ - Calderon
166
+ - Vance
167
+ - Castillo
168
+ - Flores
169
+ - Ford
170
+ - Mcgee
171
+ - Leon
172
+ - Mckee
173
+ - Carver
174
+ - Hardy
175
+ - Mcmillan
176
+ - Strong
177
+ - Franks
178
+ - Cooke
179
+ - Boyer
180
+ - Meyer
181
+ - Gates
182
+ - Madden
183
+ - William
184
+ - Riggs
185
+ - Walker
186
+ - Rosa
187
+ - Simmons
188
+ - Dunlap
189
+ - Acosta
190
+ - Espinoza
191
+ - Beasley
192
+ - Ramirez
193
+ - Farrell
194
+ - Ratliff
195
+ - Caldwell
196
+ - Harper
197
+ - Wiley
198
+ - Mendoza
199
+ - Cain
200
+ - Blankenship
201
+ - Buck
202
+ - Marquez
203
+ - Stevenson
204
+ - Gates
205
+ - Carpenter
206
+ - Fletcher
207
+ person.suffix:
208
+ - JR
209
+ - SR
210
+ - RET
211
+ - ESQ
212
+ person.prefix:
213
+ - DR
214
+ - PROF
215
+ - HON
216
+ - ATTY
217
+ dmgr.gender:
218
+ - M
219
+ - F
220
+ address.streetNames:
221
+ - 504 Honey Elk Wynd
222
+ - 7608 Silent Glen
223
+ - 7741 Foggy Pond Jetty
224
+ - 7061 Iron Blossom Ridge
225
+ - 5777 Fallen Panda Expressway
226
+ address.cities:
227
+ - Oatmeal
228
+ - Owl
229
+ - Dollar Settlement
230
+ - Saint-Quentin
231
+ - Ragtown
232
+ address.states:
233
+ - TN
234
+ - MS
235
+ - TN
236
+ - MS
237
+ - GA
238
+ address.states.all:
239
+ - AL
240
+ - AK
241
+ - AZ
242
+ - AR
243
+ - CA
244
+ - CO
245
+ - CT
246
+ - DE
247
+ - FL
248
+ - GA
249
+ - HI
250
+ - ID
251
+ - IL
252
+ - IN
253
+ - IA
254
+ - KS
255
+ - KY
256
+ - LA
257
+ - ME
258
+ - MD
259
+ - MA
260
+ - MI
261
+ - MN
262
+ - MS
263
+ - MO
264
+ - MT
265
+ - NE
266
+ - NV
267
+ - NH
268
+ - NJ
269
+ - NM
270
+ - NY
271
+ - NC
272
+ - ND
273
+ - OH
274
+ - OK
275
+ - OR
276
+ - PA
277
+ - RI
278
+ - SC
279
+ - SD
280
+ - TN
281
+ - TX
282
+ - UT
283
+ - VT
284
+ - VA
285
+ - WA
286
+ - WV
287
+ - WI
288
+ - WY
289
+ address.zips:
290
+ - 37166-9572
291
+ - 38889-6760
292
+ - 37326-6978
293
+ - 39377-7406
294
+ - 39833-8563
295
+ address.countries:
296
+ - USA
297
+ - USA
298
+ - USA
299
+ - USA
300
+ - USA
301
+ address.phones:
302
+ - "(931)872-7634"
303
+ - "(601)110-8688"
304
+ - "(731)538-7434"
305
+ - "(662)120-6474"
306
+ - "(470)446-7282"
307
+ codes.allergens.icd10:
308
+ T78.40XA: Allergy unspecified initial encounter
309
+ T78.40XD: Allergy unspecified subsequent encounter
310
+ Z91.048: Other nonmedicinal substance allergy status
311
+ Z91.09: Other allergy status, other than to drugs and biological substances
312
+ Z91.013: Allergy to seafood
313
+ Z91.010: Allergy to peanuts
314
+ Z88.0: Allergy status to penicillin
315
+ Z91.038: Other insect allergy status
316
+ Z91.030: Bee Allergy status
317
+ codes.allergens:
318
+ L50.0: Hives
319
+ R11.2: Nausea with vomiting
320
+ R68.2: Dry mouth
321
+ K52.2: Diarrhea
322
+ J30.9: Itching
323
+ allergens.yn:
324
+ - Y
325
+ - N
@@ -0,0 +1,45 @@
1
+ require 'yaml'
2
+ require_relative '../../profile_parser'
3
+ require_relative '../base_field_generator'
4
+
5
+ class DynamicFieldGenerator < BaseFieldGenerator
6
+ include Utils
7
+
8
+ # constructor
9
+ def initialize(pp)
10
+ super pp
11
+ end
12
+
13
+ # base data types ["DT", "FT", "ID", "IS", "NM", "SI", "ST", "TM", "TN", "TX"]
14
+
15
+ def dynamic(name, map, force=false)
16
+ #check if the field is optional and randomly generate it of skip
17
+ return '' if(!generate?(map, force))
18
+ sub_types = []
19
+ value = []
20
+
21
+ @pp.xml.Export.Document.Category.locate('DataType').select{|it| it.attributes[:name] == name}.first.locate('DataSubType').each{ |it| sub_types << it.attributes}
22
+
23
+ sub_types.each{ |sub_type|
24
+ # check if field is required
25
+ begin
26
+ value << method(sub_type[:datatype]).call(sub_type,true)
27
+ rescue NameError => e
28
+ # puts e
29
+ $log.error("#{self.class.to_s}:#{__method__.to_s}") { e.message }
30
+ sub_values = dynamic(sub_type[:datatype], sub_type, true)
31
+
32
+ # TODO :remove trailing empty fields
33
+ # TODO: handle fields and subfields if it deeper then 3 levels in DR : "761&663^753&799"
34
+ value << sub_values.gsub(@@HAT,@@SUB)
35
+ puts sub_values
36
+ end
37
+ }
38
+
39
+ return value.join(@@HAT)
40
+ end
41
+
42
+ #
43
+
44
+
45
+ end
@@ -0,0 +1,1586 @@
1
+ require 'yaml'
2
+ require_relative '../../profile_parser'
3
+
4
+ class FieldGenerator
5
+ # class TypeAwareFieldGenerator
6
+ include Utils
7
+
8
+ attr_accessor :yml,:pp
9
+ # @@UP_TO_3_DGTS = 1000 # up to 3 digits
10
+ @@REQ_LEN_3_DGTS = 3 #up to 3 digits
11
+ @@RANGE_INDICATOR = '...'
12
+ @@HAT = '^' # Component separator, aka hat
13
+ @@SUB ='&' # Subcomponent separator
14
+ # @@MONEY_FORMAT_INDICATORS = ['Money', 'Balance', 'Charge', 'Adjustment', 'Income', 'Amount', 'Payment','Cost']
15
+ # @@MONEY_FORMAT_REGEX = /\bMoney\b|\bBalance\b|\bCharge|\bAdjustment\b|\bIncome\b|\bAmount\b|\bPayment\b|\bCost\b|\bPercentage\b/
16
+ @@MONEY_FORMAT_REGEX = /\bMoney\b|\bBalance\b|\bCharge|\bAdjustment\b|\bIncome\b|\bAmount\b|\bPayment\b|\bCost\b/
17
+ @@PERCENT_FORMAT_REGEX = /\bPercentage\b|%/
18
+ @@INITIALS = ('A'..'Z').to_a
19
+ @@GENERAL_TEXT = 'Notes'
20
+
21
+ @@random = Random.new
22
+
23
+ # constructor
24
+ def initialize(parser, helper_parser=nil)
25
+ @pp = parser
26
+ # Coded table value lookup profiler. Only set for custom schemas.
27
+ # Custom schema has types which coming from the base schema but using coded tables from primary schema.
28
+ # Also primary schemas use base type coded tables.
29
+ @hp = helper_parser
30
+
31
+ # dirname = File.join(File.dirname(File.expand_path(__FILE__)),'../../resources/properties.yml')
32
+ propertiesFile = File.expand_path('../../../resources/properties.yml', __FILE__)
33
+ @yml = YAML.load_file propertiesFile
34
+ end
35
+
36
+ # This method common for all field generators
37
+ def dt (dt, attrs)
38
+ self.method(dt).call(attrs)
39
+ end
40
+
41
+ #Generate HL7 AD (address) data type.
42
+ def AD(map, force=false)
43
+ #check if the field is optional and randomly generate it of skip
44
+ return '' if(!generate?(map, force))
45
+
46
+ # match cities, states and zips
47
+ sample = @yml['address.states'].sample
48
+ idx = @yml['address.states'].index(sample) #index of random element
49
+
50
+ val=[]
51
+ #street address (ST) (ST)
52
+ val << @yml['address.streetNames'].sample
53
+ #other designation (ST)
54
+ val <<''
55
+ #city (ST)
56
+ val << @yml['address.cities'].at(idx)
57
+ #state or province (ST)
58
+ val << @yml['address.states'].at(idx)
59
+ #zip or postal code (ST)
60
+ val << @yml['address.zips'].at(idx)
61
+ #country (ID)
62
+ val << @yml['address.countries'].at(idx)
63
+ # address type (ID)
64
+ # ot5 her geographic designation (ST)
65
+
66
+ val.join(@@HAT)
67
+ end
68
+
69
+ # Authorization information
70
+ def AUI(map, force=false)
71
+ #check if the field is optional and randomly generate it of skip
72
+ return '' if(!generate?(map, force))
73
+
74
+ # authorization number (ST)
75
+ ST(map, true)
76
+ # date (DT)
77
+ # source (ST)
78
+ end
79
+
80
+ #Charge time
81
+ def CCD(map, force=false)
82
+ #check if the field is optional and randomly generate it of skip
83
+ return '' if(!generate?(map, force))
84
+
85
+ #<when to charge code (ID)>
86
+ ID(map, force=false)
87
+ # <date/time (TS)>
88
+ end
89
+
90
+ #Channel calibration parameters
91
+ def CCP(map, force=false)
92
+ #check if the field is optional and randomly generate it of skip
93
+ return '' if(!generate?(map, force))
94
+
95
+ # <channel calibration sensitivity correction (NM)>
96
+ NM(map,true)
97
+ # <channel calibration baseline (NM)>
98
+ # <channel calibration time skew (NM)>
99
+ end
100
+
101
+ # Channel definition
102
+ def CD(map, force=false)
103
+ # check if the field is optional and randomly generate it of skip
104
+ return '' if(!generate?(map, force))
105
+
106
+ #<channel identifier (WVI)>
107
+ WVI(map, force=true)
108
+ #<waveform source (WVS)>
109
+ # <channel sensitivity/units (SCU)>
110
+ #<channel calibration parameters (CCP)>
111
+ # <sampling frequency (NM)>
112
+ # <minimum/maximum data values (NR)>
113
+ end
114
+
115
+ # Generate HL7 CE (coded element) data type
116
+ def CE(map, force=false)
117
+ #check if the field is optional and randomly generate it of skip
118
+ return '' if(!generate?(map, force))
119
+
120
+ if(map[:max_length] && map[:max_length].to_i <3)
121
+ # if CE Element has lenght of 2 or less use only value
122
+ return ID(map, true)
123
+ end
124
+
125
+ #TODO: Refactor this method
126
+ if (map[:description] == 'Role Action Reason' || map[:description] == 'Species Code' || map[:description] == 'Breed Code' || map[:description] == 'Production Class Code')
127
+ return '' #Per requirement, PID.35 – PID.38
128
+ end
129
+
130
+ val = []
131
+ # CE ce = (CE) map?.fld
132
+ codes = get_coded_map(map)
133
+ if(blank?(codes))
134
+ case map[:description]
135
+ when 'Allergen Code/Mnemonic/Description'
136
+ pair = yml['codes.allergens.icd10'].to_a.sample(1).to_h.first # randomly pick a pair
137
+ val<<pair.first
138
+ val<<pair.last
139
+
140
+ else
141
+ # TODO: only for elements that don't have look up table set the id randomly
142
+ # if codetable is empty
143
+ val << ((blank?(map[:codetable])) ? ID(map, true) : '')
144
+ end
145
+ else
146
+ #identifier (ST) (ST)
147
+ val<<codes[:value]
148
+ #text (ST)
149
+ val<<codes[:description]
150
+ #name of coding system (IS)
151
+ #alternate identifier (ST) (ST)
152
+ #alternate text (ST)
153
+ #name of alternate coding system (IS)
154
+ end
155
+ return val.join(@@HAT)
156
+ end
157
+
158
+ # Coded element with formatted values
159
+ def CF(map, force=false)
160
+ #check if the field is optional and randomly generate it of skip
161
+ return '' if(!generate?(map, force))
162
+
163
+ # <identifier (ID)>
164
+ ID(map, true)
165
+ # <formatted text (FT)>
166
+ # <name of coding system (IS)>
167
+ # <alternate identifier (ID)>
168
+ # <alternate formatted text (FT)>
169
+ # <name of alternate coding system (IS)>
170
+ end
171
+
172
+ #Composite ID with check digit
173
+ def CK(map, force=false)
174
+ #check if the field is optional and randomly generate it of skip
175
+ return '' if(!generate?(map, force))
176
+ # <ID number (NM)>
177
+ NM(map,true)
178
+ # <check digit (NM)>
179
+ # <code identifying the check digit scheme employed (ID)>
180
+ # < assigning authority (HD)>
181
+ end
182
+
183
+ #Composite
184
+ def CM(map, force=false)
185
+ #check if the field is optional and randomly generate it of skip
186
+ return '' if(!generate?(map, force))
187
+
188
+ val=[]
189
+ # <penalty type (IS)>
190
+ val=IS(map,true)
191
+ # <penalty amount (NM)>
192
+ val<<NM({},true)
193
+ val.join(@@HAT)
194
+ end
195
+
196
+ # CN Composite ID number and name
197
+ # "<ID number (ST)> ^ <family name (FN)> ^ <given name (ST)> ^ < second and further given names or initials thereof (ST)> ^ <suffix (e.g., JR or III) (ST)> ^ <prefix (e.g. DR) (ST)> ^ <degree (e.g., MD) (IS)> ^ <source table (IS)> ^ <assigning authority(HD)>
198
+ # Replaced by XCN data type as of v 2.3"
199
+
200
+ # CNE Coded with no exceptions
201
+ def CNE(map, force=false)
202
+ #check if the field is optional and randomly generate it of skip
203
+ return '' if(!generate?(map, force))
204
+
205
+ # <identifier (ST)> ^ <text (ST)>
206
+ ST(map, true)
207
+ # <name of coding system (IS)>
208
+ # <alternate identifier(ST)>
209
+ # <alternate text (ST)>
210
+ # <name of alternate coding system (IS)>
211
+ # <coding system version ID (ST)>
212
+ # alternate coding system version ID (ST)>
213
+ # <original text (ST)>
214
+ end
215
+
216
+ # Composite ID number and name (special DT for NDL)
217
+ def CNN(map, force=false)
218
+ #check if the field is optional and randomly generate it of skip
219
+ return '' if(!generate?(map, force))
220
+
221
+ # ID number (ST) (ST)
222
+
223
+ # val << ID(map, true)
224
+ # family name (FN), used for ST
225
+ # val << FN(map, true)
226
+ # given name (ST)
227
+ # val << @yml['person.names.first'].sample
228
+ # second and further given names or initials thereof (ST)
229
+ # val << @@INITIALS.to_a.sample
230
+ # < suffix (e.g., JR or III) (ST)> ^ < prefix (e.g., DR) (ST)>
231
+ # < degree (e.g., MD) (IS)> ^ < source table (IS)>
232
+ PN(map, true)
233
+
234
+ # < assigning authority namespace ID (IS)>
235
+ # < assigning authority universal ID (ST)>
236
+ # < assigning authority universal ID type (ID)>
237
+ # val.join(@@SUB)
238
+ end
239
+
240
+ def CP(map, force=false)
241
+ #check if the field is optional and randomly generate it of skip
242
+ return '' if(!generate?(map, force))
243
+
244
+ #price (MO)
245
+ MO(map,true)
246
+ #price type (ID)
247
+ #from value (NM)
248
+ #to value (NM)
249
+ #range units (CE)
250
+ #range type (ID)
251
+ end
252
+
253
+ # Composite quantity with units
254
+ def CQ(map, force=false)
255
+ #check if the field is optional and randomly generate it of skip
256
+ return '' if(!generate?(map, force))
257
+ # val =[]
258
+ # <quantity (NM)>
259
+ NM({},true)
260
+
261
+ # val<<NM({},true)
262
+ # <units (CE)>
263
+ # val<<CE(map,true) # Per request with QBP_Q21 issue
264
+ # CE always get values from code table 335, schema does not always specify it.
265
+ # only ID part from CE is used for this data type
266
+ # val<<ID(reset_map_attr(map, :codetable, '335'), true)
267
+ # val<<ID(map,true)
268
+ # val.join(@@HAT)
269
+ # val.join(@@SUB)
270
+ end
271
+
272
+ #Channel sensitivity/units
273
+ def CSU(map, force=false)
274
+ #check if the field is optional and randomly generate it of skip
275
+ return '' if(!generate?(map, force))
276
+
277
+ # < channel sensitivity (NM)>
278
+ NM(map,true)
279
+ # < unit of measure identifier (ST)>
280
+ # < unit of measure description (ST)>
281
+ # < unit of measure coding system (IS)>
282
+ # < alternate unit of measure identifier (ST)>
283
+ # < alternate unit of measure description (ST)>
284
+ # < alternate unit of measure coding system (IS)>
285
+ end
286
+
287
+ #Coded with exceptions
288
+ def CWE(map, force=false)
289
+ #check if the field is optional and randomly generate it of skip
290
+ return '' if(!generate?(map, force))
291
+ # <identifier (ST)>
292
+ # <text (ST)> ^ <name of coding system (IS)> ^ <alternate identifier(ST)> ^ <alternate text (ST)> ^ <name of alternate coding system (IS)> ^ <coding system version ID (ST)> ^ alternate coding system version ID (ST)> ^ <original text (ST)>
293
+ end
294
+
295
+ #Generate HL7 CX (extended composite ID with check digit) data type.
296
+ def CX(map, force=false)
297
+ #check if the field is optional and randomly generate it of skip
298
+ return '' if(!generate?(map, force))
299
+
300
+ #ID (ST)
301
+ ST(reset_map_attr(map, :description, 'Number'), true)
302
+ #check digit (ST) (ST)
303
+ #code identifying the check digit scheme employed (ID)
304
+ #assigning authority (HD)
305
+ #identifier type code (ID) (ID)
306
+ #assigning facility (HD)
307
+ #effective date (DT) (DT)
308
+ #expiration date (DT)
309
+ end
310
+
311
+ # Daily deductible
312
+ def DDI(map, force=false)
313
+ #check if the field is optional and randomly generate it of skip
314
+ return '' if(!generate?(map, force))
315
+
316
+ # < delay days (NM)>
317
+ # < amount (NM)>
318
+ NM(map,true)
319
+ # < number of days (NM)>
320
+ end
321
+
322
+ # Activation date
323
+ def DIN(map, force=false)
324
+ #check if the field is optional and randomly generate it of skip
325
+ return '' if(!generate?(map, force))
326
+ # date < date (TS)>
327
+ TS(map,true)
328
+ # <institution name (CE)>
329
+ end
330
+
331
+ #Generate HL7 DLD (discharge location) data type. This type consists of the following components=>
332
+ def DLD(map, force=false)
333
+ #check if the field is optional and randomly generate it of skip
334
+ return '' if(!generate?(map, force))
335
+
336
+ val=[]
337
+ #discharge location (ID)
338
+ val<<ID(map, true)
339
+ #effective date (TS)
340
+ val<<TS({},true)
341
+ val.join(@@HAT)
342
+ end
343
+
344
+ #Generate HHL7 DLN (driver's license number) data type
345
+ def DLN(map, force=false)
346
+ #check if the field is optional and randomly generate it of skip
347
+ return '' if(!generate?(map, force))
348
+ val=[]
349
+ # DLN dln = (DLN) map.fld
350
+ #Driver´s License Number (ST)
351
+ val << generate_length_bound_id(10) # 10 vs 7 Numeric, as for some states in real life
352
+ #Issuing State, province, country (IS)
353
+ #is(['fld'=>dln.getIssuingStateProvinceCountry(), 'required'=>'R','codetable'=>map.codetable])
354
+ #dln.getIssuingStateProvinceCountry().setValue(allStates.get(Math.abs(random.nextInt()%allStates.size())))
355
+ # val << @yml['address.states'].sample # pick a state
356
+ val << IS({:codetable =>'333'},true) # pick a state
357
+ #expiration date (DT)
358
+ val << DT(reset_map_attr(map, :description, 'End'), true)
359
+ val.join(@@HAT)
360
+ end
361
+
362
+
363
+ # Delta check
364
+ def DLT(map, force=false)
365
+ #check if the field is optional and randomly generate it of skip
366
+ return '' if(!generate?(map, force))
367
+ # <range (NR)>
368
+ NR(map,true)
369
+ # <numeric threshold (NM)>
370
+ # <change computation (ST)>
371
+ # <length of time-days (NM)>
372
+ end
373
+
374
+ #Generates HL7 DR (date/time range) data type.
375
+ def DR(map, force=false)
376
+ #check if the field is optional and randomly generate it of skip
377
+ return '' if(!generate?(map, force))
378
+ val=[]
379
+ #range start date/time (TS)
380
+ val<<TS(map,true)
381
+ #range end date/time (TS)
382
+ val<<TS(reset_map_attr(map, :description, 'End'), true)
383
+ val.join(@@HAT)
384
+ end
385
+
386
+ #Generates an HL7 DT (date) datatype.
387
+ def DT(map, force=false)
388
+ #check if the field is optional and randomly generate it of skip
389
+ return '' if(!generate?(map, force))
390
+
391
+ is_year_only = (map[:max_length]) ? map[:max_length].to_i == 4 : false
392
+ # #time of an event (TSComponentOne)
393
+ (is_year_only)? to_datetime(map).strftime('%Y') : to_datetime(map).strftime('%Y%m%d') #format('YYYYMMdd.SSS')Date.iso8601
394
+ end
395
+
396
+ # Day Type and Number
397
+ def DTN(map, force=false)
398
+ #check if the field is optional and randomly generate it of skip
399
+ return '' if(!generate?(map, force))
400
+
401
+ # val=[]
402
+ # # <day type (IS)>
403
+ # val<<IS(map,true)
404
+ # per Galina request: Ensemble limits the length of IN3.11 to 3. So, we need to remove the second component from being populated ...
405
+ IS(map,true)
406
+ # # <number of days (NM)>
407
+ # val<<NM({},true)
408
+ # val.join(@@HAT)
409
+ end
410
+
411
+ # Encapsulated data
412
+ def ED(map, force=false)
413
+ #check if the field is optional and randomly generate it of skip
414
+ return '' if(!generate?(map, force))
415
+ # <source application (HD) >
416
+ HD(map, true)
417
+ # <type of data (ID)>
418
+ # <data subtype (ID)>
419
+ # <encoding (ID)>
420
+ # <data (ST)>
421
+ end
422
+
423
+ # Entity identifier
424
+ def EI(map, force=false)
425
+ #check if the field is optional and randomly generate it of skip
426
+ return '' if(!generate?(map, force))
427
+ # <entity identifier (ST)>
428
+ ST(map,true)
429
+ # <namespace ID (IS)>
430
+ # <universal ID (ST)>
431
+ # < universal ID type (ID)>
432
+ end
433
+
434
+ # Parent order
435
+ def EIP(map, force=false)
436
+ #check if the field is optional and randomly generate it of skip
437
+ return '' if(!generate?(map, force))
438
+
439
+ # <parent’s placer order number (EI)>
440
+ EI(map,true)
441
+ # <parent’s filler order number (EI)>
442
+ end
443
+
444
+ # Error segment
445
+ def ELD(map, force=false)
446
+ #check if the field is optional and randomly generate it of skip
447
+ return '' if(!generate?(map, force))
448
+ val = []
449
+ # <segment ID (ST)>
450
+ val<<''
451
+ # <sequence (NM)>
452
+ val<<''
453
+ # <field position (NM)>
454
+ val<<''
455
+ # <code identifying error (CE)>
456
+ val<<CE(map,true)
457
+ val.join(@@HAT)
458
+ end
459
+
460
+ #Generates HL7 FC (financial class) data type.
461
+ def FC(map, force=false)
462
+ #check if the field is optional and randomly generate it of skip
463
+ return '' if(!generate?(map, force))
464
+
465
+ val = []
466
+ #Financial Class (IS)
467
+ val << IS(map, true)
468
+ #Effective Date (TS) (TS)
469
+ val << TS(map, true)
470
+ val.join(@@HAT)
471
+ end
472
+
473
+ #Generates an HL7 FN (familiy name) data type.
474
+ def FN(map, force=false)
475
+ #check if the field is optional and randomly generate it of skip
476
+ return '' if(!generate?(map, force))
477
+
478
+ #surname (ST)
479
+ @yml['person.names.last'].sample
480
+ #own surname prefix (ST)
481
+ #own surname (ST)
482
+ #surname prefix from partner/spouse (ST)
483
+ #surname from partner/spouse (ST)
484
+ end
485
+
486
+ # Formatted text data.
487
+ # The FT field is of arbitrary length (up to 64k) and may contain formatting commands enclosed in escape characters.
488
+ def FT(map, force=false)
489
+ #check if the field is optional and randomly generate it of skip
490
+ return '' if(!generate?(map, force))
491
+
492
+ ID(map, true)
493
+ end
494
+
495
+
496
+ #Generates HL7 HD (hierarchic designator) data type
497
+ def HD(map, force=false)
498
+ #check if the field is optional and randomly generate it of skip
499
+ return '' if(!generate?(map, force))
500
+
501
+ #namespace ID (IS)
502
+ IS(map, true)
503
+ #universal ID (ST)
504
+ #universal ID type (ID)
505
+ end
506
+
507
+
508
+ # Generate HL7 ID, usually using value from code table
509
+ def ID(map, force=false)
510
+ #check if the field is optional and randomly generate it of skip
511
+ return '' if(!generate?(map, force))
512
+
513
+ #value only
514
+ #Case when max_len overrides requirements
515
+ len = safe_len(map[:max_length], @@REQ_LEN_3_DGTS)
516
+ (!blank?(map[:codetable]))? get_coded_value(map): generate_length_bound_id(len)
517
+ end
518
+
519
+ #Generates HL7 IS (namespace id) data type
520
+ def IS(map, force=false)
521
+ #check if the field is optional and randomly generate it of skip
522
+ return '' if(!generate?(map, force))
523
+
524
+ #TODO: same as ID?
525
+ ID(map,true)
526
+ end
527
+
528
+
529
+ #Generates HL7 JCC (job code/class) data type.
530
+ def JCC(map, force=false)
531
+ #check if the field is optional and randomly generate it of skip
532
+ return '' if(!generate?(map, force))
533
+
534
+ val=[]
535
+ #job code (IS)
536
+ # is(['fld'=>jcc.getComponent(0), 'required'=>'R', 'codetable'=>map.codetable])
537
+ val << IS(map, true)
538
+ #job class (IS)
539
+ val << IS(map, true)
540
+ # is(['fld'=>jcc.getComponent(1), 'required'=>'R'])
541
+ val.join(@@HAT)
542
+ end
543
+
544
+ # Location with address information (variant 1)
545
+ def LA1(map, force=false)
546
+ #check if the field is optional and randomly generate it of skip
547
+ return '' if(!generate?(map, force))
548
+ val =[]
549
+ # <point of care (IS)>
550
+ val<<IS(map,true)
551
+ # <room (IS) >
552
+ val<<IS({:codetable =>'303'},true)
553
+ # <bed (IS)>
554
+ val<<IS({:codetable =>'304'},true)
555
+ # <facility (HD) >
556
+ val<<HD({},true)
557
+ # <location status (IS)
558
+ val<<''
559
+ # <patient location type (IS)>
560
+ val<<''
561
+ # <building (IS)>
562
+ val<<IS({:codetable =>'307'},true)
563
+ # <floor (IS)>
564
+ # <address(AD)>
565
+ val.join(@@HAT)
566
+ end
567
+
568
+ # Location with address information (variant 2)
569
+ def LA2(map, force=false)
570
+ #check if the field is optional and randomly generate it of skip
571
+ return '' if(!generate?(map, force))
572
+
573
+ val =[]
574
+ # <point of care (IS)>
575
+ val<<IS(map,true)
576
+ # <room (IS)
577
+ val<<IS({:codetable =>'303'},true)
578
+ # <bed (IS)>
579
+ val<<IS({:codetable =>'304'},true)
580
+ # <facility (HD) >
581
+ val<<HD({},true)
582
+ # <location status (IS)
583
+ val<<''
584
+ # <patient location type (IS)>
585
+ val<<''
586
+ # <building (IS)>
587
+ val<<IS({:codetable =>'307'},true)
588
+ # <floor (IS)>
589
+ # < street address (ST)>
590
+ # <other designation (ST)>
591
+ # <city (ST)>
592
+ # <state or province (ST)>
593
+ # <zip or postal code (ST)>
594
+ # <country (ID)>
595
+ # <address type (ID)>
596
+ # <other geographic designation (ST)>
597
+ val.join(@@HAT)
598
+ end
599
+
600
+ #MA segment
601
+ def MA(map, force=false)
602
+ #check if the field is optional and randomly generate it of skip
603
+ return '' if(!generate?(map, force))
604
+
605
+ # <sample 1 from channel 1 (NM)>
606
+ NM(map,true)
607
+ # <sample 1 from channel 2 (NM)>
608
+ # <sample 1 from channel 3 (NM)>
609
+ # <sample 2 from channel 1 (NM)>
610
+ # <sample 2 from channel 2 (NM)>
611
+ # <sample 2 from channel 3 (NM)>
612
+ end
613
+
614
+
615
+ #Generates an HL7 MO (money) data type.
616
+ def MO(map, force=false)
617
+ #check if the field is optional and randomly generate it of skip
618
+ return '' if(!generate?(map, force))
619
+ # val = []
620
+ #quantity (NM)Guarantor Household Annual Income
621
+ # val << NM(reset_map_attr(map,:description,'Money'),true)
622
+ #val << NM(map,true)
623
+ NM(map,true)
624
+ #denomination (ID)
625
+ # val << 'USD' # Per request.
626
+ # return val.join(@@SUB)
627
+ end
628
+
629
+ # Charge to practice
630
+ def MOC(map, force=false)
631
+ #check if the field is optional and randomly generate it of skip
632
+ return '' if(!generate?(map, force))
633
+
634
+ # <dollar amount (MO)>
635
+ MO(map,true)
636
+ # <charge code (CE)>
637
+ end
638
+
639
+ # Money or percentage
640
+ def MOP(map, force=false)
641
+ #check if the field is optional and randomly generate it of skip
642
+ return '' if(!generate?(map, force))
643
+ val=[]
644
+ # <money or percentage indicator (IS)>
645
+ val<<IS({:codetable =>'148'},true)
646
+ # <money or percentage quantity (NM)>
647
+ val<<NM({:description =>'Percentage'},true)
648
+ val.join(@@HAT)
649
+ end
650
+
651
+ # MSG segment
652
+ def MSG(map, force=false)
653
+ #check if the field is optional and randomly generate it of skip
654
+ return '' if(!generate?(map, force))
655
+ val=[]
656
+ # <message type (ID)>
657
+ val<<IS({:codetable =>'76'},true)
658
+ # <trigger event (ID)>
659
+ val<<IS({:codetable =>'3'},true)
660
+ # <message structure (ID)>
661
+ val<<IS({:codetable =>'354'},true)
662
+ val.join(@@HAT)
663
+ end
664
+
665
+ #Generates HL7 MSG (Message Type) data type.
666
+ def MSH(map, force=false)
667
+ #Message type set while initializing MSH segment, do nothing.
668
+
669
+ #message type (ID)
670
+ #trigger event (ID)
671
+ #message structure (ID)
672
+ end
673
+
674
+
675
+ # Numeric Array
676
+ def NA(map, force=false)
677
+ #check if the field is optional and randomly generate it of skip
678
+ return '' if(!generate?(map, force))
679
+ # <value1 (NM)>
680
+ NM(map,true)
681
+ # <value2 (NM)>
682
+ # <value3 (NM)>
683
+ # <value4 (NM)>
684
+ end
685
+
686
+ # Observing practitioner
687
+ def NDL(map, force=false)
688
+ #check if the field is optional and randomly generate it of skip
689
+ return '' if(!generate?(map, force))
690
+ # <name (CNN)>
691
+ CNN(map,true)
692
+ # <start date/time (TS)>
693
+ # <end date/time (TS)>
694
+ # <point of care (IS)>
695
+ # <room (IS)>
696
+ # <bed (IS)>
697
+ # <facility (HD)>
698
+ # <location status (IS)>
699
+ # <person location type (IS)>
700
+ # <building (IS)>
701
+ # <floor (IS)>
702
+ end
703
+
704
+ #Generates an HL7 NM (numeric) data type. A NM contains a single String value.
705
+ def NM(map, force=false)
706
+ #check if the field is optional and randomly generate it of skip
707
+ return '' if(!generate?(map, force))
708
+ val = 0
709
+ case map[:description]
710
+ when'Guarantor Household Size','Birth Order'
711
+ val = generate_length_bound_id(1)
712
+ when 'Guarantor Household Annual Income'
713
+ val = '%.2f' % generate_length_bound_id(5)
714
+ when @@MONEY_FORMAT_REGEX
715
+ val = '%.2f' % ID(map,true)
716
+ when @@PERCENT_FORMAT_REGEX
717
+ val = @@random.rand(0..100) # generate proper % value < 100
718
+ else
719
+ val = ID(map,true) # general rule for a number
720
+ if (map[:datatype] == 'CP' || map[:datatype] == 'MO') # money
721
+ val = '%.2f' % val
722
+ end
723
+ end
724
+ # #money
725
+ # if (!Utils.blank?(map[:description]) && @@MONEY_FORMAT_INDICATORS.index{|it| map[:description].include?(it)}) #check for specific numeric for money
726
+ # val = '%.2f' % @@random.rand(@@UP_TO_3_DGTS) #under $1,000
727
+ # else #quantity (NM)
728
+ # val = @@random.rand(@@UP_TO_3_DGTS).to_s #under 20
729
+ # end
730
+ return val
731
+ end
732
+
733
+
734
+ #Numeric Range
735
+ def NR(map, force=false)
736
+ #check if the field is optional and randomly generate it of skip
737
+ return '' if(!generate?(map, force))
738
+ val=[]
739
+ # Low Value (NM)
740
+ val=NM(map,true)
741
+ # High Value (NM)
742
+ val<<''
743
+ val.join(@@SUB)
744
+ end
745
+
746
+ #Generates an HL7 OCD (occurence) data type.
747
+ #The code and associated date defining a significant event relating to a bill that may affect payer processing
748
+ def OCD(map, force=false)
749
+ #check if the field is optional and randomly generate it of skip
750
+ return '' if(!generate?(map, force))
751
+ val = []
752
+ #occurrence code (IS)
753
+ val << IS(map, true)
754
+ # is(['fld'=>ocd.getComponent(0), 'required'=>'R', 'codetable'=>map.codetable])
755
+ #occurrence date (DT)
756
+ #dt(['fld'=>ocd.getComponent(1), 'required'=>'R'])
757
+ val << DT(map, true)
758
+ val.join(@@HAT)
759
+ end
760
+
761
+ # Order sequence
762
+ def OSD(map, force=false)
763
+ #check if the field is optional and randomly generate it of skip
764
+ return '' if(!generate?(map, force))
765
+
766
+ # <sequence/results flag (ID)>
767
+ ID(map, force)
768
+ # <placer order number: entity identifier (ST)>
769
+ # <placer order number: namespace ID (IS)>
770
+ # <filler order number: entity identifier (ST)>
771
+ # <filler order number: namespace ID (IS)>
772
+ # <sequence condition value (ST)>
773
+ # <maximum number of repeats (NM)>
774
+ # <placer order number: universal ID (ST)>
775
+ # <placer order number; universal ID type (ID)>
776
+ # <filler order number: universal ID (ST)>
777
+ # <filler order number: universal ID type (ID)>
778
+ end
779
+
780
+ #Generate an HL7 OSP (occurence span) data type.
781
+ def OSP(map, force=false)
782
+ #check if the field is optional and randomly generate it of skip
783
+ return '' if(!generate?(map, force))
784
+ val = []
785
+
786
+ #occurrence span code (CE)
787
+ # val << CE(map, true) # Per request with ADT_A05 and ADT_A06 issues
788
+ val << ID(map, true)
789
+ #occurrence span start date (DT)
790
+ val << DT({},true)
791
+ #occurrence span stop date (DT)
792
+ val << DT(reset_map_attr(map, :description, 'End'), true)
793
+ val.join(@@HAT)
794
+ end
795
+
796
+ # Pre-certification required
797
+ def PCF(map, force=false)
798
+ #check if the field is optional and randomly generate it of skip
799
+ return '' if(!generate?(map, force))
800
+
801
+ # <pre-certification patient type (IS)>
802
+ IS({:codetable =>'150'},true)
803
+ # <pre-certification required>
804
+ # <pre-certification window>
805
+ end
806
+
807
+ # Person identifier
808
+ def PI(map, force=false)
809
+ #check if the field is optional and randomly generate it of skip
810
+ return '' if(!generate?(map, force))
811
+ # <ID number (ST)>
812
+ ST(map,true)
813
+ # <type of ID number>
814
+ # <other qualifying info>
815
+ end
816
+
817
+ # Privileges
818
+ def PIP(map, force=false)
819
+ #check if the field is optional and randomly generate it of skip
820
+ return '' if(!generate?(map, force))
821
+
822
+ # <privilege (CE)>
823
+ IS(map,true)
824
+ # <privilege class (CE)>
825
+ # <expiration date (DT)>
826
+ # <activation date (DT)>
827
+ # <facility (EI)>
828
+ end
829
+
830
+
831
+ #Generate an HL7 PL (person location) data type.
832
+ def PL(map, force=false)
833
+ #check if the field is optional and randomly generate it of skip
834
+ return '' if(!generate?(map, force))
835
+ val = []
836
+ #point of care (IS)
837
+ val<<IS({:codetable =>'302'},true)
838
+ #room (IS)
839
+ val<<IS({:codetable =>'303'},true)
840
+ #bed (IS)
841
+ val<<IS({:codetable =>'304'},true)
842
+ #facility (HD) (HD)
843
+ val << HD({:codetable =>'300'}, true)
844
+ #location status (IS)
845
+ val << ''
846
+ #person location type (IS)
847
+ val << ''
848
+ #building (IS)
849
+ val<<IS({:codetable =>'307'},true)
850
+ #floor (IS)
851
+ #Location description (ST)
852
+ val.join(@@HAT)
853
+ end
854
+
855
+ # Practitioner ID Numbers
856
+ def PLN(map, force=false)
857
+ #check if the field is optional and randomly generate it of skip
858
+ return '' if(!generate?(map, force))
859
+
860
+ # <ID number (ST)>
861
+ ST(map,true)
862
+ # <type of ID number (IS)>
863
+ # <state/other qualifying info (ST)>
864
+ # <expiration date (DT)>
865
+ end
866
+
867
+ # Person name
868
+ def PN(map, force=false)
869
+ #check if the field is optional and randomly generate it of skip
870
+ return '' if(!generate?(map, force))
871
+ val=[]
872
+ # family name (FN)
873
+ val << FN(map, true)
874
+ # given name (ST)
875
+ val << @yml['person.names.first'].sample
876
+ # second and further given names or initials thereof (ST)
877
+ val << @@INITIALS.to_a.sample
878
+ # suffix (e.g., JR or III) (ST)
879
+ # prefix (e.g., DR) (ST)
880
+ # degree (e.g., MD) (IS)
881
+ val.join(@@HAT)
882
+ end
883
+
884
+ # Performing person time stamp
885
+ def PPN(map, force=false)
886
+ # check if the field is optional and randomly generate it of skip
887
+ return '' if(!generate?(map, force))
888
+ val = []
889
+ # <ID number (ST)>
890
+ val << ST(map,true)
891
+
892
+ # PN will work for the subset of fields used below
893
+ val << PN({},true)
894
+ # <family name (FN)>
895
+ # <given name (ST)>
896
+ # <second and further given names or initials thereof (ST)>
897
+ # <suffix (e.g., JR or III) (ST)>
898
+ # <prefix (e.g., DR) (ST)>
899
+ # <degree (e.g., MD) (IS)>
900
+ # <source table (IS)>
901
+ # <assigning authority (HD)>
902
+ # <name type code(ID)>
903
+ # <identifier check digit (ST)>
904
+ # <code identifying the check digit scheme employed (ID )>
905
+ # <identifier type code (IS)>
906
+ # <assigning facility (HD)>
907
+ # < date/time action performed (TS)>
908
+ # <name representation code (ID)>
909
+ # <name context (CE)>
910
+ # <name validity range (DR)>
911
+ # <name assembly order (ID)>
912
+
913
+ val.join(@@HAT)
914
+ end
915
+
916
+ # Parent result link
917
+ def PRL(map, force=false)
918
+ #check if the field is optional and randomly generate it of skip
919
+ return '' if(!generate?(map, force))
920
+
921
+ # <OBX-3-observation identifier of parent result (CE)>
922
+ CE(map,true)
923
+ # <OBX-4-sub-ID of parent result(ST)>
924
+ # <part of OBX-5 observation result from parent (TX)see discussion>
925
+ end
926
+
927
+ #Generate HL7 S PT (processing type) data type.
928
+ def PT(map, force=false)
929
+ #check if the field is optional and randomly generate it of skip
930
+ return '' if(!generate?(map, force))
931
+
932
+ #map.maxlen
933
+ # PT pt = (PT) map.fld
934
+ # Map mp = map.clone()
935
+ # mp.fld = pt.getComponent(0)
936
+ # mp.required = 'R'
937
+ ID(map, true)
938
+ #processing ID (ID)
939
+ #processing mode (ID)
940
+ end
941
+
942
+ # Processing type
943
+ def PTA(map, force=false)
944
+ #check if the field is optional and randomly generate it of skip
945
+ return '' if(!generate?(map, force))
946
+
947
+ # <processing ID (ID)>
948
+ ID(map, true)
949
+ # <processing mode (ID)>
950
+ # <processing ID (ID)>
951
+ end
952
+
953
+ # Query input parameter list
954
+ def OIP(map, force=false)
955
+ #check if the field is optional and randomly generate it of skip
956
+ return '' if(!generate?(map, force))
957
+
958
+ # <segment field name (ST) >
959
+ # <value1 (ST) & value2 (ST) & value3 (ST) ...>
960
+ #Example: |@PID.5.1^EVANS|
961
+ #TBD
962
+ ''
963
+ end
964
+
965
+ # QSC Query selection criteria
966
+ def QSC(map, force=false)
967
+ #check if the field is optional and randomly generate it of skip
968
+ return '' if(!generate?(map, force))
969
+
970
+ # <segment field name(ST)>
971
+ # <relational operator (ID)>
972
+ # <value (ST)> <relational conjunction (ID)>
973
+ # Example: |@PID.5.1^EQ^EVANS|"
974
+ #TBD
975
+ ''
976
+ end
977
+
978
+ # RCD Row column definition
979
+ def RCD(map, force=false)
980
+ #check if the field is optional and randomly generate it of skip
981
+ return '' if(!generate?(map, force))
982
+
983
+ # <segment field name (ST)>
984
+ ST(reset_map_attr(map,:codetable, '440'),true)
985
+ # <HL7 data type (ID)>
986
+ # <maximum column width (NM)>
987
+ # Example: |@PID.5.1^ST^20|"
988
+ #TBD
989
+ # ''
990
+ end
991
+
992
+ # RDF Table row definition
993
+ def RDT(map, force=false)
994
+ #check if the field is optional and randomly generate it of skip
995
+ return '' if(!generate?(map, force))
996
+ val = []
997
+ # <parameter class (IS)>
998
+ # randomly generated 3-digit number
999
+ # v << generate_length_bound_id(@@REQ_LEN_3_DGTS)
1000
+ ID({},true)
1001
+ end
1002
+
1003
+ # Reference range
1004
+ def RFR(map, force=false)
1005
+ #check if the field is optional and randomly generate it of skip
1006
+ return '' if(!generate?(map, force))
1007
+
1008
+ # <numeric range (NR)>
1009
+ NR(map, true)
1010
+ # <administrative sex (IS)
1011
+ # <age range (NR)>
1012
+ # <gestational range (NR)>
1013
+ # <species (TX)>
1014
+ # <race/subspecies (ST)>
1015
+ # <conditions (TX)>
1016
+ end
1017
+
1018
+ # Repeat interval
1019
+ def RI(map, force=false)
1020
+ #check if the field is optional and randomly generate it of skip
1021
+ return '' if(!generate?(map, force))
1022
+ # <repeat pattern (IS)>
1023
+ # IS(map,true)
1024
+ IS(reset_map_attr(map, :codetable, '335'), true)
1025
+ # <explicit time interval (ST)>
1026
+ end
1027
+
1028
+ # Room coverage
1029
+ def RMC(map, force=false)
1030
+ #check if the field is optional and randomly generate it of skip
1031
+ return '' if(!generate?(map, force))
1032
+
1033
+ # <room type> (IS)
1034
+ IS(map,true)
1035
+ # <amount type>
1036
+ # <coverage amount>
1037
+ end
1038
+
1039
+ # Reference pointer
1040
+ def PR(map, force=false)
1041
+ #check if the field is optional and randomly generate it of skip
1042
+ return '' if(!generate?(map, force))
1043
+
1044
+ # <pointer (ST) >
1045
+ ST(map,true)
1046
+ # < application ID (HD)>
1047
+ # <type of data (ID)>
1048
+ # <subtype (ID)>
1049
+ end
1050
+
1051
+ # Street address
1052
+ # Appears ONLY in the XAD data type.
1053
+ # TODO: Future refactoring, handled in XAD.
1054
+ # def SAD(map, force=false)
1055
+ # #check if the field is optional and randomly generate it of skip
1056
+ # return '' if(!autoGenerate?(map,force))
1057
+ #
1058
+ # # <street or mailing address (ST)>
1059
+ # # <street name (ST)>
1060
+ # # <dwelling number (ST)>
1061
+ # end
1062
+
1063
+ # SCV Scheduling class value pair
1064
+ def SCV(map, force=false)
1065
+ #check if the field is optional and randomly generate it of skip
1066
+ return '' if(!generate?(map, force))
1067
+
1068
+ val = []
1069
+ # <parameter class (IS)>
1070
+ val<<''
1071
+ # <parameter value (ST)>
1072
+ # val<<ST(map,true)
1073
+ val<<ST(reset_map_attr(map,:codetable, '294'),true)
1074
+ val.join(@@HAT)
1075
+ end
1076
+
1077
+ #Generate HL7 SI (sequence ID) data type. A SI contains a single String value.
1078
+ def SI(map, force=false)
1079
+ #check if the field is optional and randomly generate it of skip
1080
+ return '' if(!generate?(map, force))
1081
+
1082
+ #SI pt = (SI) map.fld
1083
+ #pt.setValue(generate_length_bound_id((map.max_length)?map.max_length.toInteger():1))
1084
+ len = (!blank?(map[:max_length]))?map[:max_length].to_i : 1
1085
+ # per Galina: - the set IDs should be max 4 digits, please remove all the zeros.
1086
+ len = (len >4 )? 4 :len
1087
+ generate_length_bound_id(len)
1088
+ end
1089
+
1090
+ # Structured numeric
1091
+ def SN(map, force=false)
1092
+ #check if the field is optional and randomly generate it of skip
1093
+ return '' if(!generate?(map, force))
1094
+ val = []
1095
+ # <comparator (ST)>
1096
+ val << ''
1097
+ # <num1 (NM)>
1098
+ val << NM(map,true)
1099
+ # <separator/suffix (ST)>
1100
+ # <num2 (NM)>
1101
+ val.join(@@HAT)
1102
+ end
1103
+
1104
+ # Specialty
1105
+ def SPD(map, force=false)
1106
+ #check if the field is optional and randomly generate it of skip
1107
+ return '' if(!generate?(map, force))
1108
+
1109
+ # <specialty name (ST)>
1110
+ ST(map,true)
1111
+ # <governing board (ST)>
1112
+ # <eligible or certified (ID)>
1113
+ # <date of certification (DT)>
1114
+ end
1115
+
1116
+ # Specimen source
1117
+ def SPS(map, force=false)
1118
+ #check if the field is optional and randomly generate it of skip
1119
+ return '' if(!generate?(map, force))
1120
+
1121
+ #<specimen source name or code (CE)>
1122
+ CE(map,true)
1123
+ # <additives (TX)>
1124
+ # <freetext (TX)>
1125
+ # <body site (CE)>
1126
+ # <site modifier (CE)>
1127
+ # <collection modifier method code (CE)>
1128
+ # <specimen role (CE)>
1129
+ end
1130
+
1131
+ #Sort order
1132
+ def SRT(map, force=false)
1133
+ #check if the field is optional and randomly generate it of skip
1134
+ return '' if(!generate?(map, force))
1135
+
1136
+ # <sort-by field (ST)>
1137
+ # <sequencing (ID)>
1138
+ ID(map,true)
1139
+ end
1140
+
1141
+ #Generate HL7 ST (string data) data type. A ST contains a single String value.
1142
+ def ST(map, force=false)
1143
+ #check if the field is optional and randomly generate it of skip
1144
+ return '' if(!generate?(map, force))
1145
+
1146
+ # TODO add provider type ln 840 ROL
1147
+ case map[:description]
1148
+ when 'Guarantor SSN','Insured’s Social Security Number','Medicare health ins Card Number','Military ID Number', 'Contact Person Social Security Number'
1149
+ generate_length_bound_id(9)
1150
+ when 'Allergy Reaction Code'
1151
+ yml['codes.allergens'].keys.sample()
1152
+ when 'Strain'
1153
+ #PID.35 – PID.38 should be always blank, as they deal with animals, not humans.
1154
+ when 'AGENT ORANGE EXPOSURE LOCATION'
1155
+ #ZEL.29 should be 1 digit integer.
1156
+ generate_length_bound_id(1)
1157
+ else
1158
+ #Case when max_len overrides requirements
1159
+ len = safe_len(map[:max_length], @@REQ_LEN_3_DGTS)
1160
+ (!blank?(map[:codetable]))? get_coded_value(map): generate_length_bound_id(len)
1161
+ end
1162
+
1163
+ end
1164
+
1165
+ # An Elementary Data Type Format: HH[MM[SS[.S[S[S[S]]]]]][+/-ZZZZ]
1166
+ # EX: 160140.761
1167
+ def TM(map, force=false)
1168
+ #check if the field is optional and randomly generate it of skip
1169
+ return '' if(!generate?(map, force))
1170
+ to_datetime(map).strftime('%H%M%S.%L')
1171
+ end
1172
+
1173
+ #Generate an HL7 TN (telephone number) data type. A TN contains a single String value.
1174
+ def TN(map, force=false)
1175
+ #check if the field is optional and randomly generate it of skip
1176
+ return '' if(!generate?(map, force))
1177
+
1178
+ # TN tn = (TN) map.fld
1179
+ # tn.setValue(phones.getAt(Math.abs(random.nextInt()%phones.size())))
1180
+ @yml['address.phones'].sample # pick a phone
1181
+ end
1182
+
1183
+ # Timing quantity
1184
+ def TQ(map, force=false)
1185
+ #check if the field is optional and randomly generate it of skip
1186
+ return '' if(!generate?(map, force))
1187
+
1188
+ # <quantity (CQ)>
1189
+ # CQ(reset_map_attr(map, :codetable, '335'), true)
1190
+ CQ(map,true)
1191
+ # <interval (RI)
1192
+ # < duration (ST)>
1193
+ # <start date/time (TS)>
1194
+ # <end date/time (TS)>
1195
+ # <priority (ST)>
1196
+ # <condition (ST)>
1197
+ # <text (TX)>
1198
+ # <conjunction component (ID)>
1199
+ # <order sequencing (OSD)>
1200
+ # <occurrence duration (CE)>
1201
+ # <total occurrences (NM)>
1202
+ end
1203
+
1204
+ #Generate HL7 TS (time stamp), within number of weeks in the future or past
1205
+ def TS(map, force=false)
1206
+ #check if the field is optional and randomly generate it of skip
1207
+ return '' if(!generate?(map, force))
1208
+
1209
+ #time of an event (TSComponentOne)
1210
+ ts = to_datetime(map).strftime('%Y%m%d%H%M%S.%L') #format('YYYYMMDDHHSS.SSS')Date.iso8601
1211
+ # TS is lenght sensetive, check max_len and trim appropriate
1212
+ if (ts.size > (maxlen = (map[:max_length]) ? map[:max_length].to_i : ts.size))
1213
+ # puts ts
1214
+ # ts = ts[0,maxlen]
1215
+ ts = ts.slice(0...maxlen)
1216
+ end
1217
+ return ts
1218
+ end
1219
+
1220
+ #Generate HL7 TX (text data) data type. A TX contains a single String value.
1221
+ def TX(map, force=false)
1222
+ #check if the field is optional and randomly generate it of skip
1223
+ return '' if(!generate?(map, force))
1224
+ # @@GENERAL_TEXT
1225
+ ID(map,true)
1226
+ end
1227
+
1228
+ #Generate an HL7 UVC (Value code and amount) data type.
1229
+ def UVC(map, force=false)
1230
+ #check if the field is optional and randomly generate it of skip
1231
+ return '' if(!generate?(map, force))
1232
+ val =[]
1233
+ # UVC uvc = ((UVC)map.fld)
1234
+ #value code (IS)
1235
+ val << IS(map, true)
1236
+ # is(['fld'=>uvc.getComponent(0), 'required'=>'R', 'codetable'=>map.codetable])
1237
+ #value amount (NM)
1238
+ # nm(['fld'=>uvc.getComponent(1), 'required'=>'R'])
1239
+ val << NM({},true)# description confuses NM generator
1240
+ val.join(@@HAT)
1241
+ end
1242
+
1243
+ # Visiting hours
1244
+ def VH(map, force=false)
1245
+ #check if the field is optional and randomly generate it of skip
1246
+ return '' if(!generate?(map, force))
1247
+
1248
+ val =[]
1249
+ # <start day range (ID)>
1250
+ val << ID(map,true)
1251
+ # <end day range (ID)>
1252
+ val << ID(map,true)
1253
+ # <start hour range (TM)>
1254
+ # <end hour range (TM)>
1255
+ val.join(@@HAT)
1256
+ end
1257
+
1258
+ #Generate an HL7 VID (version identifier) data type.
1259
+ def VID(map, force=false)
1260
+ #check if the field is optional and randomly generate it of skip
1261
+ return '' if(!generate?(map, force))
1262
+
1263
+ # VID vid = ((VID)map.fld)
1264
+ #version ID (ID)
1265
+ ID(map, true)
1266
+ #id(['fld'=>vid.getComponent(0), 'required'=>'R', 'codetable'=>map.codetable])
1267
+
1268
+ # internationalization code (CE)
1269
+ # international version ID (CE)
1270
+ end
1271
+
1272
+ # Value qualifier
1273
+ def VR(map, force=false)
1274
+ #check if the field is optional and randomly generate it of skip
1275
+ return '' if(!generate?(map, force))
1276
+ # <first data code value (ST)>
1277
+ ST(map,true)
1278
+ # <Last data code value (ST)>
1279
+ end
1280
+
1281
+ #Channel identifier
1282
+ def WVI(map, force=true)
1283
+ #check if the field is optional and randomly generate it of skip
1284
+ return '' if(!generate?(map, force))
1285
+
1286
+ # <channel number (NM)>
1287
+ NM(map, true)
1288
+ # <channel name (ST)>
1289
+ end
1290
+
1291
+
1292
+ # def WVS(map, force=false)
1293
+ # #check if the field is optional and randomly generate it of skip
1294
+ # return '' if(!autoGenerate?(map,force))
1295
+ # end
1296
+
1297
+ #Generate HL7 XAD (extended address)
1298
+ def XAD(map, force=false)
1299
+ #check if the field is optional and randomly generate it of skip
1300
+ return '' if(!generate?(map, force))
1301
+
1302
+ # same as address AD
1303
+ AD(map,true)
1304
+ #street address (SAD) (SAD)
1305
+ #other designation (ST)
1306
+ #city (ST)
1307
+ #state or province (ST)
1308
+ #zip or postal code (ST)
1309
+ #country (ID)
1310
+ #address type (ID)
1311
+ #other geographic designation (ST)
1312
+ #county/parish code (IS)
1313
+ #census tract (IS)
1314
+ #address representation code (ID)
1315
+ #address validity range (DR)
1316
+ end
1317
+
1318
+ # Generate HL7 XCN (extended composite ID number and name for persons)
1319
+ def XCN(map, force=false)
1320
+ #check if the field is optional and randomly generate it of skip
1321
+ return '' if(!generate?(map, force))
1322
+
1323
+ val=[]
1324
+ # XCN xcn = (XCN) map.fld
1325
+ # ID number (ST) (ST)
1326
+ val << ID(map, true)
1327
+ # xcn.getIDNumber().setValue(Math.abs(random.nextInt() % 300).toString())
1328
+
1329
+ val << PN(map, true)
1330
+ # family name (FN)
1331
+ # val << FN(map, true)
1332
+ # given name (ST)
1333
+ # val << @yml['person.names.first'].sample
1334
+ # second and further given names or initials thereof (ST)
1335
+ # val << @@INITIALS.to_a.sample
1336
+ # suffix (e.g., JR or III) (ST)
1337
+ # prefix (e.g., DR) (ST)
1338
+ # degree (e.g., MD) (IS)
1339
+
1340
+ # source table (IS)
1341
+ # assigning authority (HD)
1342
+ # name type code (ID)
1343
+ # identifier check digit (ST)
1344
+ # code identifying the check digit scheme employed (ID)
1345
+ # identifier type code (IS) (IS)
1346
+ # assigning facility (HD)
1347
+ # Name Representation code (ID)
1348
+ # name context (CE)
1349
+ # name validity range (DR)
1350
+ # name assembly order (ID)
1351
+ val.join(@@HAT)
1352
+ end
1353
+
1354
+ #Generate an HL7 XON (extended composite name and identification number for organizations) data type.
1355
+ def XON(map, force=false)
1356
+ #check if the field is optional and randomly generate it of skip
1357
+ return '' if(!generate?(map, force))
1358
+
1359
+ # XON xtn = (XON) map.fld
1360
+ val=[]
1361
+ #organization name (ST)
1362
+ val << ST(map, true)
1363
+ # st(['fld'=>xtn.getComponent(0), 'required'=>'R', 'codetable'=>map.codetable])
1364
+ #organization name type code (IS)
1365
+ val << ''
1366
+ #ID number (NM) (NM)
1367
+ val << NM(map, true)
1368
+ #nm(['fld'=>xtn.getComponent(2), 'required'=>'R'])
1369
+ #check digit (NM) (ST)
1370
+ #code identifying the check digit scheme employed (ID)
1371
+ #assigning authority (HD)
1372
+ #identifier type code (IS) (IS)
1373
+ #assigning facility ID (HD)
1374
+ #Name Representation code (ID)
1375
+ val.join(@@HAT)
1376
+ end
1377
+
1378
+ #Generate an HL7 XPN (extended person name) data type. This type consists of the following components=>
1379
+ def XPN(map, force=false)
1380
+ #check if the field is optional and randomly generate it of skip
1381
+ return '' if(!generate?(map, force))
1382
+
1383
+ # val=[]
1384
+ #family name (FN)
1385
+ # val << FN(map, true)
1386
+ # fn(['fld'=> xpn.getComponent(0),'required'=>'R'])
1387
+ #given name (ST)
1388
+ # val << @yml['person.names.first'].sample
1389
+ #xpn.givenName.setValue(firstNames.getAt(Math.abs(random.nextInt()%firstNames.size())));
1390
+ #xpn.getComponent(1).setValue(firstNames.getAt(Math.abs(random.nextInt()%firstNames.size())))
1391
+ #second and further given names or initials thereof (ST)
1392
+ # val << @@INITIALS.to_a.sample
1393
+ #xpn.secondAndFurtherGivenNamesOrInitialsThereof.setValue('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.getAt(Math.abs(random.nextInt()%26)))
1394
+ #suffix (e.g., JR or III) (ST)
1395
+ #prefix (e.g., DR) (ST)
1396
+ #degree (e.g., MD) (IS)
1397
+ PN(map,true)
1398
+
1399
+ #name type code (ID)
1400
+ # val.join(@@HAT)
1401
+
1402
+ end
1403
+
1404
+ #Generate HL7 XTN (extended telecommunication number)
1405
+ def XTN(map, force=false)
1406
+ #check if the field is optional and randomly generate it of skip
1407
+ return '' if(!generate?(map, force))
1408
+
1409
+ #[(999)] 999-9999 [X99999][C any text] (TN)
1410
+ TN(map, true)
1411
+ #xtn.get9999999X99999CAnyText().setValue(phones.getAt(Math.abs(random.nextInt()%phones.size())))
1412
+ # telecommunication use code (ID)
1413
+ # telecommunication equipment type (ID) (ID)
1414
+ # Email address (ST)
1415
+ # Country Code (NM)
1416
+ # Area/city code (NM)
1417
+ # Phone number (NM)
1418
+ # Extension (NM)
1419
+ # any text (ST)
1420
+ end
1421
+
1422
+ # def xx(map, force=false)
1423
+ # #check if the field is optional and randomly generate it of skip
1424
+ # return '' if(!autoGenerate?(map,force))
1425
+ # end
1426
+
1427
+ # End of Data Types #
1428
+
1429
+ # Value of coded table returned as as single value
1430
+ def get_coded_value(attributes)
1431
+ codes = get_code_table(attributes)
1432
+
1433
+ # puts codes
1434
+ #Apply rules to find a value and description
1435
+ map = apply_rules(codes, attributes)
1436
+ #Return value only
1437
+ return map[:value]
1438
+ end
1439
+
1440
+ # Values and Description from code table returned as a pair.
1441
+ def get_coded_map(attributes)
1442
+ codes = get_code_table(attributes)
1443
+
1444
+ # puts codes
1445
+ #Apply rules to find a value and description
1446
+ #Returns map with code and description
1447
+ apply_rules(codes, attributes)
1448
+ end
1449
+
1450
+ def get_code_table(attributes)
1451
+ codeTable = get_name_without_base(attributes[:codetable])
1452
+ codes = @pp.get_code_table(codeTable)
1453
+ # Case when we are looking for code values defined in base schema for types
1454
+ # which are in custom/primary schema or the othere way around.
1455
+ if(@hp && (codes.first == Utils::DATA_LOOKUP_MIS))
1456
+ codes = @hp.get_code_table(codeTable)
1457
+ end
1458
+ return codes
1459
+ end
1460
+
1461
+ # Handle range values specified by '...' sequence, including empty range
1462
+ #TODO refactor candidate
1463
+ def apply_rules(codes, attributes)
1464
+ #safety check, no codes returns an empty map
1465
+ return {} if blank?(codes)
1466
+
1467
+ #index of random element
1468
+ idx = sample_index(codes.size)
1469
+ code = codes[idx][:value]
1470
+ description = codes[idx][:description]
1471
+
1472
+ if (code.include?(@@RANGE_INDICATOR))
1473
+ code = handle_ranges(code)
1474
+ end
1475
+
1476
+ if (code.size > (maxlen = (attributes[:max_length]) ? attributes[:max_length].to_i : code.size))
1477
+ #remove all codes wich values violate
1478
+ #codes.select! {|it| it[:value].size <= maxlen }
1479
+ code, description = handle_length(codes, maxlen)
1480
+ end
1481
+
1482
+ # got to have code, get an id, most basic - TODO: verify this.
1483
+ # if(Utils.blank?(code))
1484
+ # code, description = ID({},true), ''
1485
+ # end
1486
+ # return code, description
1487
+
1488
+ # puts code + ', ' + description
1489
+ return {:value => code, :description => description}
1490
+ end
1491
+
1492
+ def handle_length(codes, maxlen)
1493
+ idx = codes.find_index { |it| it[:value].size <= maxlen }
1494
+
1495
+ if (!idx)
1496
+ code, description = '', ''
1497
+ else
1498
+ # puts codes
1499
+ code = codes[idx][:value]
1500
+ description = codes[idx][:description]
1501
+ end
1502
+ return code, description
1503
+ end
1504
+
1505
+ def handle_ranges(code)
1506
+ # if (code.include?(@@RANGE_INDICATOR))
1507
+ ends = code.delete(' ').split('...').map { |it| it }
1508
+ if (ends.empty?) # This is indication that codetable does not have any values
1509
+ code = ''
1510
+ else #Handle range values, build range and pick random value
1511
+ # range = ends.first..ends.last
1512
+ # code = range.to_a.sample
1513
+
1514
+ # per Galina: Invalid value 'Q8' appears in segment 4:PD1, field 20, repetition 1, component 1, subcomponent 1,
1515
+ # but does not appear in code table 2.4:141.
1516
+ # I think you had to fix this one before to pull only the first and the last values from each row.
1517
+ code = ends.sample
1518
+ end
1519
+ return code
1520
+ end
1521
+
1522
+ # Returns randomly generated Id of required length, of single digit id
1523
+ def generate_length_bound_id(maxlen, str=@@random.rand(100000000).to_s)
1524
+ idx = maxlen
1525
+ if(maxlen > str.size)
1526
+ str = str.ljust(maxlen,'0')
1527
+ idx = str.size
1528
+ end
1529
+ #safe fail
1530
+ #this handles case when maxlen is less then 1
1531
+ idx = [0,idx-1].max
1532
+ return str[0..idx]
1533
+ end
1534
+
1535
+
1536
+ # # Returns randomly generated Id of required length, of single digit id
1537
+ # def generateLengthBoundId1(map, str=@@random.rand(100000000).to_s)
1538
+ # (!Utils.blank?(map[:codetable]))? get_coded_value(map): @@random.rand(@@UP_TO_3_DGTS).to_s
1539
+ #
1540
+ # map[:maxlen]
1541
+ # end
1542
+
1543
+ # If field are X,W,B (Not Supported, Withdrawn Fields or Backward Compatible) returns false.
1544
+ # Conditional (C) ?
1545
+ # For Optional field (O) makes random choice
1546
+ # R - Required returns true
1547
+ # def autoGenerate?(map, force=false)
1548
+ def generate?(map, force=false)
1549
+ # return true
1550
+ return true if(force) #forced generation, ignore mappings
1551
+
1552
+ #look up in the mapping
1553
+ case map[:required]
1554
+ when 'X','W','B' then false;
1555
+ when 'R' then true;
1556
+ when 'O' then [true,false].sample();
1557
+ else false ;
1558
+ end
1559
+ # if(['X','W','B'].include?(map[:required]))then return false end
1560
+ # if(map[:required] =='R') then return true end
1561
+ # if(map[:required] == 'O') then return true end #random boolean
1562
+ end
1563
+
1564
+ # @return DateTime generated with consideration of description string for dates in the future
1565
+ def to_datetime(map)
1566
+ #for Time Stamp one way to figure out if event is in the future of in the past to look for key words in description
1567
+ isFutureEvent = !blank?(map[:description])&& map[:description].include?('End') #so 'Role End Date/Time'
1568
+ seed = 365 #seed bounds duration of time to a year
1569
+ days = @@random.rand(seed)
1570
+
1571
+ if(map[:description]=='Date/Time Of Birth')
1572
+ isFutureEvent = false
1573
+ years = rand(30..50)
1574
+ days = days + 365*years # make a person 30 years old
1575
+ end
1576
+
1577
+ (isFutureEvent) ? DateTime.now().next_day(days) : DateTime.now().prev_day(days)
1578
+ end
1579
+
1580
+ # convention method to modify values of attirbutes
1581
+ def reset_map_attr(map, key, value)
1582
+ map[key.to_sym]=value
1583
+ return map
1584
+ end
1585
+
1586
+ end