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,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