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,31 @@
1
+ # == requires
2
+ # * code ( unique )
3
+ # * description ( unique and > 3 chars )
4
+ class Race < ActiveRecordShared
5
+
6
+ acts_as_list
7
+ default_scope :order => :position
8
+
9
+ acts_like_a_hash
10
+
11
+ validates_presence_of :code
12
+ validates_uniqueness_of :code
13
+ validates_length_of :code, :maximum => 250, :allow_blank => true
14
+
15
+ # Returns description
16
+ def to_s
17
+ description
18
+ end
19
+
20
+ # Returns description
21
+ def name
22
+ description
23
+ end
24
+
25
+ # Returns boolean of comparison
26
+ # true only if key == 'other'
27
+ def is_other?
28
+ key == 'other'
29
+ end
30
+
31
+ end
@@ -0,0 +1,23 @@
1
+ # == requires
2
+ # * description ( unique and > 3 chars )
3
+ class RefusalReason < ActiveRecordShared
4
+
5
+ acts_as_list
6
+ default_scope :order => :position
7
+
8
+ acts_like_a_hash
9
+
10
+ has_many :enrollments
11
+
12
+ # Returns description
13
+ def to_s
14
+ description
15
+ end
16
+
17
+ # Returns boolean of comparison
18
+ # true only if key == 'other'
19
+ def is_other?
20
+ key == 'other'
21
+ end
22
+
23
+ end
@@ -0,0 +1,168 @@
1
+ # == requires
2
+ # * enrollment_id
3
+ # * unit_id
4
+ class Sample < ActiveRecordShared
5
+
6
+ belongs_to :aliquot_sample_format
7
+ belongs_to :sample_type
8
+ belongs_to :organization, :foreign_key => 'location_id'
9
+ belongs_to :unit
10
+ has_many :aliquots
11
+ belongs_to :project
12
+ belongs_to :study_subject
13
+ belongs_to :sample_temperature
14
+
15
+ attr_protected :study_subject_id, :study_subject
16
+
17
+ has_one :sample_kit
18
+ accepts_nested_attributes_for :sample_kit
19
+
20
+ named_scope :pending, :conditions => {
21
+ :received_by_ccls_at => nil }
22
+
23
+ named_scope :collected, :conditions => [
24
+ 'received_by_ccls_at IS NOT NULL' ]
25
+
26
+ validates_presence_of :sample_type_id
27
+ validates_presence_of :sample_type, :if => :sample_type_id
28
+ validates_presence_of :study_subject_id
29
+ validates_presence_of :study_subject, :if => :study_subject_id
30
+ validates_presence_of :project_id
31
+ validates_presence_of :project, :if => :project_id
32
+
33
+ validates_presence_of :sent_to_subject_on, :if => :collected_at
34
+ validates_presence_of :collected_at, :if => :received_by_ccls_at
35
+ validates_presence_of :location_id, :if => :sent_to_lab_on
36
+ validates_presence_of :received_by_ccls_at, :if => :sent_to_lab_on
37
+ validates_presence_of :sent_to_lab_on, :if => :received_by_lab_on
38
+ validates_presence_of :received_by_lab_on, :if => :aliquotted_on
39
+
40
+ # NOTE I'm not sure how this validation will work for datetimes.
41
+ validates_complete_date_for :sent_to_subject_on, :allow_nil => true
42
+ # validates_complete_date_for :collected_at, :allow_nil => true
43
+ # validates_complete_date_for :received_by_ccls_at, :allow_nil => true
44
+ validates_complete_date_for :sent_to_lab_on, :allow_nil => true
45
+ validates_complete_date_for :received_by_lab_on, :allow_nil => true
46
+ validates_complete_date_for :aliquotted_on, :allow_nil => true
47
+ validates_complete_date_for :receipt_confirmed_on, :allow_nil => true
48
+
49
+ validates_past_date_for :sent_to_subject_on
50
+ validates_past_date_for :collected_at
51
+ validates_past_date_for :received_by_ccls_at
52
+ validates_past_date_for :sent_to_lab_on
53
+ validates_past_date_for :received_by_lab_on
54
+ validates_past_date_for :aliquotted_on
55
+ validates_past_date_for :receipt_confirmed_on
56
+
57
+ validate :date_chronology
58
+
59
+ # Returns the parent of this sample type
60
+ def sample_type_parent
61
+ sample_type.parent
62
+ end
63
+
64
+ before_save :update_sample_outcome
65
+
66
+ protected
67
+
68
+ def date_chronology
69
+ errors.add(:collected_at, "must be after sent_to_subject_on"
70
+ ) if collected_at_is_before_sent_to_subject_on?
71
+ errors.add(:received_by_ccls_at, "must be after collected_at"
72
+ ) if received_by_ccls_at_is_before_collected_at?
73
+ errors.add(:sent_to_lab_on, "must be after received_by_ccls_at"
74
+ ) if sent_to_lab_on_is_before_received_by_ccls_at?
75
+ errors.add(:received_by_lab_on, "must be after sent_to_lab_on"
76
+ ) if received_by_lab_on_is_before_sent_to_lab_on?
77
+ errors.add(:aliquotted_on, "must be after received_by_lab_on"
78
+ ) if aliquotted_on_is_before_received_by_lab_on?
79
+ end
80
+
81
+ #ArgumentError: comparison of Date with ActiveSupport::TimeWithZone failed
82
+ # app/models/sample.rb:77:in `>'
83
+ # app/models/sample.rb:77:in `collected_at_is_before_sent_to_subject_on?'
84
+ def collected_at_is_before_sent_to_subject_on?
85
+ (( sent_to_subject_on && collected_at ) &&
86
+ ( sent_to_subject_on > collected_at.to_date ))
87
+ # ( sent_to_subject_on > collected_at ))
88
+ end
89
+
90
+ def received_by_ccls_at_is_before_collected_at?
91
+ (( collected_at && received_by_ccls_at ) &&
92
+ ( collected_at > received_by_ccls_at ))
93
+ end
94
+
95
+ def sent_to_lab_on_is_before_received_by_ccls_at?
96
+ (( received_by_ccls_at && sent_to_lab_on ) &&
97
+ ( received_by_ccls_at > sent_to_lab_on ))
98
+ end
99
+
100
+ def received_by_lab_on_is_before_sent_to_lab_on?
101
+ (( sent_to_lab_on && received_by_lab_on ) &&
102
+ ( sent_to_lab_on > received_by_lab_on ))
103
+ end
104
+
105
+ def aliquotted_on_is_before_received_by_lab_on?
106
+ (( received_by_lab_on && aliquotted_on ) &&
107
+ ( received_by_lab_on > aliquotted_on ))
108
+ end
109
+
110
+ def update_sample_outcome
111
+
112
+
113
+ if study_subject.enrollments.find_by_project_id(Project['HomeExposures'].id)
114
+ # if enrollment.project_id == Project['HomeExposures'].id
115
+ # study_subject = enrollment.study_subject
116
+
117
+
118
+ ho = study_subject.homex_outcome || study_subject.create_homex_outcome
119
+ so,date = if sent_to_lab_on_changed? && !sent_to_lab_on.nil?
120
+ [SampleOutcome['lab'], sent_to_lab_on ]
121
+ elsif received_by_ccls_at_changed? && !received_by_ccls_at.nil?
122
+ [SampleOutcome['received'], received_by_ccls_at ]
123
+ elsif sent_to_subject_on_changed? && !sent_to_subject_on.nil?
124
+ [SampleOutcome['sent'], sent_to_subject_on ]
125
+ end
126
+ ho.update_attributes({
127
+ :sample_outcome => so,
128
+ :sample_outcome_on => date }) if so
129
+ end
130
+ end
131
+
132
+ end
133
+ __END__
134
+
135
+
136
+ It appears that the "newer" classes know how to compare with the "older" ones, but not vice versa, which makes sense.
137
+
138
+ My comparisons in Sample should just have the "newer" class, the *_at field, first and compare it to the "older" *_on field. OR convert the DateTime to a date. Comparison of a Date to a DateTime will be confusing as it doesn't just compare the date, it takes the time zone into account which isn't 100% obvious. I think that it converts it to UTC before comparing. This could effectively make the comparison incorrect.
139
+
140
+ YES. Add a "to_date" to the _at fields.
141
+
142
+
143
+ >> Time.now
144
+ => Tue Mar 06 20:00:06 -0800 2012
145
+ >> Time.now.class
146
+ => Time
147
+
148
+ >> Time.zone.now
149
+ => Wed, 07 Mar 2012 03:54:31 UTC +00:00
150
+ >> Time.zone.now.class
151
+ => ActiveSupport::TimeWithZone
152
+
153
+ >> Time.zone.now > Date.today
154
+ => true
155
+
156
+ >> Date.today < Time.zone.now
157
+ ArgumentError: comparison of Date with ActiveSupport::TimeWithZone failed
158
+ from (irb):49:in `<'
159
+ from (irb):49
160
+
161
+ >> Date.today < Time.now
162
+ ArgumentError: comparison of Date with Time failed
163
+ from (irb):50:in `<'
164
+ from (irb):50
165
+
166
+
167
+ Also, even if the *_at field is given a Date value, it will be typecast to ActiveSupport::TimeWithZone so there is no terrible need to update all of the tests.
168
+
@@ -0,0 +1,14 @@
1
+ # A kit is 2 packages used for retrieving samples.
2
+ class SampleKit < ActiveRecordShared
3
+
4
+ # add tracking numbers to kit?
5
+ # used to be in packages
6
+ # 20120213 - Removing FedEx API, Packages and Tracks.
7
+
8
+ belongs_to :sample
9
+
10
+ delegate :study_subject, :to => :sample
11
+
12
+ validates_uniqueness_of :sample_id, :allow_nil => true
13
+
14
+ end
@@ -0,0 +1,16 @@
1
+ # don't know exactly
2
+ class SampleOutcome < ActiveRecordShared
3
+
4
+ acts_as_list
5
+ default_scope :order => :position
6
+
7
+ acts_like_a_hash
8
+
9
+ has_many :homex_outcomes
10
+
11
+ # Returns description
12
+ def to_s
13
+ description
14
+ end
15
+
16
+ end
@@ -0,0 +1,14 @@
1
+ class SampleTemperature < ActiveRecordShared
2
+
3
+ acts_as_list
4
+ default_scope :order => :position
5
+
6
+ acts_like_a_hash
7
+
8
+ has_many :samples
9
+
10
+ def to_s
11
+ description
12
+ end
13
+
14
+ end
@@ -0,0 +1,37 @@
1
+ # == requires
2
+ # * description ( unique and > 3 chars )
3
+ class SampleType < ActiveRecordShared
4
+
5
+ acts_as_list :scope => :parent_id
6
+ # default_scope :order => :position
7
+ default_scope :order => 'parent_id, position, description ASC'
8
+
9
+ acts_like_a_hash
10
+
11
+ has_many :samples
12
+
13
+ belongs_to :parent, :class_name => 'SampleType'
14
+ has_many :children,
15
+ :class_name => 'SampleType',
16
+ :foreign_key => 'parent_id',
17
+ :dependent => :nullify
18
+
19
+ named_scope :roots, :conditions => { :parent_id => nil }
20
+
21
+ named_scope :not_roots, :conditions => [
22
+ 'sample_types.parent_id IS NOT NULL' ]
23
+
24
+ # Returns description
25
+ def to_s
26
+ description
27
+ end
28
+
29
+ def is_root?
30
+ parent_id.blank?
31
+ end
32
+
33
+ def is_child?
34
+ !is_root?
35
+ end
36
+
37
+ end
@@ -0,0 +1,195 @@
1
+ #
2
+ # Originally from http://railscasts.com/episodes/111-advanced-search-form
3
+ # however, I have modified it heavily and made it quite abstract.
4
+ # Its still a bit muddy, but I'd like to replace it with rsolr.
5
+ #
6
+ class Search
7
+
8
+ class << self
9
+ def valid_orders
10
+ @valid_orders
11
+ end
12
+ def valid_orders=(more_orders)
13
+ @valid_orders = more_orders
14
+ end
15
+ def searchable_attributes
16
+ @searchable_attributes
17
+ end
18
+ def searchable_attributes=(more_attributes)
19
+ @searchable_attributes = more_attributes
20
+ end
21
+ def attr_accessors
22
+ @attr_accessors
23
+ end
24
+ def attr_accessors=(more_accessors) # extend with += [ :something ] NOT << :something
25
+ @attr_accessors = more_accessors
26
+ attr_accessor *@attr_accessors
27
+ end
28
+ end
29
+ self.valid_orders = HashWithIndifferentAccess.new
30
+ self.searchable_attributes = []
31
+ self.attr_accessors = [ :order, :dir, :includes, :paginate, :per_page, :page ]
32
+
33
+ def valid_orders
34
+ self.class.valid_orders
35
+ end
36
+
37
+ def searchable_attributes
38
+ self.class.searchable_attributes
39
+ end
40
+
41
+ def attr_accessors
42
+ self.class.attr_accessors
43
+ end
44
+
45
+ def search_order
46
+ if valid_orders.has_key?(@order)
47
+ order_string = if valid_orders[@order].blank?
48
+ @order
49
+ else
50
+ valid_orders[@order]
51
+ end
52
+ dir = case @dir.try(:downcase)
53
+ when 'desc' then 'desc'
54
+ else 'asc'
55
+ end
56
+ [order_string,dir].join(' ')
57
+ else
58
+ nil
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def paginate?
65
+ (@paginate.nil?) ? true : @paginate
66
+ end
67
+
68
+ def initialize(options={})
69
+ self.class.send('attr_accessor', *searchable_attributes)
70
+ options.each do |attr,value|
71
+ if attr_accessors.include?(attr.to_sym) ||
72
+ searchable_attributes.include?(attr.to_sym)
73
+ self.send("#{attr}=",value)
74
+ end
75
+ end
76
+ end
77
+
78
+ def self.inherited(subclass)
79
+ # USE DUP! Without it, the two will share the same object_id
80
+ # resulting is cross contamination
81
+ subclass.searchable_attributes = searchable_attributes.dup
82
+ subclass.attr_accessors = attr_accessors.dup
83
+ subclass.valid_orders = valid_orders.dup
84
+ # Create 'shortcut'
85
+ # StudySubjectSearch(options) -> StudySubjectSearch.new(options)
86
+ Object.class_eval do
87
+ define_method subclass.to_s do |*args|
88
+ subclass.send(:new,*args)
89
+ end
90
+ end
91
+ end
92
+
93
+ # This may work for the simple stuff, but I suspect
94
+ # that once things get complicated, it will unravel.
95
+
96
+ def conditions
97
+ [conditions_clauses.join(' AND '), *conditions_options]
98
+ end
99
+
100
+ def conditions_clauses
101
+ conditions_parts.map { |condition| condition.first }
102
+ end
103
+
104
+ def conditions_options
105
+ # conditions_parts.map { |condition| condition[1..-1] }.flatten
106
+ #
107
+ # the above flatten breaks the "IN (?)" style search
108
+ #
109
+ # conditions_parts.map { |condition| condition[1..-1] }
110
+ # This fixes it, but is kinda bulky
111
+ # opts = []
112
+ # conditions_parts.each do |condition|
113
+ # condition[1..-1].each{|cp| opts << cp}
114
+ # end
115
+ # opts
116
+ # That's better!
117
+ parts = conditions_parts.map { |condition| condition[1..-1] }.flatten(1)
118
+
119
+ # The "parts" contain the variables inserted in the query.
120
+ # Apparently, we can't mix the ? style with the :var_name style,
121
+ # but we can only have 1 trailing hash so we need to merge all
122
+ # of the trailing hashes.
123
+
124
+ # symbol_options = HashWithIndifferentAccess.new
125
+ # while( !( h = parts.extract_options! ).empty? ) do
126
+ # symbol_options.merge!(h)
127
+ # end
128
+
129
+ # parts.push(symbol_options)
130
+
131
+ # caller is expecting an array
132
+ [parts.inject(:merge)]
133
+ end
134
+
135
+ def conditions_parts
136
+ private_methods(false).grep(/_conditions$/).map { |m| send(m) }.compact
137
+ end
138
+
139
+ # Join order can be important if joining on other joins
140
+ # so added a sort. Added a "a_" to those joins which must go first.
141
+ # Crude solution, but a solution nonetheless.
142
+ def joins
143
+ private_methods(false).grep(/_joins$/).sort.map { |m| send(m) }.compact
144
+ end
145
+
146
+ def select
147
+ # :select - By default, this is "*" as in "SELECT * FROM",
148
+ # but can be changed if you, for example, want to do a join
149
+ # but not include the joined columns. Takes a string with the
150
+ # SELECT SQL fragment (e.g. "id, name").
151
+ selects = private_methods(false).grep(/_selects$/).sort.map { |m| send(m) }.compact
152
+ # select CANNOT be ''
153
+ # ActiveRecord::StatementInvalid: Mysql::Error: You have an error in your SQL syntax;
154
+ # check the manual that corresponds to your MySQL server version for the right
155
+ # syntax to use near 'FROM `study_subjects` LIMIT 0, 25' at line 1:
156
+ # SELECT FROM `study_subjects` LIMIT 0, 25
157
+ # nil will cause default use of '*', which could also be passed
158
+ ( selects.empty? ) ? nil : selects.join(',')
159
+ end
160
+
161
+ def group
162
+ # :group - An attribute name by which the result should be grouped.
163
+ # Uses the GROUP BY SQL-clause
164
+ groups = private_methods(false).grep(/_groups$/).sort.map { |m| send(m) }.compact
165
+ # ActiveRecord::StatementInvalid: Mysql::Error: You have an error in your SQL syntax;
166
+ # check the manual that corresponds to your MySQL server version for the right
167
+ # syntax to use near '' at line 1: SELECT * FROM `study_subjects` GROUP BY
168
+ # nil will cause group by to not be used
169
+ ( groups.empty? ) ? nil : groups.join(',')
170
+ end
171
+
172
+ def having
173
+ # :having - Combined with :group this can be used to filter the records
174
+ # that a GROUP BY returns. Uses the HAVING SQL-clause.
175
+ # this is very similar to :conditions/WHERE so may have to add all of the
176
+ # conditions_* methods to handle
177
+ [having_clauses.join(' AND '), *having_options]
178
+ end
179
+
180
+ def having_clauses
181
+ having_parts.map { |condition| condition.first }
182
+ end
183
+
184
+ def having_options
185
+ parts = having_parts.map { |condition| condition[1..-1] }.flatten(1)
186
+ # just like conditions, these parts need to be hashes of symbol names
187
+ # for use in the sql command. Not ?.
188
+ [parts.inject(:merge)]
189
+ end
190
+
191
+ def having_parts
192
+ private_methods(false).grep(/_havings$/).map { |m| send(m) }.compact
193
+ end
194
+
195
+ end