ccls-ccls_engine 3.11.0

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 (269) hide show
  1. data/README.rdoc +182 -0
  2. data/app/models/abstract.rb +181 -0
  3. data/app/models/abstract_search.rb +50 -0
  4. data/app/models/abstract_validations.rb +324 -0
  5. data/app/models/address.rb +70 -0
  6. data/app/models/address_type.rb +15 -0
  7. data/app/models/addressing.rb +147 -0
  8. data/app/models/aliquot.rb +44 -0
  9. data/app/models/aliquot_sample_format.rb +13 -0
  10. data/app/models/analysis.rb +14 -0
  11. data/app/models/bc_request.rb +20 -0
  12. data/app/models/candidate_control.rb +101 -0
  13. data/app/models/context.rb +23 -0
  14. data/app/models/context_data_source.rb +4 -0
  15. data/app/models/county.rb +16 -0
  16. data/app/models/data_source.rb +24 -0
  17. data/app/models/diagnosis.rb +23 -0
  18. data/app/models/document_type.rb +16 -0
  19. data/app/models/document_version.rb +27 -0
  20. data/app/models/enrollment.rb +78 -0
  21. data/app/models/enrollment_validations.rb +167 -0
  22. data/app/models/follow_up.rb +16 -0
  23. data/app/models/follow_up_type.rb +18 -0
  24. data/app/models/gift_card.rb +22 -0
  25. data/app/models/gift_card_search.rb +137 -0
  26. data/app/models/home_exposure_response.rb +24 -0
  27. data/app/models/homex_outcome.rb +75 -0
  28. data/app/models/hospital.rb +22 -0
  29. data/app/models/icf_master_id.rb +30 -0
  30. data/app/models/icf_master_tracker.rb +217 -0
  31. data/app/models/icf_master_tracker_change.rb +9 -0
  32. data/app/models/icf_master_tracker_update.rb +50 -0
  33. data/app/models/ineligible_reason.rb +26 -0
  34. data/app/models/instrument.rb +26 -0
  35. data/app/models/instrument_type.rb +17 -0
  36. data/app/models/instrument_version.rb +28 -0
  37. data/app/models/interview.rb +122 -0
  38. data/app/models/interview_method.rb +17 -0
  39. data/app/models/interview_outcome.rb +16 -0
  40. data/app/models/language.rb +28 -0
  41. data/app/models/live_birth_data_update.rb +142 -0
  42. data/app/models/operational_event.rb +99 -0
  43. data/app/models/operational_event_type.rb +31 -0
  44. data/app/models/organization.rb +28 -0
  45. data/app/models/patient.rb +63 -0
  46. data/app/models/patient_validations.rb +118 -0
  47. data/app/models/person.rb +28 -0
  48. data/app/models/phone_number.rb +105 -0
  49. data/app/models/phone_type.rb +15 -0
  50. data/app/models/project.rb +39 -0
  51. data/app/models/project_outcome.rb +19 -0
  52. data/app/models/race.rb +31 -0
  53. data/app/models/refusal_reason.rb +23 -0
  54. data/app/models/sample.rb +168 -0
  55. data/app/models/sample_kit.rb +14 -0
  56. data/app/models/sample_outcome.rb +16 -0
  57. data/app/models/sample_temperature.rb +14 -0
  58. data/app/models/sample_type.rb +37 -0
  59. data/app/models/search.rb +195 -0
  60. data/app/models/section.rb +18 -0
  61. data/app/models/state.rb +25 -0
  62. data/app/models/study_subject.rb +237 -0
  63. data/app/models/study_subject_abstracts.rb +47 -0
  64. data/app/models/study_subject_addresses.rb +34 -0
  65. data/app/models/study_subject_associations.rb +38 -0
  66. data/app/models/study_subject_duplicates.rb +111 -0
  67. data/app/models/study_subject_enrollments.rb +17 -0
  68. data/app/models/study_subject_homex_outcome.rb +22 -0
  69. data/app/models/study_subject_identifier.rb +153 -0
  70. data/app/models/study_subject_interviews.rb +25 -0
  71. data/app/models/study_subject_languages.rb +21 -0
  72. data/app/models/study_subject_operational_events.rb +66 -0
  73. data/app/models/study_subject_patient.rb +177 -0
  74. data/app/models/study_subject_pii.rb +74 -0
  75. data/app/models/study_subject_races.rb +25 -0
  76. data/app/models/study_subject_search.rb +260 -0
  77. data/app/models/study_subject_validations.rb +116 -0
  78. data/app/models/subject_language.rb +11 -0
  79. data/app/models/subject_race.rb +11 -0
  80. data/app/models/subject_relationship.rb +21 -0
  81. data/app/models/subject_type.rb +22 -0
  82. data/app/models/tracing_status.rb +20 -0
  83. data/app/models/transfer.rb +40 -0
  84. data/app/models/unit.rb +14 -0
  85. data/app/models/vital_status.rb +19 -0
  86. data/app/models/zip_code.rb +36 -0
  87. data/config/abstract_fields.yml +1038 -0
  88. data/config/abstract_sections.yml +77 -0
  89. data/config/home_exposure_response_fields.yml +583 -0
  90. data/config/icf_master_tracker_update.yml +56 -0
  91. data/config/live_birth_data_update.yml +56 -0
  92. data/config/shared_use_db.yml +4 -0
  93. data/generators/ccls_engine/USAGE +2 -0
  94. data/generators/ccls_engine/ccls_engine_generator.rb +123 -0
  95. data/generators/ccls_engine/templates/autotest_ccls_engine.rb +3 -0
  96. data/generators/ccls_engine/templates/ccls_engine.rake +12 -0
  97. data/generators/ccls_engine/templates/fixtures/address_types.yml +30 -0
  98. data/generators/ccls_engine/templates/fixtures/context_data_sources.yml +54 -0
  99. data/generators/ccls_engine/templates/fixtures/contexts.yml +19 -0
  100. data/generators/ccls_engine/templates/fixtures/data_sources.yml +40 -0
  101. data/generators/ccls_engine/templates/fixtures/diagnoses.yml +40 -0
  102. data/generators/ccls_engine/templates/fixtures/document_types.yml +65 -0
  103. data/generators/ccls_engine/templates/fixtures/document_versions.csv +155 -0
  104. data/generators/ccls_engine/templates/fixtures/follow_up_types.yml +16 -0
  105. data/generators/ccls_engine/templates/fixtures/hospitals.yml +114 -0
  106. data/generators/ccls_engine/templates/fixtures/ineligible_reasons.yml +35 -0
  107. data/generators/ccls_engine/templates/fixtures/instrument_types.yml +26 -0
  108. data/generators/ccls_engine/templates/fixtures/instrument_versions.yml +22 -0
  109. data/generators/ccls_engine/templates/fixtures/instruments.yml +22 -0
  110. data/generators/ccls_engine/templates/fixtures/interview_methods.yml +30 -0
  111. data/generators/ccls_engine/templates/fixtures/interview_outcomes.yml +31 -0
  112. data/generators/ccls_engine/templates/fixtures/languages.yml +34 -0
  113. data/generators/ccls_engine/templates/fixtures/operational_event_types.yml +141 -0
  114. data/generators/ccls_engine/templates/fixtures/organizations.yml +198 -0
  115. data/generators/ccls_engine/templates/fixtures/people.yml +130 -0
  116. data/generators/ccls_engine/templates/fixtures/phone_types.yml +30 -0
  117. data/generators/ccls_engine/templates/fixtures/project_outcomes.yml +25 -0
  118. data/generators/ccls_engine/templates/fixtures/projects.yml +59 -0
  119. data/generators/ccls_engine/templates/fixtures/races.yml +52 -0
  120. data/generators/ccls_engine/templates/fixtures/refusal_reasons.yml +55 -0
  121. data/generators/ccls_engine/templates/fixtures/sample_outcomes.yml +36 -0
  122. data/generators/ccls_engine/templates/fixtures/sample_temperatures.yml +16 -0
  123. data/generators/ccls_engine/templates/fixtures/sample_types.yml +147 -0
  124. data/generators/ccls_engine/templates/fixtures/sections.yml +31 -0
  125. data/generators/ccls_engine/templates/fixtures/states.yml +363 -0
  126. data/generators/ccls_engine/templates/fixtures/subject_relationships.yml +46 -0
  127. data/generators/ccls_engine/templates/fixtures/subject_types.yml +30 -0
  128. data/generators/ccls_engine/templates/fixtures/tracing_statuses.yml +30 -0
  129. data/generators/ccls_engine/templates/fixtures/units.yml +13 -0
  130. data/generators/ccls_engine/templates/fixtures/vital_statuses.yml +28 -0
  131. data/generators/ccls_engine/templates/functional/roles_controller_test.rb +142 -0
  132. data/generators/ccls_engine/templates/functional/sessions_controller_test.rb +19 -0
  133. data/generators/ccls_engine/templates/functional/users_controller_test.rb +94 -0
  134. data/generators/ccls_engine/templates/images/sort_down.png +0 -0
  135. data/generators/ccls_engine/templates/images/sort_up.png +0 -0
  136. data/generators/ccls_engine/templates/initializer.rb +28 -0
  137. data/generators/ccls_engine/templates/javascripts/ccls_engine.js +24 -0
  138. data/generators/ccls_engine/templates/javascripts/jquery-ui.js +763 -0
  139. data/generators/ccls_engine/templates/javascripts/jquery.js +154 -0
  140. data/generators/ccls_engine/templates/javascripts/jrails.js +1 -0
  141. data/generators/ccls_engine/templates/migrations/create_user_invitations.rb +18 -0
  142. data/generators/ccls_engine/templates/migrations/create_users.rb +33 -0
  143. data/generators/ccls_engine/templates/migrations/drop_user_invitations.rb +18 -0
  144. data/generators/ccls_engine/templates/stylesheets/ccls_engine.css +180 -0
  145. data/generators/ccls_engine/templates/stylesheets/user.css +35 -0
  146. data/generators/ccls_engine/templates/stylesheets/users.css +23 -0
  147. data/generators/ccls_engine/templates/unit/core_extension_test.rb +18 -0
  148. data/generators/ccls_engine/templates/unit/role_test.rb +30 -0
  149. data/generators/ccls_engine/templates/unit/user_test.rb +321 -0
  150. data/lib/ccls-ccls_engine.rb +1 -0
  151. data/lib/ccls_engine.rb +135 -0
  152. data/lib/ccls_engine/action_view_extension.rb +3 -0
  153. data/lib/ccls_engine/action_view_extension/base.rb +53 -0
  154. data/lib/ccls_engine/action_view_extension/form_builder.rb +39 -0
  155. data/lib/ccls_engine/active_record_extension.rb +2 -0
  156. data/lib/ccls_engine/active_record_extension/base.rb +70 -0
  157. data/lib/ccls_engine/active_record_shared.rb +8 -0
  158. data/lib/ccls_engine/assertions.rb +69 -0
  159. data/lib/ccls_engine/autotest.rb +54 -0
  160. data/lib/ccls_engine/ccls_user.rb +117 -0
  161. data/lib/ccls_engine/core_extension.rb +14 -0
  162. data/lib/ccls_engine/date_and_time_formats.rb +30 -0
  163. data/lib/ccls_engine/factories.rb +880 -0
  164. data/lib/ccls_engine/factory_test_helper.rb +276 -0
  165. data/lib/ccls_engine/helper.rb +112 -0
  166. data/lib/ccls_engine/icf_master_tracker_update_test_helper.rb +121 -0
  167. data/lib/ccls_engine/live_birth_data_update_test_helper.rb +110 -0
  168. data/lib/ccls_engine/package_test_helper.rb +49 -0
  169. data/lib/ccls_engine/shared_database.rb +20 -0
  170. data/lib/ccls_engine/tasks.rb +1 -0
  171. data/lib/ccls_engine/test_tasks.rb +52 -0
  172. data/lib/ccls_engine/translation_table.rb +86 -0
  173. data/lib/shared_migration.rb +5 -0
  174. data/lib/surveyor/survey_extensions.rb +125 -0
  175. data/lib/tasks/application.rake +286 -0
  176. data/lib/tasks/calnet_authenticated.rake +6 -0
  177. data/lib/tasks/common_lib.rake +7 -0
  178. data/lib/tasks/database.rake +288 -0
  179. data/lib/tasks/documentation.rake +71 -0
  180. data/lib/tasks/homex_import.rake +723 -0
  181. data/lib/tasks/odms_import.rake +1116 -0
  182. data/lib/tasks/simply_authorized.rake +6 -0
  183. data/lib/tasks/ucb_ccls_engine_tasks.rake +4 -0
  184. data/lib/tasks/use_db.rake +4 -0
  185. data/rails/init.rb +4 -0
  186. data/test/unit/ccls/abstract_search_test.rb +150 -0
  187. data/test/unit/ccls/abstract_test.rb +674 -0
  188. data/test/unit/ccls/address_test.rb +155 -0
  189. data/test/unit/ccls/address_type_test.rb +25 -0
  190. data/test/unit/ccls/addressing_test.rb +466 -0
  191. data/test/unit/ccls/aliquot_sample_format_test.rb +20 -0
  192. data/test/unit/ccls/aliquot_test.rb +156 -0
  193. data/test/unit/ccls/analysis_test.rb +31 -0
  194. data/test/unit/ccls/bc_request_test.rb +43 -0
  195. data/test/unit/ccls/candidate_control_test.rb +712 -0
  196. data/test/unit/ccls/context_data_source_test.rb +26 -0
  197. data/test/unit/ccls/context_test.rb +40 -0
  198. data/test/unit/ccls/core_extension_test.rb +17 -0
  199. data/test/unit/ccls/county_test.rb +34 -0
  200. data/test/unit/ccls/data_source_test.rb +41 -0
  201. data/test/unit/ccls/diagnosis_test.rb +51 -0
  202. data/test/unit/ccls/document_type_test.rb +35 -0
  203. data/test/unit/ccls/document_version_test.rb +68 -0
  204. data/test/unit/ccls/enrollment_test.rb +575 -0
  205. data/test/unit/ccls/follow_up_test.rb +23 -0
  206. data/test/unit/ccls/follow_up_type_test.rb +34 -0
  207. data/test/unit/ccls/gift_card_search_test.rb +153 -0
  208. data/test/unit/ccls/gift_card_test.rb +40 -0
  209. data/test/unit/ccls/home_exposure_response_test.rb +83 -0
  210. data/test/unit/ccls/homex_outcome_test.rb +199 -0
  211. data/test/unit/ccls/hospital_test.rb +102 -0
  212. data/test/unit/ccls/icf_master_id_test.rb +30 -0
  213. data/test/unit/ccls/icf_master_tracker_change_test.rb +14 -0
  214. data/test/unit/ccls/icf_master_tracker_test.rb +132 -0
  215. data/test/unit/ccls/icf_master_tracker_update_test.rb +176 -0
  216. data/test/unit/ccls/ineligible_reason_test.rb +48 -0
  217. data/test/unit/ccls/instrument_test.rb +62 -0
  218. data/test/unit/ccls/instrument_type_test.rb +39 -0
  219. data/test/unit/ccls/instrument_version_test.rb +71 -0
  220. data/test/unit/ccls/interview_method_test.rb +44 -0
  221. data/test/unit/ccls/interview_outcome_test.rb +34 -0
  222. data/test/unit/ccls/interview_test.rb +298 -0
  223. data/test/unit/ccls/language_test.rb +47 -0
  224. data/test/unit/ccls/live_birth_data_update_test.rb +358 -0
  225. data/test/unit/ccls/operational_event_test.rb +187 -0
  226. data/test/unit/ccls/operational_event_type_test.rb +51 -0
  227. data/test/unit/ccls/organization_test.rb +64 -0
  228. data/test/unit/ccls/patient_test.rb +538 -0
  229. data/test/unit/ccls/person_test.rb +55 -0
  230. data/test/unit/ccls/phone_number_test.rb +244 -0
  231. data/test/unit/ccls/phone_type_test.rb +32 -0
  232. data/test/unit/ccls/project_outcome_test.rb +34 -0
  233. data/test/unit/ccls/project_test.rb +60 -0
  234. data/test/unit/ccls/race_test.rb +37 -0
  235. data/test/unit/ccls/refusal_reason_test.rb +52 -0
  236. data/test/unit/ccls/role_test.rb +26 -0
  237. data/test/unit/ccls/sample_kit_test.rb +35 -0
  238. data/test/unit/ccls/sample_outcome_test.rb +34 -0
  239. data/test/unit/ccls/sample_temperature_test.rb +25 -0
  240. data/test/unit/ccls/sample_test.rb +363 -0
  241. data/test/unit/ccls/sample_type_test.rb +58 -0
  242. data/test/unit/ccls/section_test.rb +34 -0
  243. data/test/unit/ccls/state_test.rb +31 -0
  244. data/test/unit/ccls/study_subject_abstracts_test.rb +115 -0
  245. data/test/unit/ccls/study_subject_addresses_test.rb +93 -0
  246. data/test/unit/ccls/study_subject_duplicates_test.rb +407 -0
  247. data/test/unit/ccls/study_subject_enrollments_test.rb +65 -0
  248. data/test/unit/ccls/study_subject_homex_outcome_test.rb +64 -0
  249. data/test/unit/ccls/study_subject_identifier_test.rb +439 -0
  250. data/test/unit/ccls/study_subject_interviews_test.rb +26 -0
  251. data/test/unit/ccls/study_subject_languages_test.rb +142 -0
  252. data/test/unit/ccls/study_subject_operational_events_test.rb +53 -0
  253. data/test/unit/ccls/study_subject_patient_test.rb +249 -0
  254. data/test/unit/ccls/study_subject_pii_test.rb +278 -0
  255. data/test/unit/ccls/study_subject_races_test.rb +203 -0
  256. data/test/unit/ccls/study_subject_search_test.rb +704 -0
  257. data/test/unit/ccls/study_subject_test.rb +770 -0
  258. data/test/unit/ccls/subject_language_test.rb +43 -0
  259. data/test/unit/ccls/subject_race_test.rb +35 -0
  260. data/test/unit/ccls/subject_relationship_test.rb +43 -0
  261. data/test/unit/ccls/subject_type_test.rb +40 -0
  262. data/test/unit/ccls/tracing_status_test.rb +32 -0
  263. data/test/unit/ccls/transfer_test.rb +81 -0
  264. data/test/unit/ccls/translation_table_test.rb +40 -0
  265. data/test/unit/ccls/unit_test.rb +21 -0
  266. data/test/unit/ccls/user_test.rb +156 -0
  267. data/test/unit/ccls/vital_status_test.rb +36 -0
  268. data/test/unit/ccls/zip_code_test.rb +55 -0
  269. metadata +633 -0
