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,24 @@
1
+ # Extraction of answers from the survey
2
+ class HomeExposureResponse < ActiveRecordShared
3
+
4
+ belongs_to :study_subject
5
+ attr_protected :study_subject_id, :study_subject
6
+
7
+ # NEEDS to be here to match the uniqueness index in the database.
8
+ validates_uniqueness_of :study_subject_id, :allow_nil => true
9
+
10
+ validates_length_of :additional_comments, :maximum => 65000, :allow_blank => true
11
+
12
+ def self.fields
13
+ # db: db field name
14
+ # human: humanized field
15
+ @@fields ||= YAML::load( ERB.new( IO.read(
16
+ File.join(File.dirname(__FILE__),'../../config/home_exposure_response_fields.yml')
17
+ )).result)
18
+ end
19
+
20
+ def self.db_field_names
21
+ fields.collect{|f|f[:db]}
22
+ end
23
+
24
+ end
@@ -0,0 +1,75 @@
1
+ # don't know exactly
2
+ class HomexOutcome < ActiveRecordShared
3
+
4
+ acts_as_list
5
+ default_scope :order => :position
6
+
7
+ belongs_to :study_subject
8
+ attr_protected :study_subject_id, :study_subject
9
+ belongs_to :sample_outcome
10
+ belongs_to :interview_outcome
11
+
12
+ validates_uniqueness_of :study_subject_id, :allow_nil => true
13
+ validates_presence_of :sample_outcome_on, :if => :sample_outcome_id?
14
+ validates_presence_of :interview_outcome_on, :if => :interview_outcome_id?
15
+ validates_complete_date_for :interview_outcome_on, :allow_nil => true
16
+ validates_complete_date_for :sample_outcome_on, :allow_nil => true
17
+
18
+ before_save :create_interview_outcome_update,
19
+ :if => :interview_outcome_id_changed?
20
+
21
+ before_save :create_sample_outcome_update,
22
+ :if => :sample_outcome_id_changed?
23
+
24
+ class NoHomeExposureEnrollment < StandardError # :nodoc:
25
+ end
26
+
27
+ protected
28
+
29
+ # Create OperationalEvent regarding the interview outcome
30
+ def create_interview_outcome_update
31
+ operational_event_type = case interview_outcome
32
+ when InterviewOutcome['scheduled']
33
+ OperationalEventType['scheduled']
34
+ when InterviewOutcome['complete']
35
+ OperationalEventType['iv_complete']
36
+ else nil
37
+ end
38
+ unless operational_event_type.nil?
39
+ if hxe = study_subject.enrollments.find_by_project_id(Project['HomeExposures'].id)
40
+ OperationalEvent.create!(
41
+ :enrollment => hxe,
42
+ :operational_event_type => operational_event_type,
43
+ :occurred_on => interview_outcome_on
44
+ )
45
+ else
46
+ raise NoHomeExposureEnrollment
47
+ end
48
+ end
49
+ end
50
+
51
+ # Create OperationalEvent regarding the sample outcome
52
+ def create_sample_outcome_update
53
+ operational_event_type = case sample_outcome
54
+ when SampleOutcome['sent']
55
+ OperationalEventType['kit_sent']
56
+ when SampleOutcome['received']
57
+ OperationalEventType['sample_received']
58
+ when SampleOutcome['complete']
59
+ OperationalEventType['sample_complete']
60
+ else nil
61
+ end
62
+ unless operational_event_type.nil?
63
+ if hxe = study_subject.enrollments.find_by_project_id(Project['HomeExposures'].id)
64
+ OperationalEvent.create!(
65
+ :enrollment => hxe,
66
+ :operational_event_type => operational_event_type,
67
+ :occurred_on => sample_outcome_on
68
+ )
69
+ else
70
+ raise NoHomeExposureEnrollment
71
+ end
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,22 @@
1
+ class Hospital < ActiveRecordShared
2
+
3
+ acts_as_list
4
+ default_scope :order => :position
5
+
6
+ belongs_to :organization
7
+
8
+ # database will default to false
9
+ validates_inclusion_of :has_irb_waiver, :in => [ true, false ]
10
+
11
+ # if organization_id is not unique, using find_by_organization_id as I do
12
+ # WILL cause problems as it will only ever return the first match
13
+ validates_presence_of :organization_id
14
+ validates_presence_of :organization, :if => :organization_id
15
+ validates_uniqueness_of :organization_id, :allow_blank => true
16
+
17
+ named_scope :waivered, :conditions => { :has_irb_waiver => true }
18
+ named_scope :nonwaivered, :conditions => { :has_irb_waiver => false }
19
+
20
+ delegate :to_s, :to => :organization, :allow_nil => true
21
+
22
+ end
@@ -0,0 +1,30 @@
1
+ class IcfMasterId < ActiveRecordShared
2
+
3
+ #+------------------+------------+------+-----+---------+----------------+
4
+ #| Field | Type | Null | Key | Default | Extra |
5
+ #+------------------+------------+------+-----+---------+----------------+
6
+ #| id | int(11) | NO | PRI | NULL | auto_increment |
7
+ #| icf_master_id | varchar(9) | YES | UNI | NULL | |
8
+ #| assigned_on | date | YES | | NULL | |
9
+ #| created_at | datetime | YES | | NULL | |
10
+ #| updated_at | datetime | YES | | NULL | |
11
+ #| study_subject_id | int(11) | YES | UNI | NULL | |
12
+ #+------------------+------------+------+-----+---------+----------------+
13
+
14
+ belongs_to :study_subject
15
+ attr_protected( :study_subject_id, :study_subject )
16
+
17
+ # probably shouldn't add validations as this won't be created by users. yet.
18
+
19
+ def to_s
20
+ icf_master_id
21
+ end
22
+
23
+ # a named scope would be nice but
24
+ def self.next_unused
25
+ find(:first,
26
+ :conditions => ['study_subject_id IS NULL']
27
+ )
28
+ end
29
+
30
+ end
@@ -0,0 +1,217 @@
1
+ class IcfMasterTracker < ActiveRecordShared
2
+
3
+ # can I attr_protected for update only?
4
+ # or perhaps find_or_create_by_masterid?
5
+ # Of course that may create the new_tracker_record
6
+ # And then on update it would create all the others?
7
+
8
+ validates_presence_of :Masterid
9
+ validates_uniqueness_of :Masterid, :allow_blank => true
10
+ attr_protected :Masterid
11
+
12
+ # validate all string field lengths ?
13
+ validates_length_of :last_update_attempt_errors, :maximum => 65000, :allow_blank => true
14
+
15
+ belongs_to :study_subject
16
+ attr_protected( :study_subject_id, :study_subject )
17
+
18
+ before_save :attach_study_subject
19
+ before_save :flag_for_update
20
+ before_save :save_all_changes
21
+
22
+ named_scope :have_changed, :conditions => {
23
+ :flagged_for_update => true
24
+ }
25
+
26
+ # This may not be the best way to update.
27
+ # We may have to implement something like BackgrounDRb.
28
+ # Updating the actual data may require a number of SQL searches
29
+ # to find the appropriate columns which could consume enough
30
+ # time to trigger a timeout. In addition, there may not be
31
+ # enough information here to determine the correct model
32
+ # to update, but we'll see how it progresses.
33
+ # If we do use BackgrounDRb, we'll probably need an additional
34
+ # column to flag has having been updated to be set in
35
+ # a before_save callback. This would then need unset by
36
+ # the BackgrounDRb worker when complete.
37
+ # after_save :update_models
38
+
39
+ def attach_study_subject
40
+ unless study_subject_id
41
+ self.study_subject = StudySubject.find_by_icf_master_id(self.Masterid)
42
+ end
43
+ end
44
+
45
+ def ignorable_changes
46
+ # %w{id flagged_for_update study_subject_id Masterid created_at updated_at}
47
+ %w{ id created_at updated_at
48
+ flagged_for_update last_update_attempt_errors last_update_attempted_at }
49
+ end
50
+
51
+ def unignorable_changes
52
+ changes.dup.delete_keys!(*ignorable_changes)
53
+ end
54
+
55
+ def flag_for_update
56
+ self.flagged_for_update = true unless unignorable_changes.empty?
57
+ end
58
+
59
+ def save_all_changes
60
+ if new_record?
61
+ IcfMasterTrackerChange.create(
62
+ :icf_master_id => self.Masterid,
63
+ # 5 t.date :master_tracker_date # Hmm.
64
+ :new_tracker_record => true
65
+ )
66
+ else
67
+ unignorable_changes.each do |field,values|
68
+ IcfMasterTrackerChange.create(
69
+ :icf_master_id => self.Masterid,
70
+ # 5 t.date :master_tracker_date # Hmm.
71
+ :modified_column => field,
72
+ :previous_value => values[0],
73
+ :new_value => values[1]
74
+ )
75
+ end
76
+ end
77
+ end
78
+
79
+ def self.update_models_flagged_for_update
80
+ puts "Searching for changed Icf Master Tracker records."
81
+ changed_records = self.have_changed
82
+ if changed_records.empty?
83
+ puts "- Found no changed records."
84
+ else
85
+ puts "- Found #{changed_records} changed records."
86
+ changed_records.each do |record|
87
+ # record.last_update_attempted_at = Time.now
88
+ # unless record.study_subject_id.nil?
89
+ # try to update models
90
+ # if successful
91
+ # record.flagged_for_update = false
92
+ # record.last_update_attempt_errors = nil
93
+ # else
94
+ # set last_update_attempt_error
95
+ # leave flagged_for_update as true
96
+ # end
97
+ # else
98
+ # record.last_update_attempt_errors = "study_subject is nil. Nothing to update."
99
+ # leave flagged_for_update as true
100
+ # end
101
+ # record.save
102
+ end
103
+ end
104
+ end
105
+
106
+
107
+
108
+
109
+ # def update_models
110
+ # #
111
+ # # "Masterid","Motherid","Record_Owner","Datereceived","Lastatt","Lastdisp",
112
+ # # "Currphone","Vacauthrecd","Recollect","Needpreincentive","Active_Phone",
113
+ # # "Recordsentformatching","Recordreceivedfrommatching","Sentpreincentive",
114
+ # # "Releasedtocati","Confirmedcaticontact","Refused","Deceasednotification",
115
+ # # "Eligible","Confirmationpacketsent","Catiprotocolexhausted",
116
+ # # "Newphonenumreleasedtocati","Pleanotificationsent",
117
+ # # "Casereturnedtoberkeleyfornewinf","Casereturnedfromberkeley","Caticomplete",
118
+ # # "Kitmothersent","Kitinfantsent","Kitchildsent","Kitadolescentsent",
119
+ # # "Kitmotherrefusedcode","Kitchildrefusedcode","Noresponsetoplea",
120
+ # # "Responsereceivedfromplea","Senttoinpersonfollowup","Kitmotherrecd",
121
+ # # "Kitchildrecvd","Thankyousent","Physrequestsent","Physresponsereceived"
122
+ # #
123
+ # # Most of the columns are dates which probably correspond to an enrollment or sample.
124
+ # #Table: samples
125
+ # #+------------------------------+---------------
126
+ # #| Field | Type
127
+ # #+------------------------------+--------------
128
+ # #| aliquot_sample_format_id | int(11)
129
+ # #| sample_type_id | int(11)
130
+ # #| study_subject_id | int(11)
131
+ # #| unit_id | int(11)
132
+ # #| order_no | int(11)
133
+ # #| quantity_in_sample | decimal(10,0)
134
+ # #| aliquot_or_sample_on_receipt | varchar(255)
135
+ # #| sent_to_subject_on | date
136
+ # #| received_by_ccls_on | date
137
+ # #| sent_to_lab_on | date
138
+ # #| received_by_lab_on | date
139
+ # #| aliquotted_on | date
140
+ # #| external_id | varchar(255)
141
+ # #| external_id_source | varchar(255)
142
+ # #| receipt_confirmed_on | date
143
+ # #| receipt_confirmed_by | varchar(255)
144
+ # #| future_use_prohibited | tinyint(1)
145
+ # #| collected_on | date
146
+ # #| location_id | int(11)
147
+ # #
148
+ # # if study_subject_id and dirty
149
+ # # Consider Record_Owner field?
150
+ # # Which project?
151
+ # # add operational event with differences to study subject
152
+ # # update models
153
+ # # end
154
+ #
155
+ # if study_subject_id and changed?
156
+ # # puts
157
+ # # puts "Tracker has subject and has changed so begin updating"
158
+ # # puts self.changes
159
+ # #
160
+ # # Which changes matter?
161
+ # # There are many validations, so what to do if update fails?
162
+ # # If subject doesn't initially exist (shouldn't happen),
163
+ # # then these updates will NEVER be added as the record
164
+ # # "changes" won't be changed. Will need another condition
165
+ # # to update everything if study_subject_id is new.
166
+ # # Again, this shouldn't actually ever happen as the Masterid
167
+ # # is assigned to a subject by us, meaning the subject exists
168
+ # # before giving it to ICF.
169
+ #
170
+ # # unignored_changes = changes.dup.delete_keys!(*ignorable_changes)
171
+ # unless unignorable_changes.empty?
172
+ # # description = []
173
+ # # unignorable_changes.each { |field,values|
174
+ # # description << "#{field} changed from #{values[0]} to #{values[1]}"
175
+ # # }
176
+ # # OperationalEvent.create!(
177
+ # # :enrollment => study_subject.enrollments.find_or_create_by_project_id(
178
+ # # Project[:ccls].id),
179
+ # # :operational_event_type => OperationalEventType[:other],
180
+ # ##
181
+ # ## description can only be 250 chars so this fails in testing
182
+ # ## when creating new tracker as everything has changed.
183
+ # ## Change description to text? Will 65000 chars be enough?
184
+ # ##
185
+ # ## :description => description.join("\n")
186
+ # # :description => "Icf Master Tracker caused changes."
187
+ # # )
188
+ # end
189
+ # # else
190
+ # # puts
191
+ # # puts "Tracker has no subject so skipping updating"
192
+ # end
193
+ # end
194
+
195
+ end
196
+
197
+ __END__
198
+
199
+
200
+ changed?() public
201
+
202
+ Returns true if any attribute have unsaved changes, false otherwise.
203
+
204
+ person.changed? # => false
205
+ person.name = 'bob'
206
+ person.changed? # => true
207
+
208
+
209
+ changes() public
210
+
211
+ Map of changed attrs => [original value, new value].
212
+
213
+ person.changes # => {}
214
+ person.name = 'bob'
215
+ person.changes # => { 'name' => ['bill', 'bob'] }
216
+
217
+
@@ -0,0 +1,9 @@
1
+ class IcfMasterTrackerChange < ActiveRecordShared
2
+
3
+ # Would be pointless without the icf_master_id
4
+ validates_presence_of :icf_master_id
5
+
6
+ # should probably avoid validations
7
+ # validates_inclusion_of :new_tracker_record, :in => [ true, false ]
8
+
9
+ end
@@ -0,0 +1,50 @@
1
+ class IcfMasterTrackerUpdate < ActiveRecordShared
2
+
3
+ has_attached_file :csv_file,
4
+ YAML::load(ERB.new(IO.read(File.expand_path(
5
+ File.join(File.dirname(__FILE__),'../..','config/icf_master_tracker_update.yml')
6
+ ))).result)[Rails.env]
7
+
8
+
9
+ # This doesn't really do much of anything yet.
10
+ def parse
11
+ results = []
12
+ if !self.csv_file_file_name.blank? &&
13
+ File.exists?(self.csv_file.path)
14
+ (f=FasterCSV.open( self.csv_file.path, 'rb',{
15
+ :headers => true })).each do |line|
16
+
17
+ # "Masterid","Motherid","Record_Owner","Datereceived","Lastatt","Lastdisp","Currphone","Vacauthrecd","Recollect","Needpreincentive","Active_Phone","Recordsentformatching","Recordreceivedfrommatching","Sentpreincentive","Releasedtocati","Confirmedcaticontact","Refused","Deceasednotification","Eligible","Confirmationpacketsent","Catiprotocolexhausted","Newphonenumreleasedtocati","Pleanotificationsent","Casereturnedtoberkeleyfornewinf","Casereturnedfromberkeley","Caticomplete","Kitmothersent","Kitinfantsent","Kitchildsent","Kitadolescentsent","Kitmotherrefusedcode","Kitchildrefusedcode","Noresponsetoplea","Responsereceivedfromplea","Senttoinpersonfollowup","Kitmotherrecd","Kitchildrecvd","Thankyousent","Physrequestsent","Physresponsereceived"
18
+
19
+ #
20
+ # The IcfMasterTracker will include an after_save or something that will
21
+ # determine what has changed and update appropriately. It may also
22
+ # create OperationalEvents to document the data changes. As it is
23
+ # theoretically possible that the Masterid does not exist in the identifiers
24
+ # table, perhaps add a successfully_updated_models flag which could
25
+ # be used?
26
+ #
27
+ icf_master_tracker = IcfMasterTracker.find_or_create_by_Masterid(line['Masterid'])
28
+ # NO BANG. Don't want to raise any errors.
29
+ successfully_updated = icf_master_tracker.update_attributes(line.to_hash)
30
+ #
31
+ # errors = icf_master_tracker.errors.full_messages.to_sentence
32
+ # These won't be validation errors as there shouldn't be any.
33
+ # Perhaps "no column by that name" errors if csv file changes?
34
+ #
35
+ # Add successfully_updated value?
36
+ # icf_master_tracker.update_attribute(:sucessfully_updated, successfully_updated)
37
+ # will the above include the line's attributes?
38
+ #
39
+ # Add update_errors column?
40
+ # icf_master_tracker.update_attribute(:update_errors, errors)
41
+ #
42
+
43
+ results.push(icf_master_tracker)
44
+
45
+ end # (f=FasterCSV.open( self.csv_file.path, 'rb',{ :headers => true })).each
46
+ end # if !self.csv_file_file_name.blank? && File.exists?(self.csv_file.path)
47
+ results # TODO why am I returning anything? will I use this later?
48
+ end # def parse
49
+
50
+ end
@@ -0,0 +1,26 @@
1
+ # == requires
2
+ # * description (unique and > 3 chars)
3
+ class IneligibleReason < ActiveRecordShared
4
+
5
+ acts_as_list
6
+ default_scope :order => :position
7
+
8
+ acts_like_a_hash
9
+
10
+ has_many :enrollments
11
+
12
+ validates_length_of :ineligible_context,
13
+ :maximum => 250, :allow_blank => true
14
+
15
+ # Returns description
16
+ def to_s
17
+ description
18
+ end
19
+
20
+ # Returns boolean of comparison
21
+ # true only if key == 'other'
22
+ def is_other?
23
+ key == 'other'
24
+ end
25
+
26
+ end