ez7gen 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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