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,31 @@
1
+ # == requires
2
+ # * key ( unique )
3
+ # * description ( unique and > 3 chars )
4
+ class OperationalEventType < ActiveRecordShared
5
+
6
+ acts_as_list
7
+ default_scope :order => :position
8
+
9
+ acts_like_a_hash
10
+
11
+ has_many :operational_events
12
+
13
+ validates_presence_of :event_category
14
+ validates_uniqueness_of :event_category
15
+ validates_length_of :event_category,
16
+ :in => 4..250, :allow_blank => true
17
+
18
+ # Returns event_category.
19
+ def to_s
20
+ "#{event_category}:#{description}"
21
+ end
22
+
23
+ def self.categories
24
+ find(:all,
25
+ :conditions => 'event_category IS NOT NULL',
26
+ :order => 'event_category ASC',
27
+ :group => :event_category
28
+ ).collect(&:event_category)
29
+ end
30
+
31
+ end
@@ -0,0 +1,28 @@
1
+ # == requires
2
+ # * name ( unique and > 3 chars )
3
+ class Organization < ActiveRecordShared
4
+
5
+ acts_as_list
6
+ default_scope :order => :position
7
+
8
+ acts_like_a_hash(:value => :name)
9
+
10
+ belongs_to :person
11
+ has_many :aliquots, :foreign_key => 'owner_id'
12
+ has_many :incoming_transfers, :class_name => 'Transfer',
13
+ :foreign_key => 'to_organization_id'
14
+ has_many :outgoing_transfers, :class_name => 'Transfer',
15
+ :foreign_key => 'from_organization_id'
16
+ # has_many :hospitals
17
+ has_one :hospital
18
+ has_many :patients
19
+
20
+ validates_presence_of :name
21
+ validates_uniqueness_of :name
22
+
23
+ # Returns name
24
+ def to_s
25
+ name
26
+ end
27
+
28
+ end
@@ -0,0 +1,63 @@
1
+ # Patient related study_subject info.
2
+ class Patient < ActiveRecordShared
3
+
4
+ belongs_to :study_subject
5
+ belongs_to :organization
6
+ belongs_to :diagnosis
7
+
8
+ delegate :is_other?, :to => :diagnosis, :allow_nil => true, :prefix => true
9
+
10
+ attr_protected( :study_subject_id, :study_subject )
11
+
12
+ include PatientValidations
13
+
14
+ # Would it be better to do this before_validation?
15
+ before_save :format_raf_zip, :if => :raf_zip_changed?
16
+
17
+ after_save :trigger_update_matching_study_subjects_reference_date,
18
+ :if => :admit_date_changed?
19
+
20
+ after_save :trigger_setting_was_under_15_at_dx,
21
+ :if => :admit_date_changed?
22
+
23
+ protected
24
+
25
+ # Simply squish the zip removing leading and trailing spaces.
26
+ def format_raf_zip
27
+ # zip was nil during import and skipping validations
28
+ self.raf_zip.squish! unless raf_zip.nil?
29
+ # convert to 12345-1234
30
+ if !self.raf_zip.nil? and self.raf_zip.length > 5
31
+ old = self.raf_zip.gsub(/\D/,'')
32
+ self.raf_zip = "#{old[0..4]}-#{old[5..8]}"
33
+ end
34
+ end
35
+
36
+ def trigger_setting_was_under_15_at_dx
37
+ logger.debug "DEBUG: calling update_patient_was_under_15_at_dx from Patient:#{self.attributes['id']}"
38
+ logger.debug "DEBUG: Admit date changed from:#{admit_date_was}:to:#{admit_date}"
39
+ if study_subject
40
+ logger.debug "DEBUG: study_subject:#{study_subject.id}"
41
+ study_subject.update_patient_was_under_15_at_dx
42
+ else
43
+ # This should never happen, except in testing.
44
+ logger.warn "WARNING: Patient(#{self.attributes['id']}) is missing study_subject"
45
+ end
46
+ end
47
+ #
48
+ # logger levels are ... debug, info, warn, error, and fatal.
49
+ #
50
+ def trigger_update_matching_study_subjects_reference_date
51
+ logger.debug "DEBUG: calling update_study_subjects_reference_date_matching from Patient:#{self.attributes['id']}"
52
+ logger.debug "DEBUG: Admit date changed from:#{admit_date_was}:to:#{admit_date}"
53
+ if study_subject
54
+ logger.debug "DEBUG: study_subject:#{study_subject.id}"
55
+ # study_subject.update_matching_study_subjects_reference_date
56
+ study_subject.update_study_subjects_reference_date_matching
57
+ else
58
+ # This should never happen, except in testing.
59
+ logger.warn "WARNING: Patient(#{self.attributes['id']}) is missing study_subject"
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,118 @@
1
+ #
2
+ # Simply extracted some code to clean up model.
3
+ # I'd like to do this to all of the really big classes
4
+ # but let's see how this goes first.
5
+ #
6
+ module PatientValidations
7
+ def self.included(base)
8
+ # Must delay the calls to these ActiveRecord methods
9
+ # or it will raise many "undefined method"s.
10
+ base.class_eval do
11
+
12
+ validates_presence_of :admit_date
13
+ validate :presence_of_organization_id
14
+ validates_presence_of :diagnosis_id
15
+ validate :presence_of_hospital_no
16
+ validates_length_of :hospital_no, :maximum => 25, :allow_blank => true
17
+ validates_uniqueness_of :hospital_no, :scope => :organization_id
18
+ validates_past_date_for :admit_date
19
+ validates_past_date_for :diagnosis_date
20
+ validates_past_date_for :treatment_began_on
21
+ validate :admit_date_is_after_dob
22
+ validate :diagnosis_date_is_after_dob
23
+ validate :treatment_began_on_is_after_diagnosis_date
24
+ validate :subject_is_case
25
+ validates_complete_date_for :admit_date, :allow_nil => true
26
+ validates_complete_date_for :diagnosis_date, :allow_nil => true
27
+ validates_complete_date_for :treatment_began_on, :allow_nil => true
28
+
29
+ validates_length_of :raf_zip, :maximum => 10, :allow_blank => true
30
+
31
+ validates_format_of :raf_zip,
32
+ :with => /\A\s*\d{5}(-)?(\d{4})?\s*\z/,
33
+ :message => "should be 12345 or 12345-1234",
34
+ :allow_blank => true
35
+
36
+ validates_presence_of :other_diagnosis, :if => :diagnosis_is_other?
37
+
38
+
39
+ validates_inclusion_of :was_under_15_at_dx, :was_previously_treated,
40
+ :was_ca_resident_at_diagnosis,
41
+ :in => YNDK.valid_values, :allow_nil => true
42
+
43
+
44
+ protected
45
+
46
+ ##
47
+ # This validation does not work when using nested attributes as
48
+ # the study_subject has not been resolved yet, unless this is an update.
49
+ # This results in a similar validation in Subject.
50
+ def admit_date_is_after_dob
51
+ if !admit_date.blank? &&
52
+ !study_subject.blank? &&
53
+ !study_subject.dob.blank? &&
54
+ study_subject.dob.to_date != Date.parse('1/1/1900') &&
55
+ admit_date < study_subject.dob &&
56
+ admit_date.to_date != Date.parse('1/1/1900')
57
+ errors.add(:admit_date, "is before study_subject's dob.")
58
+ end
59
+ end
60
+
61
+ ##
62
+ # This validation does not work when using nested attributes as
63
+ # the study_subject has not been resolved yet, unless this is an update.
64
+ # This results in a similar validation in Subject.
65
+ def diagnosis_date_is_after_dob
66
+ if !diagnosis_date.blank? &&
67
+ !study_subject.blank? &&
68
+ !study_subject.dob.blank? &&
69
+ diagnosis_date < study_subject.dob
70
+ errors.add(:diagnosis_date, "is before study_subject's dob.")
71
+ end
72
+ end
73
+
74
+ ##
75
+ # Both are patient dates so this doesn't need in subject!
76
+ # custom validation and custom message
77
+ def treatment_began_on_is_after_diagnosis_date
78
+ if !treatment_began_on.blank? &&
79
+ !diagnosis_date.blank? &&
80
+ treatment_began_on < diagnosis_date
81
+ # errors.add(:treatment_began_on, "is before diagnosis_date.")
82
+ errors.add(:treatment_began_on, ActiveRecord::Error.new(
83
+ self, :base, :blank, {
84
+ :message => "Date treatment began must be on or after the diagnosis date." } ) )
85
+ end
86
+ end
87
+
88
+ ##
89
+ # This validation does not work when using nested attributes as
90
+ # the study_subject has not been resolved yet, unless this is an update.
91
+ # This results in a similar validation in Subject.
92
+ def subject_is_case
93
+ if study_subject and !study_subject.is_case?
94
+ errors.add(:study_subject,"must be case to have patient info")
95
+ end
96
+ end
97
+
98
+ # custom validation for custom message without standard attribute prefix
99
+ def presence_of_organization_id
100
+ if organization_id.blank?
101
+ errors.add(:organization_id, ActiveRecord::Error.new(
102
+ self, :base, :blank, {
103
+ :message => "Treating institution can't be blank." } ) )
104
+ end
105
+ end
106
+
107
+ # custom validation for custom message without standard attribute prefix
108
+ def presence_of_hospital_no
109
+ if hospital_no.blank?
110
+ errors.add(:hospital_no, ActiveRecord::Error.new(
111
+ self, :base, :blank, {
112
+ :message => "Hospital record number can't be blank." } ) )
113
+ end
114
+ end
115
+
116
+ end # class_eval
117
+ end # included
118
+ end # PatientValidations
@@ -0,0 +1,28 @@
1
+ # don't know exactly
2
+ class Person < ActiveRecordShared
3
+
4
+ acts_as_list
5
+ default_scope :order => :position
6
+
7
+ # belongs_to :context
8
+ has_many :interviews, :foreign_key => 'interviewer_id'
9
+ has_many :organizations
10
+
11
+ validates_presence_of :last_name
12
+ validates_length_of :first_name, :maximum => 250, :allow_blank => true
13
+ validates_length_of :last_name, :maximum => 250, :allow_blank => true
14
+ validates_length_of :honorific, :maximum => 250, :allow_blank => true
15
+
16
+ named_scope :interviewers, :conditions => { :person_type_id => 3 }
17
+
18
+ # Returns string containing first and last name
19
+ def full_name
20
+ "#{first_name} #{last_name}"
21
+ end
22
+
23
+ # Returns full_name
24
+ def to_s
25
+ full_name
26
+ end
27
+
28
+ end
@@ -0,0 +1,105 @@
1
+ # A study_subject's phone number
2
+ class PhoneNumber < ActiveRecordShared
3
+
4
+ acts_as_list :scope => :study_subject_id
5
+ default_scope :order => :position
6
+
7
+ belongs_to :study_subject
8
+ belongs_to :phone_type
9
+ belongs_to :data_source
10
+
11
+ # TODO test this. Also may not need current_user now.
12
+ # This works in the console and such, but ActiveScaffold tries
13
+ # to use it in a join, but it is in a different database so fails.
14
+ # May be able to make it work in AS, but need to fiddle.
15
+ # belongs_to :verified_by, :foreign_key => 'verified_by_uid',
16
+ # :class_name => 'User', :primary_key => 'uid'
17
+
18
+ delegate :is_other?, :to => :data_source, :allow_nil => true, :prefix => true
19
+
20
+ validates_presence_of :phone_number
21
+
22
+ validates_presence_of :phone_type_id
23
+ validates_presence_of :phone_type, :if => :phone_type_id
24
+
25
+ validates_presence_of :why_invalid, :if => :is_not_valid?
26
+ validates_presence_of :how_verified, :if => :is_verified?
27
+ validates_presence_of :data_source_other, :if => :data_source_is_other?
28
+ validates_length_of :why_invalid, :maximum => 250, :allow_blank => true
29
+ validates_length_of :how_verified, :maximum => 250, :allow_blank => true
30
+
31
+ # Want to ensure contains 10 digits.
32
+ # I'm kinda surprised that this regex works.
33
+ validates_format_of :phone_number, :with => /\A(\D*\d\D*){10}\z/,
34
+ :allow_blank => true
35
+
36
+
37
+
38
+
39
+ attr_protected :study_subject_id, :study_subject
40
+
41
+
42
+
43
+
44
+ validates_inclusion_of :current_phone, :is_valid,
45
+ :in => YNDK.valid_values, :allow_nil => true
46
+
47
+
48
+ named_scope :current, :conditions => [
49
+ 'current_phone IS NOT NULL AND current_phone != 2'
50
+ ]
51
+
52
+ named_scope :historic, :conditions => [
53
+ 'current_phone IS NULL OR current_phone = 2'
54
+ ]
55
+
56
+ before_save :format_phone_number, :if => :phone_number_changed?
57
+
58
+ before_save :set_verifier,
59
+ :if => :is_verified?,
60
+ :unless => :is_verified_was
61
+
62
+ before_save :nullify_verifier,
63
+ :unless => :is_verified?,
64
+ :if => :is_verified_was
65
+
66
+ attr_accessor :current_user
67
+
68
+ # Returns description
69
+ def to_s
70
+ phone_number
71
+ end
72
+
73
+ # Returns boolean of comparison
74
+ # true only if is_valid == 2 or 999
75
+ # Beware of strings from forms
76
+ # Rails SHOULD convert incoming string params to integer.
77
+ def is_not_valid?
78
+ # [2,999].include?(is_valid.to_i)
79
+ [2,999].include?(is_valid)
80
+ end
81
+
82
+ protected
83
+
84
+ # Set verified time and user if given
85
+ def set_verifier
86
+ self.verified_on = Time.now
87
+ self.verified_by_uid = current_user.try(:uid)||''
88
+ end
89
+
90
+ # Unset verified time and user
91
+ def nullify_verifier
92
+ self.verified_on = nil
93
+ self.verified_by_uid = nil
94
+ end
95
+
96
+ # Formats phone numer with () and -
97
+ def format_phone_number
98
+ unless self.phone_number.nil?
99
+ old = self.phone_number.gsub(/\D/,'')
100
+ new_phone = "(#{old[0..2]}) #{old[3..5]}-#{old[6..9]}"
101
+ self.phone_number = new_phone
102
+ end
103
+ end
104
+
105
+ end
@@ -0,0 +1,15 @@
1
+ # The type of phone number (home,work,mobile,etc.)
2
+ class PhoneType < ActiveRecordShared
3
+
4
+ acts_as_list
5
+ default_scope :order => :position
6
+
7
+ acts_like_a_hash
8
+ has_many :phone_numbers
9
+
10
+ # Returns key
11
+ def to_s
12
+ key
13
+ end
14
+
15
+ end
@@ -0,0 +1,39 @@
1
+ # == requires
2
+ # * key ( unique )
3
+ # * description ( unique and > 3 chars )
4
+ class Project < ActiveRecordShared
5
+
6
+ acts_as_list
7
+ default_scope :order => :position
8
+
9
+ acts_like_a_hash
10
+
11
+ # has_many :operational_event_types
12
+ has_many :instrument_types
13
+ has_many :enrollments
14
+ has_many :samples
15
+ has_many :gift_cards
16
+ has_many :study_subjects, :through => :enrollments
17
+ has_many :instruments
18
+
19
+ validates_complete_date_for :began_on, :allow_nil => true
20
+ validates_complete_date_for :ended_on, :allow_nil => true
21
+ validates_length_of :eligibility_criteria, :maximum => 65000, :allow_blank => true
22
+
23
+ # TODO perhaps move this into study_subject where is clearly belongs, but will need a RIGHT JOIN or something?
24
+ # Returns all projects for which the study_subject
25
+ # does not have an enrollment
26
+ def self.unenrolled_projects(study_subject)
27
+ Project.all(
28
+ :joins => "LEFT JOIN enrollments ON " <<
29
+ "projects.id = enrollments.project_id AND " <<
30
+ "enrollments.study_subject_id = #{study_subject.id}",
31
+ :conditions => [ "enrollments.study_subject_id IS NULL" ])
32
+ end
33
+
34
+ # Returns description
35
+ def to_s
36
+ description
37
+ end
38
+
39
+ end
@@ -0,0 +1,19 @@
1
+ class ProjectOutcome < ActiveRecordShared
2
+
3
+ acts_as_list
4
+ default_scope :order => :position
5
+
6
+ acts_like_a_hash
7
+
8
+ has_many :enrollments
9
+
10
+ # validates_presence_of :code
11
+ # validates_uniqueness_of :code
12
+ # validates_length_of :code, :maximum => 250, :allow_blank => true
13
+
14
+ # Returns description
15
+ def to_s
16
+ description
17
+ end
18
+
19
+ end