@@ -0,0 +1,1116 @@
1
+ require 'fastercsv'
2
+ require 'chronic'
3
+
4
+ #
5
+ # The purpose of these tasks is to import data extracted from the previous
6
+ # database tables. THEY ARE DESTRUCTIVE!
7
+ #
8
+ # This collection of rake tasks will only be used once. After its successful
9
+ # initial usage, I will comment it all out rather than destroy it so that it
10
+ # can be referenced.
11
+ #
12
+
13
+ BASEDIR = "/Volumes/BUF-Fileshare/SharedFiles/SoftwareDevelopment\(TBD\)/GrantApp/DataMigration/"
14
+ SUBJECTS_CSV = "#{BASEDIR}/ODMS_SubjectData_Combined_xxxxxx.csv"
15
+ ADDRESSES_CSV = "#{BASEDIR}/ODMS_Addresses_xxxxxx.csv"
16
+ ADDRESSINGS_CSV = "#{BASEDIR}/ODMS_Addressings_xxxxxx.csv"
17
+ PHONENUMBERS_CSV = "#{BASEDIR}/ODMS_Phone_Numbers_xxxxxx.csv"
18
+ EVENTS_CSV = "#{BASEDIR}/ODMS_Operational_Events_xxxxxx.csv"
19
+ ICFMASTERIDS_CSV = "#{BASEDIR}/export_ODMS_ICF_Master_IDs.csv"
20
+ ENROLLMENTS_CSV = "#{BASEDIR}/ODMS_Enrollments_xxxxxx.csv"
21
+
22
+ def format_date(date)
23
+ ( date.blank? ) ? nil : date.try(:strftime,"%m/%d/%Y")
24
+ end
25
+
26
+ def format_time_to_date(time)
27
+ ( time.blank? ) ? nil : format_date(Time.parse(time).to_date)
28
+ end
29
+
30
+ # gonna start asserting that everything is as expected.
31
+ # will slow down import, but I want to make sure I get it right.
32
+ def assert(expression,message = 'Assertion failed.')
33
+ raise "#{message} :\n #{caller[0]}" unless expression
34
+ end
35
+
36
+ # Object and not String because could be NilClass
37
+ Object.class_eval do
38
+ def nilify_blank
39
+ ( self.blank? ) ? nil : self
40
+ end
41
+ def to_nil_or_boolean
42
+ if self.blank?
43
+ nil
44
+ else
45
+ ( self.to_i == 1 or self.to_s.upcase == 'TRUE' ) ? true : false
46
+ end
47
+ end
48
+ def to_nil_or_yndk
49
+ if self.blank?
50
+ nil
51
+ else
52
+ ( self.upcase == 'TRUE' ) ? YNDK[:yes] : YNDK[:no]
53
+ end
54
+ end
55
+ def to_nil_or_i
56
+ ( self.blank? ) ? nil : self.to_i
57
+ end
58
+
59
+ # this is only used for a missing organization_id
60
+ # def to_dk_or_i
61
+ # ( self.blank? ) ? 9999999 : self.to_i
62
+ # end
63
+
64
+ def only_numeric
65
+ self.to_s.gsub(/\D/,'')
66
+ end
67
+ def to_nil_or_999_or_i
68
+ if self.blank?
69
+ nil
70
+ else
71
+ if self.to_s == '9'
72
+ 999
73
+ else
74
+ self.to_i
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ namespace :odms_destroy do
81
+
82
+ desc "Destroy subject and address data"
83
+ task :csv_data => :environment do
84
+ puts "Destroying existing data"
85
+ StudySubject.destroy_all
86
+ # subject_races? currently, there aren't any created
87
+ # subject_languages? currently, there aren't any created
88
+ Enrollment.destroy_all
89
+ Addressing.destroy_all
90
+ Address.destroy_all
91
+ PhoneNumber.destroy_all
92
+ Interview.destroy_all
93
+ Patient.destroy_all
94
+ Sample.destroy_all
95
+ SampleKit.destroy_all
96
+ HomexOutcome.destroy_all
97
+ HomeExposureResponse.destroy_all
98
+ OperationalEvent.destroy_all
99
+ # have to destroy these as well as they are associated with a given
100
+ # subject, all of which were just destroyed.
101
+ BcRequest.destroy_all
102
+ CandidateControl.destroy_all
103
+ IcfMasterId.destroy_all
104
+ end
105
+
106
+ end
107
+
108
+
109
+ namespace :odms_import do
110
+
111
+ #
112
+ # Generates subject_in.csv from Magee's input file.
113
+ # This file will need sorted before comparison.
114
+ #
115
+ #
116
+ # GONNA NEED TO SORT THESE TO COMPARE THEM, BUT BEWARE! OF MULTI-LINED ENTRIES
117
+ #
118
+ #
119
+ task :prepare_input_for_comparison => :environment do
120
+ # Some columns are quoted and some aren't. Quote all.
121
+ FasterCSV.open('subject_in.csv','w', {:force_quotes=>true}) do |out|
122
+ out.add_row ["subjectid","subject_type_id","vital_status_id","do_not_contact","sex","reference_date","childidwho","hispanicity_id","childid","icf_master_id","matchingid","familyid","patid","case_control_type","orderno","newid","studyid","related_case_childid","state_id_no","admit_date","diagnosis_id","created_at","first_name","middle_name","last_name","maiden_name","dob","died_on","mother_first_name","mother_maiden_name","mother_last_name","father_first_name","father_last_name","was_previously_treated","was_under_15_at_dx","raf_zip","raf_county","birth_year","hospital_no","organization_id","other_diagnosis"]
123
+
124
+ # DO NOT COMMENT OUT THE HEADER LINE OR IT RAISES CRYPTIC ERROR
125
+ (f=FasterCSV.open(SUBJECTS_CSV, 'rb',{ :headers => true })).each do |line|
126
+
127
+ # Not all input records have created_at so nillify all
128
+ line['created_at'] = nil
129
+
130
+ #
131
+ # Some dates are dates and some are strings so the format is different.
132
+ #
133
+ line['reference_date'] = format_time_to_date( line['reference_date'] )
134
+ line['admit_date'] = format_time_to_date( line['admit_date'] )
135
+ line['dob'] = format_time_to_date( line['dob'] )
136
+ line['died_on'] = format_time_to_date( line['died_on'] )
137
+
138
+
139
+ # TODO deal with incorrect value 9 in was_* fields
140
+ # if( line['was_previously_treated'].to_s == '9' )
141
+ # puts "Converting was_previously_treated = 9 to 999"
142
+ # puts line
143
+ # line['was_previously_treated'] = '999'
144
+ # puts line
145
+ # end
146
+ # if( line['was_under_15_at_dx'].to_s == '9' )
147
+ # puts "Converting was_under_15_at_dx = 9 to 999"
148
+ # puts line
149
+ # line['was_under_15_at_dx'] = '999'
150
+ # puts line
151
+ # end
152
+
153
+ # if line['subject_type_id'].to_i == StudySubject.subject_type_case_id &&
154
+ # line['organization_id'].blank?
155
+ #
156
+ ## # 1 record is missing organization_id so must do this.
157
+ ## m.organization_id = ( line['organization_id'].blank? ) ?
158
+ ## 999 : line['organization_id']
159
+ #
160
+ # line['organization_id'] = 999
161
+ # end
162
+
163
+ out.add_row line
164
+ end
165
+
166
+ end
167
+ end
168
+
169
+ #
170
+ # Generates a subject_out.csv file from data in the database.
171
+ #
172
+ #
173
+ # GONNA NEED TO SORT THESE TO COMPARE THEM
174
+ #
175
+ #
176
+ task :csv_dump => :environment do
177
+ puts "Dumping to csv for comparison"
178
+
179
+ FasterCSV.open('subject_out.csv','w', {:force_quotes=>true}) do |f|
180
+ f.add_row ["subjectid","subject_type_id","vital_status_id","do_not_contact","sex","reference_date","childidwho","hispanicity_id","childid","icf_master_id","matchingid","familyid","patid","case_control_type","orderno","newid","studyid","related_case_childid","state_id_no","admit_date","diagnosis_id","created_at","first_name","middle_name","last_name","maiden_name","dob","died_on","mother_first_name","mother_maiden_name","mother_last_name","father_first_name","father_last_name","was_previously_treated","was_under_15_at_dx","raf_zip","raf_county","birth_year","hospital_no","organization_id","other_diagnosis"]
181
+
182
+ StudySubject.find(:all,
183
+ :order => 'subjectid ASC' ).each do |s|
184
+
185
+ f.add_row([
186
+ s.subjectid,
187
+ s.subject_type_id,
188
+ s.vital_status_id,
189
+ s.do_not_contact.to_s.upcase, # FALSE
190
+ s.sex,
191
+ format_date(s.reference_date),
192
+ s.childidwho,
193
+ s.hispanicity_id,
194
+ s.childid,
195
+ s.icf_master_id,
196
+ s.matchingid,
197
+ s.familyid,
198
+ s.patid,
199
+ s.case_control_type,
200
+ s.orderno,
201
+ s.newid,
202
+ s.studyid,
203
+ s.related_case_childid,
204
+ s.state_id_no,
205
+ format_date(s.patient.try(:admit_date)),
206
+ s.patient.try(:diagnosis_id),
207
+ nil,
208
+ s.first_name,
209
+ s.middle_name,
210
+ s.last_name,
211
+ s.maiden_name,
212
+ format_date(s.dob),
213
+ format_date(s.died_on),
214
+ s.mother_first_name,
215
+ s.mother_maiden_name,
216
+ s.mother_last_name,
217
+ s.father_first_name,
218
+ s.father_last_name,
219
+ s.patient.try(:was_previously_treated),
220
+ s.patient.try(:was_under_15_at_dx),
221
+ s.patient.try(:raf_zip),
222
+ s.patient.try(:raf_county),
223
+ s.birth_year,
224
+ s.patient.try(:hospital_no),
225
+ s.patient.try(:organization_id),
226
+ s.patient.try(:other_diagnosis)
227
+ ])
228
+ end
229
+
230
+ end
231
+ end
232
+
233
+ desc "Import subject data from CSV files"
234
+ task :csv_data => [
235
+ 'odms_destroy:csv_data',
236
+ 'odms_import:subjects',
237
+ 'odms_import:icf_master_ids',
238
+ 'odms_import:enrollments',
239
+ 'odms_import:operational_events',
240
+ 'odms_import:phone_numbers',
241
+ 'odms_import:addresses',
242
+ 'odms_import:addressings',
243
+ # 'odms_import:create_dummy_candidate_controls',
244
+ 'ccls:data_report'
245
+ ]
246
+
247
+
248
+ task :addresses => :environment do
249
+ puts "Destroying addresses"
250
+ Address.destroy_all
251
+ puts "Importing addresses"
252
+
253
+ error_file = File.open('addresses_errors.txt','w') # overwrite existing
254
+
255
+ # DO NOT COMMENT OUT THE HEADER LINE OR IT RAISES CRYPTIC ERROR
256
+ (f=FasterCSV.open(ADDRESSES_CSV, 'rb',{ :headers => true })).each do |line|
257
+ puts "Processing line #{f.lineno}"
258
+ puts line
259
+
260
+ #"address_type_id","data_source_id","line_1","unit","city","state","zip","external_address_id","county","country","created_at"
261
+
262
+ address = Address.create({
263
+ :address_type_id => line["address_type_id"],
264
+ :data_source_id => line["data_source_id"],
265
+ :line_1 => line["line_1"],
266
+ :unit => line["unit"],
267
+ :city => line["city"],
268
+ :state => line["state"],
269
+ :zip => line["zip"],
270
+ :external_address_id => line["external_address_id"],
271
+ :county => line["county"],
272
+ :country => line["country"],
273
+ :created_at => (( line['created_at'].blank? ) ?
274
+ nil : Time.parse(line['created_at']) )
275
+ })
276
+
277
+ if address.new_record?
278
+ error_file.puts
279
+ error_file.puts "Line #:#{f.lineno}: #{address.errors.full_messages.to_sentence}"
280
+ error_file.puts line
281
+ error_file.puts
282
+ else
283
+ address.reload
284
+ assert address.address_type_id == line["address_type_id"].to_nil_or_i,
285
+ 'Address Type mismatch'
286
+ assert address.data_source_id == line["data_source_id"].to_nil_or_i,
287
+ 'Data Source mismatch'
288
+ assert address.line_1 == line["line_1"],
289
+ 'Line 1 mismatch'
290
+ assert address.line_2.blank?
291
+ 'Line 2 mismatch'
292
+ assert address.unit == line["unit"],
293
+ 'Unit mismatch'
294
+ assert address.city == line["city"],
295
+ 'City mismatch'
296
+ assert address.state == line["state"],
297
+ 'State mismatch'
298
+ assert address.zip.only_numeric == line["zip"].only_numeric,
299
+ 'Zip mismatch'
300
+ assert address.external_address_id == line["external_address_id"].to_nil_or_i,
301
+ 'External Address mismatch'
302
+ assert address.county == line["county"],
303
+ 'County mismatch'
304
+ assert address.country == line["country"],
305
+ 'Country mismatch'
306
+ end
307
+
308
+ end
309
+ error_file.close
310
+ end
311
+
312
+ task :addressings => :environment do
313
+ puts "Destroying addressings"
314
+ Addressing.destroy_all
315
+ puts "Importing addressings"
316
+
317
+ error_file = File.open('addressings_errors.txt','w') # overwrite existing
318
+
319
+ # DO NOT COMMENT OUT THE HEADER LINE OR IT RAISES CRYPTIC ERROR
320
+ (f=FasterCSV.open( ADDRESSINGS_CSV, 'rb',{ :headers => true })).each do |line|
321
+ puts "Processing line #{f.lineno}"
322
+ puts line
323
+
324
+ #"subjectid","external_address_id","current_address","address_at_diagnosis","valid_from","valid_to","data_source_id","created_at"
325
+
326
+
327
+ if line['subjectid'].blank?
328
+ error_file.puts
329
+ error_file.puts "Line #:#{f.lineno}: subjectid blank."
330
+ error_file.puts line
331
+ error_file.puts
332
+ next
333
+ end
334
+ study_subject = StudySubject.find_by_subjectid(line['subjectid'])
335
+ unless study_subject
336
+ error_file.puts
337
+ error_file.puts "Line #:#{f.lineno}: subjectid #{line['subjectid']} not found."
338
+ error_file.puts line
339
+ error_file.puts
340
+ next
341
+ end
342
+
343
+ address = Address.find_by_external_address_id(line['external_address_id'])
344
+ unless address
345
+ error_file.puts
346
+ error_file.puts "Line #:#{f.lineno}: address with external id #{line['external_address_id']} not found."
347
+ error_file.puts line
348
+ error_file.puts
349
+ next
350
+ end
351
+
352
+ # addressing = Addressing.create({
353
+ # study_subject_id is attr_protected
354
+ # :study_subject_id => study_subject.id,
355
+ addressing = study_subject.addressings.create({
356
+ :address_id => address.id,
357
+ :current_address => line["current_address"], # yndk integer
358
+ :address_at_diagnosis => line["address_at_diagnosis"], # yndk integer
359
+ :valid_from => (( line['valid_from'].blank? ) ?
360
+ nil : Time.parse(line['valid_from']).to_date ),
361
+ :valid_to => (( line['valid_to'].blank? ) ?
362
+ nil : Time.parse(line['valid_to']).to_date ),
363
+ :data_source_id => line["data_source_id"],
364
+ :created_at => (( line['created_at'].blank? ) ?
365
+ nil : Time.parse(line['created_at']) )
366
+ })
367
+
368
+ if addressing.new_record?
369
+ error_file.puts
370
+ error_file.puts "Line #:#{f.lineno}: #{addressing.errors.full_messages.to_sentence}"
371
+ error_file.puts line
372
+ error_file.puts
373
+ else
374
+ addressing.reload
375
+ assert addressing.study_subject_id == study_subject.id,
376
+ 'Study Subject mismatch'
377
+ assert addressing.address_id == address.id,
378
+ 'Address mismatch'
379
+ assert addressing.current_address == line["current_address"].to_nil_or_i,
380
+ 'Current Address mismatch'
381
+ assert addressing.address_at_diagnosis == line["address_at_diagnosis"].to_nil_or_i,
382
+ 'Address at Diagnosis mismatch'
383
+ assert addressing.data_source_id == line["data_source_id"].to_nil_or_i,
384
+ 'Data Source mismatch'
385
+ if line['valid_from'].blank?
386
+ assert addressing.valid_from.nil?, 'Valid From not nil'
387
+ else
388
+ assert !addressing.valid_from.nil?, 'Valid From is nil'
389
+ assert addressing.valid_from == Time.parse(line['valid_from']).to_date,
390
+ "Valid From mismatch"
391
+ end
392
+ if line['valid_to'].blank?
393
+ assert addressing.valid_to.nil?, 'Valid To not nil'
394
+ else
395
+ assert !addressing.valid_to.nil?, 'Valid To is nil'
396
+ assert addressing.valid_to == Time.parse(line['valid_to']).to_date,
397
+ "Valid To mismatch"
398
+ end
399
+ end
400
+
401
+ end
402
+ error_file.close
403
+ end
404
+
405
+ task :phone_numbers => :environment do
406
+ puts "Destroying phone_numbers"
407
+ PhoneNumber.destroy_all
408
+ puts "Importing phone_numbers"
409
+
410
+ error_file = File.open('phone_numbers_errors.txt','w') # overwrite existing
411
+
412
+ # DO NOT COMMENT OUT THE HEADER LINE OR IT RAISES CRYPTIC ERROR
413
+ (f=FasterCSV.open(PHONENUMBERS_CSV, 'rb',{ :headers => true })).each do |line|
414
+ puts "Processing line #{f.lineno}"
415
+ puts line
416
+
417
+ #"subjectid","data_source_id","external_address_id","created_at","phone_number","is_primary","current_phone","phone_type_id"
418
+
419
+ if line['subjectid'].blank?
420
+ error_file.puts
421
+ error_file.puts "Line #:#{f.lineno}: subjectid blank."
422
+ error_file.puts line
423
+ error_file.puts
424
+ next
425
+ end
426
+ study_subject = StudySubject.find_by_subjectid(line['subjectid'])
427
+ unless study_subject
428
+ error_file.puts
429
+ error_file.puts "Line #:#{f.lineno}: subjectid #{line['subjectid']} not found."
430
+ error_file.puts line
431
+ error_file.puts
432
+ next
433
+ end
434
+
435
+ phone_number = study_subject.phone_numbers.create({
436
+ # phone_number = PhoneNumber.create({
437
+ # study_subject_id is attr_protected
438
+ # :study_subject_id => study_subject.id,
439
+ :phone_type_id => line["phone_type_id"],
440
+ :data_source_id => line["data_source_id"],
441
+ :phone_number => line["phone_number"],
442
+ :is_primary => line["is_primary"], # boolean
443
+ :current_phone => line["current_phone"], # yndk integer
444
+ # :current_phone => line["current_phone"].to_nil_or_yndk,
445
+ :created_at => (( line['created_at'].blank? ) ?
446
+ nil : Time.parse(line['created_at']) )
447
+ })
448
+
449
+ if phone_number.new_record?
450
+ error_file.puts
451
+ error_file.puts "Line #:#{f.lineno}: #{phone_number.errors.full_messages.to_sentence}"
452
+ error_file.puts line
453
+ error_file.puts
454
+ else
455
+ phone_number.reload
456
+ assert phone_number.study_subject_id == study_subject.id,
457
+ "Study Subject mismatch"
458
+ assert phone_number.phone_type_id == line["phone_type_id"].to_nil_or_i,
459
+ "phone_type_id mismatch:#{phone_number.phone_type_id}:#{line["phone_type_id"]}:"
460
+ assert phone_number.data_source_id == line["data_source_id"].to_nil_or_i,
461
+ "data_source_id mismatch:#{phone_number.data_source_id}:#{line["data_source_id"]}:"
462
+ # import will change format of phone number (adds () and - )
463
+ assert phone_number.phone_number.only_numeric == line["phone_number"].only_numeric,
464
+ "phone_number mismatch:#{phone_number.phone_number}:#{line["phone_number"]}:"
465
+ # assert phone_number.current_phone == line["current_phone"].to_nil_or_yndk,
466
+ assert phone_number.current_phone == line["current_phone"].to_nil_or_i,
467
+ "current_phone mismatch:#{phone_number.current_phone}:#{line["current_phone"]}:"
468
+ assert phone_number.is_primary == line["is_primary"].to_nil_or_boolean,
469
+ "is_primary mismatch:#{phone_number.is_primary}:#{line["is_primary"]}:"
470
+ end
471
+
472
+ end
473
+ error_file.close
474
+ end
475
+
476
+ task :operational_events => :environment do
477
+ # Can't destroy them as there will be some already
478
+ # Actually, this seems to include the subject creation event
479
+ # so destruction may be just fine.
480
+ # puts "Destroying operational_events"
481
+ # OperationalEvent.destroy_all
482
+ puts "Importing operational_events"
483
+
484
+ error_file = File.open('operational_events_errors.txt','w') # overwrite existing
485
+
486
+ # DO NOT COMMENT OUT THE HEADER LINE OR IT RAISES CRYPTIC ERROR
487
+ (f=FasterCSV.open(EVENTS_CSV, 'rb',{ :headers => true })).each do |line|
488
+ puts "Processing line #{f.lineno}"
489
+ puts line
490
+
491
+ #"subjectID","project_id","operational_event_id","occurred_on","description","enrollment_id","event_notes"
492
+
493
+ study_subject = StudySubject.find_by_subjectid(line['subjectID']) # misnamed field
494
+ unless study_subject
495
+ error_file.puts
496
+ error_file.puts "Line #:#{f.lineno}: subjectid #{line['subjectID']} not found."
497
+ error_file.puts line
498
+ error_file.puts
499
+ next
500
+ end
501
+
502
+ ccls_enrollment = study_subject.enrollments.find_by_project_id(line['project_id'])
503
+ operational_event = OperationalEvent.create({
504
+ :enrollment_id => ccls_enrollment.id,
505
+ :operational_event_type_id => line['operational_event_id'], # NOTE misnamed field
506
+ :occurred_on => Time.parse(line['occurred_on']).to_date,
507
+ :description => line['description'],
508
+ :event_notes => line['event_notes']
509
+ })
510
+ if operational_event.new_record?
511
+ error_file.puts
512
+ error_file.puts "Line #:#{f.lineno}: #{operational_event.errors.full_messages.to_sentence}"
513
+ error_file.puts line
514
+ error_file.puts
515
+ else
516
+ operational_event.reload
517
+ assert operational_event.enrollment_id == ccls_enrollment.id,
518
+ "Enrollment mismatch"
519
+ assert operational_event.operational_event_type_id == line['operational_event_id'].to_nil_or_i,
520
+ "operational_event_type mismatch:#{operational_event.operational_event_type_id}:#{line["operational_event_id"]}:"
521
+ assert operational_event.occurred_on == Time.parse(line['occurred_on']).to_date,
522
+ "occurred_on mismatch:#{operational_event.occurred_on}:#{line["occurred_on"]}:"
523
+ assert operational_event.description == line['description'],
524
+ "description mismatch:#{operational_event.description}:#{line["description"]}:"
525
+ assert operational_event.event_notes == line['event_notes'],
526
+ "event_notes mismatch:#{operational_event.event_notes}:#{line["event_notes"]}:"
527
+ end
528
+ end
529
+ error_file.close
530
+ end
531
+
532
+ task :icf_master_ids => :environment do
533
+ puts "Destroying icf_master_ids"
534
+ IcfMasterId.destroy_all
535
+ puts "Importing icf_master_ids"
536
+
537
+ # DO NOT COMMENT OUT THE HEADER LINE OR IT RAISES CRYPTIC ERROR
538
+ (f=FasterCSV.open(ICFMASTERIDS_CSV, 'rb',{ :headers => true })).each do |line|
539
+ puts "Processing line #{f.lineno}"
540
+ puts line
541
+
542
+ raise "Given icf_master_id is blank?" if line['icf_master_id'].blank?
543
+
544
+ attributes = { :icf_master_id => line['icf_master_id'] }
545
+
546
+
547
+
548
+
549
+ #
550
+ # subjectid is unique so this should NEVER happen
551
+ #
552
+ if line['subjectid'] and !line['subjectid'].blank?
553
+ study_subjects = StudySubject.find(:all,
554
+ :conditions => { :subjectid => line['subjectid'] } )
555
+ case
556
+ when study_subjects.length > 1
557
+ raise "More than one study_subject found matching subjectid:#{line['subjectid']}:"
558
+ when study_subjects.length == 0
559
+ raise "No study_subject found matching subjectid:#{line['subjectid']}:"
560
+ else
561
+ puts "Found study_subject matching subjectid:#{line['subjectid']}:"
562
+ end
563
+ study_subject = study_subjects.first
564
+
565
+
566
+
567
+
568
+
569
+
570
+ # Fortunately, these never happen
571
+ if study_subject.icf_master_id.blank?
572
+ # assign it?
573
+ raise "ICF Master ID isn't actually set in the StudySubject!"
574
+ else
575
+ # different?
576
+ if study_subject.icf_master_id != line['icf_master_id']
577
+ raise "ICF Master ID is different than that set in the StudySubject!\n" <<
578
+ "#{study_subject.icf_master_id}:#{line['icf_master_id']}"
579
+ end
580
+ end
581
+
582
+
583
+ attributes[:study_subject_id] = study_subject.id
584
+ attributes[:assigned_on] = Time.parse(line['assigned_on'])
585
+ else
586
+ # I just noticed that some of the icf_master_ids are actually
587
+ # assigned in the subject data, but not marked as being
588
+ # assigned in the icf_master_id list. So, search for them.
589
+ study_subjects = StudySubject.find(:all,
590
+ :conditions => { :icf_master_id => line['icf_master_id'] } )
591
+ case
592
+ #
593
+ # icf_master_id is unique, so should NEVER find more than 1 unless it is nil.
594
+ #
595
+ when study_subjects.length > 1
596
+ raise "More than one study_subject found matching icf_master_id:#{line['icf_master_id']}:"
597
+ # when study_subjects.length == 0
598
+ # raise "No study_subject found matching icf_master_id:#{line['icf_master_id']}:"
599
+ when study_subjects.length == 1
600
+ puts "Found study_subject matching icf_master_id:#{line['icf_master_id']}:"
601
+ attributes[:study_subject_id] = study_subjects.first.id
602
+ attributes[:assigned_on] = Date.today
603
+ end
604
+ end
605
+
606
+ IcfMasterId.create!(attributes)
607
+ end
608
+
609
+ end
610
+
611
+
612
+ # task :create_dummy_candidate_controls => :environment do
613
+ ## puts "Destroying candidate controls"
614
+ ## CandidateControl.destroy_all
615
+ # puts "Creating dummy candidate controls"
616
+ # SubjectType['Case'].study_subjects.each do |s|
617
+ # rand(5).times do |i|
618
+ # puts "Creating candidate control for study_subject_id:#{s.id}"
619
+ # CandidateControl.create!({
620
+ # :related_patid => s.patid,
621
+ # :first_name => "First#{i}",
622
+ # :last_name => "Last#{s.id}",
623
+ # :sex => ['M','F'][rand(2)],
624
+ # :dob => Date.jd(2440000+rand(15000))
625
+ # })
626
+ # end
627
+ # end
628
+ #
629
+ # printf "%-19s %5d\n", "CandidateControl.count:", CandidateControl.count
630
+ # end
631
+
632
+ desc "Import data from enrollments.csv file"
633
+ task :enrollments => :environment do
634
+ puts "Importing enrollments"
635
+
636
+ # error_file = File.open('enrollments_errors.txt','a') # append existing
637
+ error_file = File.open('enrollments_errors.txt','w') # overwrite existing
638
+
639
+ # DO NOT COMMENT OUT THE HEADER LINE OR IT RAISES CRYPTIC ERROR
640
+ (f=FasterCSV.open(ENROLLMENTS_CSV, 'rb',{ :headers => true })).each do |line|
641
+
642
+ # skip until ...
643
+ # next if f.lineno <= 10619
644
+
645
+ puts "Processing line #{f.lineno}"
646
+ puts line
647
+
648
+ # Don't need all of this and don't know exactly what to do with the DeclineReasons
649
+ # also is_eligible changed and ineligible_reason_id added
650
+ #"subjectType-donotimprot","ChildId","project_id","subjectID","consented","consented_on","tPatientInfo_DeclineReason","tlDeclineReasons_DeclineReason","refusal_reason_id","document_version_id","is_eligible","ineligible_reason_id"
651
+
652
+ if line['subjectID'].blank?
653
+ error_file.puts
654
+ error_file.puts "Line #:#{f.lineno}: subjectid blank."
655
+ error_file.puts line
656
+ error_file.puts
657
+ next
658
+ end
659
+ study_subject = StudySubject.find_by_subjectid(line['subjectID']) # misnamed field
660
+ unless study_subject
661
+ error_file.puts
662
+ error_file.puts "Line #:#{f.lineno}: subjectid #{line['subjectID']} not found."
663
+ error_file.puts line
664
+ error_file.puts
665
+ next
666
+ end
667
+
668
+ enrollment = study_subject.enrollments.find_or_create_by_project_id(
669
+ line['project_id'])
670
+
671
+ # TEMPORARY "FIXES" to get most enrollments imported
672
+
673
+ consented = line['consented']
674
+ consented_on = (( line['consented_on'].blank? ) ?
675
+ nil : Time.parse(line['consented_on']).to_date )
676
+ # consented_on = if [nil,999,'','999'].include?(consented)
677
+ # nil
678
+ # else
679
+ # (( line['consented_on'].blank? ) ?
680
+ # nil : Time.parse(line['consented_on']).to_date )
681
+ # end
682
+ refusal_reason_id = line['refusal_reason_id']
683
+ # refusal_reason_id = if consented.to_i == 2
684
+ # line['refusal_reason_id']
685
+ # else
686
+ # nil
687
+ # end
688
+ document_version_id = line['document_version_id']
689
+ # document_version_id = if [nil,999,'','999'].include?(consented)
690
+ # nil
691
+ # else
692
+ # line['document_version_id']
693
+ # end
694
+
695
+ # END TEMPORARY "FIXES" to get most enrollments imported
696
+
697
+ saved = enrollment.update_attributes(
698
+ :consented => consented,
699
+ :consented_on => consented_on,
700
+ :refusal_reason_id => refusal_reason_id,
701
+ # :other_refusal_reason => line['tlDeclineReasons_DeclineReason'],
702
+
703
+
704
+ # TODO
705
+ # :document_version_id => document_version_id,
706
+
707
+
708
+
709
+ :is_eligible => line['is_eligible'],
710
+ :ineligible_reason_id => line['ineligible_reason_id']
711
+ )
712
+ unless saved
713
+ error_file.puts
714
+ error_file.puts "Line #:#{f.lineno}: #{enrollment.errors.full_messages.to_sentence}"
715
+ error_file.puts line
716
+ error_file.puts enrollment.inspect
717
+ error_file.puts
718
+ else
719
+ enrollment.reload
720
+ assert enrollment.consented == line['consented'].to_nil_or_i,
721
+ "consented mismatch:#{enrollment.consented}:#{line["consented"]}:"
722
+ assert enrollment.consented_on == consented_on,
723
+ "consented_on mismatch:#{enrollment.consented_on}:#{line["consented_on"]}:"
724
+ assert enrollment.refusal_reason_id == refusal_reason_id.to_nil_or_i,
725
+ "refusal_reason_id mismatch:#{enrollment.refusal_reason_id}:#{line["refusal_reason_id"]}:"
726
+
727
+
728
+ # TODO
729
+ # assert enrollment.document_version_id == document_version_id.to_nil_or_i,
730
+ # "document_version_id mismatch:#{enrollment.document_version_id}:#{line["document_version_id"]}:"
731
+
732
+
733
+ assert enrollment.is_eligible == line['is_eligible'].to_nil_or_i,
734
+ "is_eligible mismatch:#{enrollment.is_eligible}:#{line['is_eligible']}:"
735
+ assert enrollment.ineligible_reason_id == line['ineligible_reason_id'].to_nil_or_i,
736
+ "ineligible_reason_id mismatch:#{enrollment.ineligible_reason_id}:#{line["ineligible_reason_id"]}:"
737
+ end
738
+
739
+ end
740
+ error_file.close
741
+ end
742
+
743
+
744
+ desc "Import data from subjects.csv file"
745
+ task :subjects => :environment do
746
+ puts "Importing subjects"
747
+
748
+ # error_file = File.open('subjects_errors.txt','a') # append existing
749
+ error_file = File.open('subjects_errors.txt','w') # overwrite existing
750
+
751
+ # DO NOT COMMENT OUT THE HEADER LINE OR IT RAISES CRYPTIC ERROR
752
+ (f=FasterCSV.open(SUBJECTS_CSV, 'rb',{ :headers => true })).each do |line|
753
+
754
+ # skip until ...
755
+ # next if f.lineno <= 10619
756
+
757
+ puts "Processing line #{f.lineno}"
758
+ puts line
759
+
760
+ #"subjectid","subject_type_id","vital_status_id","do_not_contact","sex","reference_date","childidwho","hispanicity_id","childid","icf_master_id","matchingid","familyid","patid","case_control_type","orderno","newid","studyid","related_case_childid","state_id_no","admit_date","diagnosis_id","created_at","first_name","middle_name","last_name","maiden_name","dob","died_on","mother_first_name","mother_maiden_name","mother_last_name","father_first_name","father_last_name","was_previously_treated","was_under_15_at_dx","raf_zip","raf_county","birth_year","hospital_no","organization_id","other_diagnosis","father_hispanicity_id","mother_hispanicity_id"
761
+
762
+
763
+
764
+ #
765
+ # Models built in block mode to avoid protected attributes
766
+ #
767
+
768
+ s = StudySubject.new do |x|
769
+ x.subject_type_id = line['subject_type_id']
770
+ x.hispanicity_id = line['hispanicity_id']
771
+ x.father_hispanicity_id = line['father_hispanicity_id']
772
+ x.mother_hispanicity_id = line['mother_hispanicity_id']
773
+ #
774
+ # do_not_contact is a boolean string in the csv file.
775
+ # It does seem to convert correctly in the database.
776
+ x.do_not_contact = line['do_not_contact']
777
+
778
+ x.sex = line['sex']
779
+ x.reference_date = ( line['reference_date'].blank?
780
+ ) ? nil : Time.parse(line['reference_date'])
781
+
782
+ x.birth_year = line['birth_year']
783
+ x.first_name = line['first_name']
784
+ x.middle_name = line['middle_name']
785
+ x.last_name = line['last_name']
786
+ x.maiden_name = line['maiden_name']
787
+ x.died_on = ( line['died_on'].blank?
788
+ ) ? nil : Time.parse(line['died_on'])
789
+ x.mother_first_name = line['mother_first_name']
790
+ x.mother_maiden_name = line['mother_maiden_name']
791
+ x.mother_last_name = line['mother_last_name']
792
+ x.father_first_name = line['father_first_name']
793
+ x.father_last_name = line['father_last_name']
794
+
795
+ x.dob = ( line['dob'].blank?
796
+ ) ? nil : Time.parse(line['dob']).to_date
797
+
798
+ x.subjectid = line['subjectid']
799
+ x.childid = line['childid']
800
+ x.childidwho = line['childidwho']
801
+ x.icf_master_id = line['icf_master_id']
802
+ x.matchingid = line['matchingid']
803
+ x.familyid = line['familyid']
804
+ x.patid = line['patid']
805
+ x.orderno = line['orderno']
806
+ x.newid = line['newid']
807
+ x.studyid = line['studyid']
808
+ x.state_id_no = line['state_id_no']
809
+ x.case_control_type = line['case_control_type']
810
+ x.related_case_childid = line['related_case_childid']
811
+ x.created_at = line['created_at']
812
+
813
+ unless line['vital_status_id'].blank?
814
+ x.vital_status_id = line['vital_status_id']
815
+ # else leave as database default
816
+ end
817
+ end
818
+
819
+ if line['subject_type_id'].to_i == StudySubject.subject_type_case_id
820
+ patient = Patient.new do |m|
821
+ m.admit_date = ( line['admit_date'].blank?
822
+ ) ? nil : Time.parse(line['admit_date'])
823
+ m.diagnosis_id = line['diagnosis_id']
824
+ m.other_diagnosis = line['other_diagnosis']
825
+
826
+
827
+
828
+
829
+ # 1 record is missing organization_id so must do this. (9999999)
830
+ # m.organization_id = line['organization_id'].to_dk_or_i
831
+ m.organization_id = line['organization_id']
832
+
833
+
834
+
835
+
836
+
837
+ m.hospital_no = line['hospital_no']
838
+
839
+ # TODO deal with incorrect value 9 in was_* fields
840
+
841
+ m.was_previously_treated = line['was_previously_treated'].to_nil_or_999_or_i
842
+ # m.was_previously_treated = line['was_previously_treated']
843
+ # kinda pointless as is set in callback
844
+ # m.was_under_15_at_dx = line['was_under_15_at_dx'].to_nil_or_999_or_i
845
+ m.was_under_15_at_dx = line['was_under_15_at_dx']
846
+
847
+ m.raf_zip = line['raf_zip']
848
+ m.raf_county = line['raf_county']
849
+ m.created_at = line['created_at']
850
+ end
851
+ s.patient = patient
852
+ end
853
+ s.save
854
+
855
+ if s.new_record?
856
+ error_file.puts
857
+ error_file.puts "Line #:#{f.lineno}: #{s.errors.full_messages.to_sentence}"
858
+ error_file.puts line
859
+ error_file.puts
860
+ else
861
+ s.reload
862
+ compare_subject_and_line(s,line)
863
+ end
864
+ end # FasterCSV.open
865
+ error_file.close
866
+ end # task :subjects => :environment do
867
+
868
+ end # namespace :odms_import do
869
+
870
+ namespace :odms_compare do
871
+ desc "Compare data from subjects.csv file"
872
+ task :subjects => :environment do
873
+ puts "Comparing subjects"
874
+ warn_file = File.open('subjects_warnings.txt','w') # overwrite existing
875
+ # DO NOT COMMENT OUT THE HEADER LINE OR IT RAISES CRYPTIC ERROR
876
+ (f=FasterCSV.open(SUBJECTS_CSV, 'rb',{ :headers => true })).each do |line|
877
+ puts "Processing line #{f.lineno}"
878
+ puts line
879
+
880
+ s = StudySubject.find_by_subjectid(line['subjectid'])
881
+ if s
882
+ compare_subject_and_line(s,line,warn_file)
883
+ else
884
+ warn_file.puts "Subject not found with subjectid:#{line['subjectid']}"
885
+ warn_file.puts
886
+ end
887
+
888
+ end # FasterCSV.open
889
+ warn_file.close
890
+ end # task :subjects => :environment do
891
+ end # namespace :odms_compare do
892
+
893
+ def compare_subject_and_line(s,line,warn_file=nil)
894
+ #
895
+ # TODO Add a "warnings" file containing some of these changes?
896
+ # Some may actually occur on the import of another subject though.
897
+ # Would have to loop to loop through the csv file again to actually compare.
898
+ #
899
+
900
+ assert s.subject_type_id == line['subject_type_id'].to_nil_or_i,
901
+ "subject_type_id mismatch:#{s.subject_type_id}:#{line['subject_type_id']}:"
902
+
903
+ if line['vital_status_id'].blank?
904
+ assert s.vital_status_id == 1,
905
+ "Vital Status not set to default"
906
+ else
907
+ assert s.vital_status_id.to_s == line['vital_status_id'],
908
+ "Vital Status mismatch:#{s.vital_status_id}:#{line['vital_status_id']}:"
909
+ end
910
+
911
+ # TODO TRUE / FALSE
912
+ assert s.do_not_contact == line['do_not_contact'].to_nil_or_boolean,
913
+ 'Do Not Contact mismatch'
914
+ assert s.sex == line['sex'],
915
+ "sex mismatch:#{s.sex}:#{line['sex']}:"
916
+ assert s.hispanicity_id == line['hispanicity_id'].to_nil_or_i,
917
+ "hispanicity_id mismatch:#{s.hispanicity_id}:#{line['hispanicity_id']}:"
918
+ assert s.mother_hispanicity_id == line['mother_hispanicity_id'].to_nil_or_i,
919
+ "mother_hispanicity_id mismatch:#{s.mother_hispanicity_id}:#{line['mother_hispanicity_id']}:"
920
+ assert s.father_hispanicity_id == line['father_hispanicity_id'].to_nil_or_i,
921
+ "father_hispanicity_id mismatch:#{s.father_hispanicity_id}:#{line['father_hispanicity_id']}:"
922
+
923
+ # TODO not always be true due to callbacks
924
+ # if line['reference_date'].blank?
925
+ # assert s.reference_date.nil?, 'reference_date not nil'
926
+ # else
927
+ # assert !s.reference_date.nil?, 'reference_date nil'
928
+ # assert s.reference_date == Time.parse(line['reference_date']),
929
+ # "reference_date mismatch:#{s.reference_date}:#{line['reference_date']}:"
930
+ # end
931
+
932
+ unless warn_file.nil?
933
+
934
+ # reference_date is changed to Patient#admit_date for all matching matchingid
935
+ # when matchingid or admit_date changes
936
+ # FYI ... During import, the case may not exist yet.
937
+ matching_case = if s.is_case?
938
+ s
939
+ else
940
+ matching_cases = StudySubject.find(:all, # should only be one
941
+ :conditions => {
942
+ :subject_type_id => StudySubject.subject_type_case_id,
943
+ :matchingid => s.matchingid
944
+ })
945
+ # still in testing so there isn't always one
946
+ raise "There can be only One!" if matching_cases.length > 1
947
+ # raise "There must be One!" if matching_cases.length < 1
948
+ ( matching_cases.length == 1 ) ? matching_cases[0] : nil
949
+ end
950
+
951
+ if line['reference_date'].blank?
952
+ if !s.reference_date.nil?
953
+ warn_file.puts s.inspect
954
+ warn_file.puts "-reference_date not nil:"
955
+ warn_file.puts "-reference_date csv :#{line['reference_date']}:"
956
+ warn_file.puts "-reference_date db :#{s.reference_date}:"
957
+ if matching_case
958
+ warn_file.puts "-case admit_date :#{matching_case.admit_date}:"
959
+ else
960
+ warn_file.puts "-case admit_date :no case found:"
961
+ end
962
+ warn_file.puts
963
+ end
964
+ else
965
+ if s.reference_date != Time.parse(line['reference_date']).to_date
966
+ warn_file.puts s.inspect
967
+ warn_file.puts "-reference_date mismatch:"
968
+ warn_file.puts "-reference_date csv :#{line['reference_date']}:"
969
+ warn_file.puts "-reference_date db :#{s.reference_date}:"
970
+ if matching_case
971
+ warn_file.puts "-case admit_date :#{matching_case.admit_date}:"
972
+ else
973
+ warn_file.puts "-case admit_date :no case found:"
974
+ end
975
+ warn_file.puts
976
+ end
977
+ end
978
+ end
979
+
980
+ assert s.first_name == line['first_name'],
981
+ "first_name mismatch:#{s.first_name}:#{line['first_name']}:"
982
+ assert s.middle_name == line['middle_name'],
983
+ "middle_name mismatch:#{s.middle_name}:#{line['middle_name']}:"
984
+ assert s.last_name == line['last_name'],
985
+ "last_name mismatch:#{s.last_name}:#{line['last_name']}:"
986
+ assert s.maiden_name == line['maiden_name'],
987
+ "maiden_name mismatch:#{s.maiden_name}:#{line['maiden_name']}:"
988
+
989
+ if line['dob'].blank?
990
+ assert s.dob.nil?, 'dob not nil'
991
+ else
992
+ assert !s.dob.nil?, 'dob nil'
993
+ assert s.dob == Time.parse(line['dob']).to_date,
994
+ "dob mismatch:#{s.dob}:#{line['dob']}:"
995
+ end
996
+ if line['died_on'].blank?
997
+ assert s.died_on.nil?, 'died_on not nil'
998
+ else
999
+ assert !s.died_on.nil?, 'died_on nil'
1000
+ assert s.died_on == Time.parse(line['died_on']).to_date,
1001
+ "died_on mismatch:#{s.died_on}:#{line['died_on']}:"
1002
+ end
1003
+
1004
+ assert s.mother_first_name == line['mother_first_name'],
1005
+ "mother_first_name mismatch:#{s.mother_first_name}:#{line['mother_first_name']}:"
1006
+ assert s.mother_maiden_name == line['mother_maiden_name'],
1007
+ "mother_maiden_name mismatch:#{s.mother_maiden_name}:#{line['mother_maiden_name']}:"
1008
+ assert s.mother_last_name == line['mother_last_name'],
1009
+ "mother_last_name mismatch:#{s.mother_last_name}:#{line['mother_last_name']}:"
1010
+ assert s.father_first_name == line['father_first_name'],
1011
+ "father_first_name mismatch:#{s.father_first_name}:#{line['father_first_name']}:"
1012
+ assert s.father_last_name == line['father_last_name'],
1013
+ "father_last_name mismatch:#{s.father_last_name}:#{line['father_last_name']}:"
1014
+ assert s.birth_year == line['birth_year'],
1015
+ "birth_year mismatch:#{s.birth_year}:#{line['birth_year']}:"
1016
+
1017
+
1018
+ pa = s.patient
1019
+ if s.subject_type == SubjectType['case']
1020
+ pa.reload
1021
+
1022
+ # TODO may not always be true
1023
+ if line['admit_date'].blank?
1024
+ assert pa.admit_date.nil?, 'admit_date not nil'
1025
+ else
1026
+ assert !pa.admit_date.nil?, 'admit_date nil'
1027
+ assert pa.admit_date == Time.parse(line['admit_date']).to_date,
1028
+ 'admit_date mismatch'
1029
+ end
1030
+
1031
+ # unless warn_file.nil?
1032
+ # if pa.admit_date != Time.parse(line['admit_date']).to_date
1033
+ ## don't think that this happens
1034
+ #raise "i guess that it does"
1035
+ # warn_file.puts s.inspect
1036
+ # warn_file.puts pa.inspect
1037
+ # warn_file.puts "-admit_date mismatch:"
1038
+ # warn_file.puts "-admit_date csv :#{line['admit_date']}:"
1039
+ # warn_file.puts "-admit_date db :#{pa.admit_date}:"
1040
+ # warn_file.puts
1041
+ # end
1042
+ # end
1043
+
1044
+
1045
+ assert pa.diagnosis_id == line['diagnosis_id'].to_nil_or_i,
1046
+ "diagnosis_id mismatch:#{pa.diagnosis_id}:#{line['diagnosis_id']}:"
1047
+ assert pa.raf_zip.only_numeric == line['raf_zip'].only_numeric,
1048
+ "raf_zip mismatch:#{pa.raf_zip}:#{line['raf_zip']}:"
1049
+ assert pa.raf_county == line['raf_county'],
1050
+ "raf_county mismatch:#{pa.raf_county}:#{line['raf_county']}:"
1051
+ assert pa.hospital_no == line['hospital_no'],
1052
+ "hospital_no mismatch:#{pa.hospital_no}:#{line['hospital_no']}:"
1053
+
1054
+
1055
+ # TODO
1056
+ # assert pa.organization_id == line['organization_id'].to_dk_or_i,
1057
+ assert pa.organization_id == line['organization_id'].to_nil_or_i,
1058
+ "organization_id mismatch:#{pa.organization_id}:#{line['organization_id']}:"
1059
+
1060
+
1061
+ assert pa.other_diagnosis == line['other_diagnosis'],
1062
+ "other_diagnosis mismatch:#{pa.other_diagnosis}:#{line['other_diagnosis']}:"
1063
+
1064
+ # TODO problem with the 9 and 999 issue as well
1065
+ # assert pa.was_previously_treated == line['was_previously_treated'].to_nil_or_i,
1066
+ assert pa.was_previously_treated == line['was_previously_treated'].to_nil_or_999_or_i,
1067
+ "was_previously_treated mismatch:#{pa.was_previously_treated}:#{line['was_previously_treated']}:"
1068
+ # TODO probably won't be true all the time
1069
+ # assert pa.was_under_15_at_dx == line['was_under_15_at_dx'],
1070
+ # 'was_under_15_at_dx mismatch'
1071
+
1072
+ unless warn_file.nil?
1073
+ if pa.was_under_15_at_dx != line['was_under_15_at_dx'].to_nil_or_i
1074
+ warn_file.puts s.inspect
1075
+ warn_file.puts pa.inspect
1076
+ warn_file.puts "was_under_15_at_dx mismatch:"
1077
+ warn_file.puts "was_under_15_at_dx csv :#{line['was_under_15_at_dx']}:"
1078
+ warn_file.puts "was_under_15_at_dx db :#{pa.was_under_15_at_dx}:"
1079
+ warn_file.puts "dob db :#{s.dob}:"
1080
+ warn_file.puts "admit_date db :#{pa.admit_date}:"
1081
+ warn_file.puts "admit_date - dob :#{((pa.admit_date.to_date - s.dob.to_date).to_f/365)}:"
1082
+ warn_file.puts
1083
+ end
1084
+ end
1085
+
1086
+ else
1087
+ assert pa.nil?, 'Patient for non-case'
1088
+ end
1089
+
1090
+ assert s.subjectid == line['subjectid'],
1091
+ "subjectid mismatch:#{s.subjectid}:#{line['subjectid']}:"
1092
+ assert s.childid.to_s == line['childid'],
1093
+ "childid mismatch:#{s.childid}:#{line['childid']}:"
1094
+ assert s.icf_master_id == line['icf_master_id'],
1095
+ "icf_master_id mismatch:#{s.icf_master_id}:#{line['icf_master_id']}:"
1096
+ assert s.childidwho == line['childidwho'],
1097
+ "childidwho mismatch:#{s.childidwho}:#{line['childidwho']}:"
1098
+ assert s.familyid == line['familyid'],
1099
+ "familyid mismatch:#{s.familyid}:#{line['familyid']}:"
1100
+ assert s.matchingid == line['matchingid'],
1101
+ "matchingid mismatch:#{s.matchingid}:#{line['matchingid']}:"
1102
+ assert s.patid == line['patid'],
1103
+ "patid mismatch:#{s.patid}:#{line['patid']}:"
1104
+ assert s.case_control_type == line['case_control_type'],
1105
+ "case_control_type mismatch:#{s.case_control_type}:#{line['case_control_type']}:"
1106
+ assert s.orderno == line['orderno'].to_nil_or_i,
1107
+ "orderno mismatch:#{s.orderno}:#{line['orderno']}:"
1108
+ assert s.newid == line['newid'],
1109
+ "newid mismatch:#{s.newid}:#{line['newid']}:"
1110
+ assert s.studyid == line['studyid'],
1111
+ "studyid mismatch:#{s.studyid}:#{line['studyid']}:"
1112
+ assert s.related_case_childid == line['related_case_childid'],
1113
+ "related_case_childid mismatch:#{s.related_case_childid}:#{line['related_case_childid']}:"
1114
+ assert s.state_id_no == line['state_id_no'],
1115
+ "state_id_no mismatch:#{s.state_id_no}:#{line['state_id_no']}:"
1116
+ end