ccls-ccls_engine 3.11.0

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