caruby-tissue 1.2.2 → 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/bin/crtdump +11 -3
- data/bin/{seed → crtseed} +0 -0
- data/conf/annotation/pathology_scg/AdditionalFinding.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/BasePathologyAnnotation.hbm.xml +260 -0
- data/conf/annotation/pathology_scg/BreastMargin.hbm.xml +21 -0
- data/conf/annotation/pathology_scg/BreastMarginInvolved.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/BreastMarginUninvolved.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/CNSMargin.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/CNSMarginLocation.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/CarcinomaInSituStatus.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/ColorectalLocalExcisionMarginUninvolved.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/ColorectalResectedMarginUninvolved.hbm.xml +22 -0
- data/conf/annotation/pathology_scg/Cytogenetics.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/DeepMelanomaMargin.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/Details.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/DirectExtensionOfTumor.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/DistalMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/DistanceFromAnalVerge.hbm.xml +23 -0
- data/conf/annotation/pathology_scg/DistantMetastasis.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/ExcionalBiopsyMarginUninvolved.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/ExcisionalBiopsyColorectalDeepMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/ExcisionalBiopsyColorectalLateralOrMucosalMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/ExtraprostaticExtension.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/ExtraprostaticExtensionTissueSites.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/GleasonScore.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/HistologicGrade.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/HistologicType.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/HistologicVariantType.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/ImmunoPhenotyping.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/Invasion.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/KidneyMarginLocation.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/KidneyNephrectomyMargin.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/LateralMelanomaMargin.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/LocalExcisionColorectalDeepMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/LocalExcisionColorectalLateralMargin.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/LungResectionMargin.hbm.xml +17 -0
- data/conf/annotation/pathology_scg/LungResectionMarginsUninvolved.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/MacroscopicExtentOfTumor.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/MesentricMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/MetastasisTissueSite.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/Microcalcification.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/NottinghamHistologicScore.hbm.xml +17 -0
- data/conf/annotation/pathology_scg/OtherResectedOrgans.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/PancreasMargin.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/PancreasMarginInvolvedByInvasiveCarcinoma.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/PancreasMarginUninvolvedByInvasiveCarcinoma.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/PathologicalStaging.hbm.xml +16 -0
- data/conf/annotation/pathology_scg/PolypConfiguration.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/PrimaryTumorStage.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/ProstateMarginLocation.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/ProximalMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/RadialMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/RadicalProstatectomyMargin.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/RegionalLymphNode.hbm.xml +19 -0
- data/conf/annotation/pathology_scg/SatelliteNodule.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/SpecimenCollectionGroup.hbm.xml +87 -0
- data/conf/annotation/pathology_scg/SpecimenIntegrity.hbm.xml +15 -0
- data/conf/annotation/pathology_scg/SpecimenSize.hbm.xml +17 -0
- data/conf/annotation/pathology_scg/TissueSide.hbm.xml +14 -0
- data/conf/annotation/pathology_scg/TumorSize.hbm.xml +29 -0
- data/conf/annotation/pathology_scg/TumorTissueSite.hbm.xml +20 -0
- data/conf/annotation/pathology_scg/UninvolvedMelanomaMargin.hbm.xml +15 -0
- data/conf/annotation/pathology_specimen/AdditionalFinding.hbm.xml +19 -0
- data/conf/annotation/pathology_specimen/AdditionalPathologicFinding.hbm.xml +18 -0
- data/conf/annotation/pathology_specimen/Details.hbm.xml +15 -0
- data/conf/annotation/pathology_specimen/GleasonScore.hbm.xml +16 -0
- data/conf/annotation/pathology_specimen/HistologicGrade.hbm.xml +16 -0
- data/conf/annotation/pathology_specimen/HistologicType.hbm.xml +19 -0
- data/conf/annotation/pathology_specimen/HistologicVariantType.hbm.xml +14 -0
- data/conf/annotation/pathology_specimen/Invasion.hbm.xml +16 -0
- data/conf/annotation/pathology_specimen/NottinghamHistologicScore.hbm.xml +17 -0
- data/conf/annotation/pathology_specimen/Specimen.hbm.xml +52 -0
- data/conf/annotation/pathology_specimen/SpecimenBaseSolidTissuePathologyAnnotation.hbm.xml +73 -0
- data/examples/galena/lib/galena/cli/seed.rb +0 -21
- data/examples/galena/lib/galena/migration/frozen_shims.rb +6 -5
- data/examples/galena/lib/galena/seed/defaults.rb +0 -5
- data/{lib → examples/galena/lib}/galena.rb +0 -0
- data/lib/catissue/annotation/annotatable.rb +37 -0
- data/lib/catissue/annotation/annotatable_class.rb +255 -0
- data/lib/catissue/annotation/annotation.rb +49 -0
- data/lib/catissue/annotation/annotation_class.rb +277 -0
- data/lib/catissue/annotation/annotation_module.rb +77 -0
- data/lib/catissue/annotation/hibernate_mapping.rb +46 -0
- data/lib/catissue/annotation/proxy.rb +28 -0
- data/lib/catissue/annotation/proxy_class.rb +68 -0
- data/lib/catissue/cli/migrate.rb +2 -2
- data/lib/catissue/cli/smoke.rb +6 -4
- data/lib/catissue/database/annotation/annotation_service.rb +75 -61
- data/lib/catissue/database/annotation/annotator.rb +17 -76
- data/lib/catissue/database/annotation/entity_facade.rb +265 -0
- data/lib/catissue/database/annotation/id_generator.rb +62 -0
- data/lib/catissue/database/annotation/integration_service.rb +105 -59
- data/lib/catissue/database/annotation/reference_writer.rb +150 -0
- data/lib/catissue/database/controlled_values.rb +12 -12
- data/lib/catissue/database.rb +148 -58
- data/lib/catissue/domain/abstract_specimen.rb +40 -14
- data/lib/catissue/domain/abstract_specimen_collection_group.rb +1 -3
- data/lib/catissue/domain/collection_protocol.rb +13 -5
- data/lib/catissue/domain/collection_protocol_event.rb +1 -14
- data/lib/catissue/domain/consent_tier_response.rb +2 -0
- data/lib/catissue/domain/consent_tier_status.rb +5 -3
- data/lib/catissue/domain/container.rb +14 -10
- data/lib/catissue/domain/container_position.rb +8 -0
- data/lib/catissue/domain/container_type.rb +13 -6
- data/lib/catissue/domain/participant.rb +15 -10
- data/lib/catissue/domain/site.rb +9 -3
- data/lib/catissue/domain/specimen.rb +79 -40
- data/lib/catissue/domain/specimen_array.rb +11 -1
- data/lib/catissue/domain/specimen_collection_group.rb +79 -41
- data/lib/catissue/domain/specimen_event_parameters.rb +5 -8
- data/lib/catissue/domain/specimen_position.rb +0 -2
- data/lib/catissue/domain/specimen_requirement.rb +1 -1
- data/lib/catissue/domain/storage_container.rb +109 -48
- data/lib/catissue/domain/storage_type.rb +1 -1
- data/lib/catissue/migration/migrator.rb +6 -14
- data/lib/catissue/resource.rb +18 -8
- data/lib/catissue/util/position.rb +11 -1
- data/lib/catissue/util/storable.rb +18 -11
- data/lib/catissue/util/storage_type_holder.rb +44 -6
- data/lib/catissue/version.rb +1 -1
- metadata +86 -35
- data/bin/migrate.rb +0 -42
- data/bin/seed.rb +0 -43
- data/examples/galena/doc/CaTissue/Participant.html +0 -241
- data/examples/galena/doc/CaTissue/SpecimenCollectionGroup.html +0 -190
- data/examples/galena/doc/CaTissue/StorageContainer.html +0 -179
- data/examples/galena/doc/CaTissue/TissueSpecimen.html +0 -320
- data/examples/galena/doc/CaTissue.html +0 -93
- data/examples/galena/doc/Galena/Seed/Defaults.html +0 -650
- data/examples/galena/doc/Galena/Seed.html +0 -203
- data/examples/galena/doc/Galena.html +0 -172
- data/examples/galena/doc/_index.html +0 -181
- data/examples/galena/doc/class_list.html +0 -36
- data/examples/galena/doc/css/common.css +0 -1
- data/examples/galena/doc/css/full_list.css +0 -53
- data/examples/galena/doc/css/style.css +0 -307
- data/examples/galena/doc/file.README.html +0 -153
- data/examples/galena/doc/file_list.html +0 -38
- data/examples/galena/doc/frames.html +0 -13
- data/examples/galena/doc/index.html +0 -153
- data/examples/galena/doc/js/app.js +0 -202
- data/examples/galena/doc/js/full_list.js +0 -149
- data/examples/galena/doc/js/jquery.js +0 -154
- data/examples/galena/doc/method_list.html +0 -163
- data/examples/galena/doc/top-level-namespace.html +0 -112
- data/lib/README.html +0 -33
- data/lib/catissue/database/annotation/annotatable_service.rb +0 -25
- data/lib/catissue/database/annotation/entity_manager.rb +0 -10
- data/lib/galena/cli/seed.rb +0 -43
- data/lib/galena/migration/filter_shims.rb +0 -43
- data/lib/galena/migration/frozen_shims.rb +0 -53
- data/lib/galena/seed/defaults.rb +0 -109
@@ -22,8 +22,8 @@ module CaTissue
|
|
22
22
|
# located_at_position is cascaded but not fetched.
|
23
23
|
add_dependent_attribute(:located_at_position, :unfetched)
|
24
24
|
|
25
|
-
# Like SCG, Container name is ignored and assigned by caTissue
|
26
|
-
# attribute is marked auto-generated.
|
25
|
+
# caTissue alert - Like SCG, the Container save argument name value is ignored and assigned by caTissue
|
26
|
+
# to a different value instead. Therefore, this attribute is marked auto-generated.
|
27
27
|
qualify_attribute(:name, :autogenerated)
|
28
28
|
|
29
29
|
# Returns the ContainerType which constrains a Container in its roles as a Storable
|
@@ -53,9 +53,6 @@ module CaTissue
|
|
53
53
|
|
54
54
|
# Lazy-initializes this Container's capacity to a copy of the {#storable_type} capacity.
|
55
55
|
def capacity
|
56
|
-
# caTissue alert - this override is necessary because the +caTissue+ API does
|
57
|
-
# not make the reasonable assumption that the default Container capacity is the
|
58
|
-
# ContainerType capacity.
|
59
56
|
getCapacity or copy_container_type_capacity
|
60
57
|
end
|
61
58
|
|
@@ -151,9 +148,11 @@ module CaTissue
|
|
151
148
|
# coordinate. The default coordinate is the first available slot within this Container.
|
152
149
|
# The storable Storable position is updated to reflect the new location. Returns self.
|
153
150
|
#
|
154
|
-
#
|
155
|
-
#
|
156
|
-
|
151
|
+
# @param [Storable] storable the item to add
|
152
|
+
# @param [CaRuby::Coordinate, nil] coordinate the x-y coordinate to place the item
|
153
|
+
# @raise [IndexError] if this Container is full
|
154
|
+
# @raise [IndexError] if the row and column are given but exceed the Container bounds
|
155
|
+
def add(storable, coordinate=nil)
|
157
156
|
validate_type(storable)
|
158
157
|
loc = create_location(coordinate)
|
159
158
|
pos = storable.position || storable.position_class.new
|
@@ -219,12 +218,17 @@ module CaTissue
|
|
219
218
|
|
220
219
|
# Copies this Container's ContainerType capacity, if it exists, to the Container capacity.
|
221
220
|
#
|
221
|
+
# caTissue alert - this method must be called by subclass initializers. The caTissue API
|
222
|
+
# does not make the reasonable assumption that the default Container capacity is the
|
223
|
+
# ContainerType capacity.
|
224
|
+
#
|
222
225
|
# @return [Capacity, nil] the initialized capacity, if any
|
223
226
|
def copy_container_type_capacity
|
224
227
|
return unless container_type and container_type.capacity
|
225
|
-
self.capacity = container_type.capacity.copy(:rows, :columns)
|
228
|
+
self.capacity = cpc = container_type.capacity.copy(:rows, :columns)
|
229
|
+
logger.debug { "Initialized #{qp} capacity from #{container_type.qp} capacity #{cpc}." }
|
226
230
|
update_full_flag
|
227
|
-
|
231
|
+
cpc
|
228
232
|
end
|
229
233
|
|
230
234
|
def update_full_flag
|
@@ -17,5 +17,13 @@ module CaTissue
|
|
17
17
|
set_attribute_inverse(:occupied_container, :located_at_position)
|
18
18
|
|
19
19
|
qualify_attribute(:parent_container, :fetched)
|
20
|
+
|
21
|
+
# @raise [ValidationError] if the parent is the same as the occupant
|
22
|
+
def validate
|
23
|
+
super
|
24
|
+
if parent == occupant or (parent.identifier and parent.identifier == occupant.identifier) then
|
25
|
+
raise ValidationError.new("#{self} has a circular containment reference to subcontainer #{occupant}")
|
26
|
+
end
|
27
|
+
end
|
20
28
|
end
|
21
29
|
end
|
@@ -8,9 +8,10 @@ module CaTissue
|
|
8
8
|
# Each {ContainerType} subclass is required to implement the container_class method.
|
9
9
|
#
|
10
10
|
# caTissue alert - the ContainerType and Container class hierarchy is a confusing
|
11
|
-
# olio of entangled relationships.
|
12
|
-
#
|
13
|
-
#
|
11
|
+
# olio of entangled relationships. The canonical use case is as follows:
|
12
|
+
# * A Specimen is contained in a box, vial or specimen array.
|
13
|
+
# * A vial or specimen array can also be placed in a box.
|
14
|
+
# * A frozen specimen container is placed on a rack in a freezer.
|
14
15
|
#
|
15
16
|
# This conceptual model is implemented in caTissue as follows:
|
16
17
|
# * The specimen collection container type, e.g. +Citrate Vacutainer+, is captured
|
@@ -43,18 +44,24 @@ module CaTissue
|
|
43
44
|
# a specimen position in a box, whereas {CaTissue::SpecimenArrayContent} is functionally
|
44
45
|
# a specimen position in a specimen array.
|
45
46
|
#
|
46
|
-
# The ContainerType/Container mish-mash is partially
|
47
|
+
# The ContainerType/Container mish-mash is partially rationalized in caRuby as follows:
|
47
48
|
# * {CaTissue::StorageType} and {CaTissue::StorageContainer} include the
|
48
49
|
# {CaTissue::StorageTypeHolder} module, which unifies treatment of contained
|
49
50
|
# types.
|
50
51
|
# * Similarly, {CaTissue::AbstractPosition} and {CaTissue::SpecimenArrayContent} include
|
51
52
|
# the {CaTissue::Position} module, which unifies treatment of positions.
|
52
|
-
# * Contained child types are consolidated into {CaTissue::StorageTypeHolder#child_types}
|
53
|
+
# * Contained child types are consolidated into {CaTissue::StorageTypeHolder#child_types}.
|
53
54
|
# * Similarly, {CaTissue::StorageContainer} child items are consolidated into
|
54
|
-
# {CaTissue::StorageContainer#child_types}
|
55
|
+
# {CaTissue::StorageContainer#child_types}.
|
55
56
|
# * The various container and position classes are augmented with helper methods to
|
56
57
|
# add, move and find specimens and subcontainers. These methods hide the mind-numbing
|
57
58
|
# eccentricity of caTissue specimen storage interaction.
|
59
|
+
# The entire amalgamation is further simplifying by introducing the standard Ruby
|
60
|
+
# container add method {CaTissue::Container::<<}. The only call the caRuby client
|
61
|
+
# needs to make to add a specimen box to a freezer is:
|
62
|
+
# freezer << box
|
63
|
+
# which places the box in the first available rack slot in the freezer, or:
|
64
|
+
# freezer.add box :at =>
|
58
65
|
class ContainerType
|
59
66
|
include Resource
|
60
67
|
|
@@ -34,24 +34,29 @@ module CaTissue
|
|
34
34
|
# it appears as Female in the GUI even though it is null in the database.
|
35
35
|
add_mandatory_attributes(:activity_status, :gender)
|
36
36
|
|
37
|
-
|
37
|
+
# caTissue alert - Participant CPR cascade is simulated in the bizlogic.
|
38
|
+
# See the PMI comment below.
|
39
|
+
add_dependent_attribute(:collection_protocol_registrations)
|
38
40
|
|
39
41
|
add_dependent_attribute(:races)
|
40
42
|
|
41
|
-
# PMI is
|
43
|
+
# caTissue alert - Participant PMI is fetched but not cascaded. However, the Participant bizlogic
|
44
|
+
# simulates PMI cascade. The bizlogic doesn't document why this is done, but it appears that the
|
45
|
+
# reason is to inject an empty PMI if necessary in order to work around a caTissue query bug
|
46
|
+
# (see merge_attribute comment). At any rate, mark PMI as cascaded in the caRuby metadata
|
47
|
+
# to reflect the bizlogic simulation. However, this designation should be revisited with each
|
48
|
+
# release, since if the bizlogic hack is removed then caRuby Participant PMI save will break.
|
42
49
|
add_dependent_attribute(:participant_medical_identifiers)
|
43
50
|
|
44
51
|
# SSN is a key, if present, but is not required.
|
45
52
|
qualify_attribute(:social_security_number, :optional)
|
53
|
+
|
54
|
+
# The clinicial annotation.
|
55
|
+
add_annotation('Clinical', :package => 'clinical_annotation', :service => 'CA')
|
46
56
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
def merge_attribute_value(attribute, oldval, newval)
|
52
|
-
# caTissue alert - remove the autogenerated blank PMI.
|
53
|
-
# TODO - file bug
|
54
|
-
# @see CaTissue::Database#query_safe
|
57
|
+
# caTissue alert - remove the autogenerated blank PMI.
|
58
|
+
# cf. https://cabig-kc.nci.nih.gov/Biospecimen/forums/viewtopic.php?f=19&t=436&sid=ef98f502fc0ab242781b7759a0eaff36
|
59
|
+
def merge_attribute(attribute, newval, matches=nil)
|
55
60
|
if attribute == :participant_medical_identifiers and newval then
|
56
61
|
CaTissue::Participant.remove_empty_medical_identifier(newval)
|
57
62
|
end
|
data/lib/catissue/domain/site.rb
CHANGED
@@ -5,9 +5,6 @@ module CaTissue
|
|
5
5
|
# The Site domain class.
|
6
6
|
class Site
|
7
7
|
include Resource
|
8
|
-
|
9
|
-
# The default pre-defined caTissue site name.
|
10
|
-
DEF_SITE_NAME = 'In Transit'
|
11
8
|
|
12
9
|
# caTissue alert - the Site SCG collection is ignored, since it is not fetched with the Site,
|
13
10
|
# the caCORE query builder doesn't support abstract types, and even if it worked it would
|
@@ -29,5 +26,14 @@ module CaTissue
|
|
29
26
|
LABORATORY = 'Laboratory'
|
30
27
|
REPOSITORY = 'Repository'
|
31
28
|
end
|
29
|
+
|
30
|
+
def self.default_site
|
31
|
+
@@def_site ||= new(:name => DEF_SITE_NAME)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# The default pre-defined caTissue site name.
|
37
|
+
DEF_SITE_NAME = 'In Transit'
|
32
38
|
end
|
33
39
|
end
|
@@ -12,7 +12,7 @@ module CaTissue
|
|
12
12
|
include Validation, Storable, Resource
|
13
13
|
|
14
14
|
# caTissue alert - Bug #64: Some domain collection properties not initialized.
|
15
|
-
# Initialize consent_tier_statuses if necessary.
|
15
|
+
# Initialize consent_tier_statuses if necessary.
|
16
16
|
#
|
17
17
|
# @return [Java::JavaUtil::Set] the statuses
|
18
18
|
def consent_tier_statuses
|
@@ -50,9 +50,18 @@ module CaTissue
|
|
50
50
|
# A child Specimen is auto-generated from a SpecimenRequirement template if it
|
51
51
|
# is part of a hierarchy built by SCG create. Unlike SpecimenRequirement,
|
52
52
|
# Specimen children are cascaded.
|
53
|
-
|
53
|
+
qualify_attribute(:child_specimens, :autogenerated)
|
54
54
|
|
55
55
|
# caTissue alert - Specimen consent_tier_statuses is cascaded but not fetched.
|
56
|
+
#
|
57
|
+
# caTissue alert - When a Specimen is auto-generated or created, a consent tier
|
58
|
+
# status is created for each registration consent. A created Specimen has a
|
59
|
+
# a well-formed status record. An auto-generated status record is malformed,
|
60
|
+
# missing the Specimen id reference. This differs from the auto-generated
|
61
|
+
# SCG status record, which is malformed in a different way which results in
|
62
|
+
# a severe display error, as described in Bug #156. The malformed Specimen
|
63
|
+
# status record results in displaying null field values in the Specimen Consent
|
64
|
+
# page, but otherwise no adverse effects.
|
56
65
|
add_dependent_attribute(:consent_tier_statuses, :unfetched)
|
57
66
|
|
58
67
|
# caTissue alert - Bug #163: ExternalIdentifer not fetched with Specimen in API.
|
@@ -87,10 +96,19 @@ module CaTissue
|
|
87
96
|
# available_quantity is not reflected in the caCORE create or update result.
|
88
97
|
# This is true even though the caTissue GUI supports available_quantity update.
|
89
98
|
# Work-around is to set the :autogenerated flag, which will refetch a saved Specimen
|
90
|
-
#
|
91
|
-
# argument.
|
99
|
+
# if there is a change to the available_quantity value and will reupdate the Specimen
|
100
|
+
# if the fetched available_quantity differs from the save argument value.
|
92
101
|
qualify_attribute(:available_quantity, :autogenerated)
|
93
102
|
|
103
|
+
# caTissue alert - An auto-generated Specimen auto-generates the collection and received events.
|
104
|
+
# Therefore, CPR create must match the complete auto-generated SCG-Specimen-Event hierarchy.
|
105
|
+
# However, SpecimenRequirement events are not auto-generated. Therefore, the AbstractSpecimen
|
106
|
+
# events behavior must be specialized for Specimen but not SpecimenRequirement.
|
107
|
+
qualify_attribute(:specimen_events, :autogenerated)
|
108
|
+
|
109
|
+
# The Specimen pathology annotation.
|
110
|
+
add_annotation('Pathology', :package => 'pathology_specimen', :service => 'pathologySpecimen')
|
111
|
+
|
94
112
|
# Specimen storage is constrained on the basis of the +specimen_class+.
|
95
113
|
alias :storable_type :specimen_class
|
96
114
|
|
@@ -114,11 +132,17 @@ module CaTissue
|
|
114
132
|
def collected?
|
115
133
|
collection_status == 'Collected'
|
116
134
|
end
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
135
|
+
|
136
|
+
# Relaxes the {CaRuby::Persistable#fetch_saved?} condition for a Specimen as follows:
|
137
|
+
# * If the Specimen available_quantity was updated, then fetch the saved Specimen.
|
138
|
+
#
|
139
|
+
# @return (see CaRuby::Persistable#fetch_saved)
|
140
|
+
def fetch_saved?
|
141
|
+
super and available_quantity_changed?
|
142
|
+
end
|
143
|
+
# caTissue alert - remove the autogenerated blank ExternalIdentifier.
|
144
|
+
# cf. https://cabig-kc.nci.nih.gov/Biospecimen/forums/viewtopic.php?f=19&t=436&sid=ef98f502fc0ab242781b7759a0eaff36
|
145
|
+
def merge_attribute(attribute, newval, matches=nil)
|
122
146
|
if attribute == :external_identifiers and newval then
|
123
147
|
CaTissue::Specimen.remove_empty_external_identifier(newval)
|
124
148
|
end
|
@@ -140,22 +164,21 @@ module CaTissue
|
|
140
164
|
# Override default {CaRuby::Resource#merge_attributes} to ignore a source SpecimenRequirement parent_specimen.
|
141
165
|
def merge_attributes(other, attributes=nil)
|
142
166
|
case other
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
super
|
167
|
+
when SpecimenRequirement then
|
168
|
+
# merge with the default requirement merge attributes if necessary
|
169
|
+
attributes ||= MERGEABLE_RQMT_ATTRS
|
170
|
+
super(other, attributes)
|
171
|
+
# copy the requirement characteristics
|
172
|
+
sc = other.specimen_characteristics
|
173
|
+
self.specimen_characteristics ||= sc.copy(MERGEABLE_SPC_CHR_ATTRS) if sc
|
174
|
+
when Hashable then
|
175
|
+
# the requirement template
|
176
|
+
rqmt = other[:specimen_requirement] || other[:requirement]
|
177
|
+
# merge the attribute => value hash
|
178
|
+
super
|
179
|
+
# merge the SpecimenRequirement after the hash
|
180
|
+
merge_attributes(rqmt) if rqmt
|
181
|
+
else super
|
159
182
|
end
|
160
183
|
self
|
161
184
|
end
|
@@ -200,6 +223,17 @@ module CaTissue
|
|
200
223
|
end
|
201
224
|
end
|
202
225
|
|
226
|
+
# Augments {AbstractSpecimen#minimal_match?} with an additional restriction that the other
|
227
|
+
# specimen is in pending state. This ensures that a specimen submitted for create matches
|
228
|
+
# its auto-generated counterpart but a new specimen can be created even if it matches an
|
229
|
+
# existing specimen on the features described in {AbstractSpecimen#minimal_match?}.
|
230
|
+
#
|
231
|
+
# @param (see CaRuby::Resource#minimal_match?)
|
232
|
+
# @return (see CaRuby::Resource#minimal_match?)
|
233
|
+
def minimal_match?(other)
|
234
|
+
super and other.collection_status == 'Pending'
|
235
|
+
end
|
236
|
+
|
203
237
|
# @return the SpecimenPosition class which this Specimen's Storable can occupy
|
204
238
|
def position_class
|
205
239
|
CaTissue::SpecimenPosition
|
@@ -334,7 +368,24 @@ module CaTissue
|
|
334
368
|
MERGEABLE_RQMT_ATTRS = nondomain_java_attributes - primary_key_attributes
|
335
369
|
|
336
370
|
MERGEABLE_SPC_CHR_ATTRS = SpecimenCharacteristics.nondomain_java_attributes - SpecimenCharacteristics.primary_key_attributes
|
337
|
-
|
371
|
+
|
372
|
+
# @see #fetch_saved
|
373
|
+
def available_quantity_changed?
|
374
|
+
oldval = snapshot && snapshot[:available_quantity]
|
375
|
+
newval = available_quantity
|
376
|
+
if oldval and oldval != newval then
|
377
|
+
logger.debug { "Saved #{qp} must be fetched from the database to reflect the current database state, since the available quantity was changed from #{oldval} to #{newval}." }
|
378
|
+
true
|
379
|
+
else
|
380
|
+
false
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
def format_saved_fetch_message(fetch, reason)
|
385
|
+
args = fetch ? [qp, 'must', reason] : [qp, 'does not need to', reason]
|
386
|
+
SAVED_FETCH_MSG % args
|
387
|
+
end
|
388
|
+
|
338
389
|
# Adds this Specimen's defaults, as follows:
|
339
390
|
# * The default specimen_collection_group is the parent specimen_collection_group.
|
340
391
|
# * Add default collection and received event parameters if this Specimen is collected.
|
@@ -353,7 +404,7 @@ module CaTissue
|
|
353
404
|
# is set to false (0 database value) when the record is inserted.
|
354
405
|
#
|
355
406
|
# caTissue alert - a collected Specimen without a collection and received event parameters
|
356
|
-
# results in the dreaded 'Severe Error' server message.
|
407
|
+
# results in the dreaded 'Severe Error' caTissue server message. Create default SEPs if necessary.
|
357
408
|
def add_defaults_local
|
358
409
|
super
|
359
410
|
self.specimen_collection_group ||= parent.specimen_collection_group if parent
|
@@ -373,7 +424,7 @@ module CaTissue
|
|
373
424
|
# Adds the default collection and received event parameters if the collection status
|
374
425
|
# is +Collected+.
|
375
426
|
def add_default_event_parameters
|
376
|
-
if
|
427
|
+
if collected? and specimen_collection_group then
|
377
428
|
unless event_parameters.detect { |ep| CaTissue::CollectionEventParameters === ep } then
|
378
429
|
CaTissue::CollectionEventParameters.new(:specimen => self, :user => specimen_collection_group.collector)
|
379
430
|
end
|
@@ -428,18 +479,6 @@ module CaTissue
|
|
428
479
|
CaTissue.domain_type_with_name(class_name) or raise ArgumentError.new("Specimen class #{class_name} is not recognized for specimen type parameter #{symbol}")
|
429
480
|
end
|
430
481
|
|
431
|
-
# def default_specimen_characteristics
|
432
|
-
# return if specimen_collection_group.nil?
|
433
|
-
# rqmts = specimen_collection_group.requirements
|
434
|
-
# # match the requirement specimen type
|
435
|
-
# rqmt = specimen_collection_group.requirements.detect { |rqmt| specimen_type == rqmt.specimen_type }
|
436
|
-
# # fallback is match on requirement class and generic requirment specimen type
|
437
|
-
# rqmt ||= specimen_collection_group.requirements.detect do |rqmt|
|
438
|
-
# specimen_class === rqmt.specimen_class and rqmt.specimen_type.nil? or rqmt.specimen_type == 'Not Specified'
|
439
|
-
# end
|
440
|
-
# rqmt.specimen_characteristics.copy if rqmt
|
441
|
-
# end
|
442
|
-
|
443
482
|
# Decrements this parent's available quantity by the given child's initial quantity, if the specimen types are the same and there
|
444
483
|
# are the relevant quantities.
|
445
484
|
def decrement_derived_quantity(child)
|
@@ -9,7 +9,17 @@ module CaTissue
|
|
9
9
|
|
10
10
|
# caTissue alert - the superclass Container occupied_positions does not apply to SpecimenArray.
|
11
11
|
remove_attribute(:occupied_positions)
|
12
|
-
|
12
|
+
|
13
|
+
# Initializes this instance's child storage types from the given type.
|
14
|
+
#
|
15
|
+
# @param [<StorageType>] the type to set
|
16
|
+
def specimen_array_type=(type)
|
17
|
+
setSpecimenArrayType(type)
|
18
|
+
unless type.nil? then
|
19
|
+
copy_container_type_capacity
|
20
|
+
end
|
21
|
+
type
|
22
|
+
end
|
13
23
|
add_attribute_aliases(:container_type => :specimen_array_type, :contents => :specimen_array_contents)
|
14
24
|
|
15
25
|
set_attribute_type(:new_specimen_array_order_items, CaTissue::SpecimenArrayOrderItem)
|
@@ -39,19 +39,28 @@ module CaTissue
|
|
39
39
|
setSurgicalPathologyNumber(value)
|
40
40
|
end
|
41
41
|
|
42
|
-
add_attribute_aliases(:
|
42
|
+
add_attribute_aliases(:site => :specimen_collection_site,
|
43
|
+
:collection_site => :specimen_collection_site,
|
44
|
+
:collection_event => :collection_protocol_event,
|
43
45
|
:event_parameters => :specimen_event_parameters,
|
44
46
|
:events => :specimen_event_parameters,
|
45
47
|
:registration => :collection_protocol_registration)
|
46
48
|
|
49
|
+
# caTissue alert - Bug #116: specimen_collection_site is incorrectly attached in the caTissue class
|
50
|
+
# model to AbstractSpecimenCollectionGroup rather than SpecimenCollectionGroup. CollectionProtocolEvent
|
51
|
+
# is a subclass of AbstractSpecimenCollectionGroup but does not have a collection site. Therfore, the
|
52
|
+
# specimen_collection_site is ignored in the caRuby AbstractSpecimenCollectionGroup class declaration
|
53
|
+
# and declared as an aliased, mandatory, fetched attribute for the SpecimenCollectionGroup subclass only.
|
47
54
|
add_mandatory_attributes(:specimen_event_parameters, :specimen_collection_site, :clinical_diagnosis, :collection_status)
|
55
|
+
|
56
|
+
qualify_attribute(:specimen_collection_site, :fetched)
|
48
57
|
|
49
58
|
set_secondary_key_attributes(:name)
|
50
59
|
|
51
60
|
set_alternate_key_attributes(:surgical_pathology_number, :collection_protocol_registration)
|
52
61
|
|
53
|
-
# caTissue alert - An auto-generated
|
54
|
-
#
|
62
|
+
# caTissue alert - An auto-generated or created SCG auto-generates a ConsentTierStatus for each
|
63
|
+
# ConsentTierResponse defined in the SCG owner CPR.
|
55
64
|
#
|
56
65
|
# caTissue alert - SCG consent_tier_statuses is cascaded but not fetched.
|
57
66
|
add_dependent_attribute(:consent_tier_statuses, :autogenerated, :unfetched)
|
@@ -70,6 +79,12 @@ module CaTissue
|
|
70
79
|
|
71
80
|
# SCG Specimens are auto-generated from SpecimenRequirement templates when the SCG is created.
|
72
81
|
# The Specimens are not cascaded.
|
82
|
+
#
|
83
|
+
# caTissue alert - SCG specimens query result does not set the Specimen children and parent, even
|
84
|
+
# though they are guaranteed to be in the SCG specimens result set. The children and parent must be
|
85
|
+
# fetched separately, resulting in redundant copies of the same Specimen and additional fetches.
|
86
|
+
# caRuby partially rectifies this lapse by reconciling the SCG specimens parent-child relationships
|
87
|
+
# within the SCG scope.
|
73
88
|
add_dependent_attribute(:specimens, :logical, :autogenerated)
|
74
89
|
|
75
90
|
# The CPE-SCG association is bi-directional.
|
@@ -82,12 +97,14 @@ module CaTissue
|
|
82
97
|
# SpecimenCollectionGroup update object references a CollectionProtocolRegistration with a Participant reference.
|
83
98
|
# The CPR identifier should be sufficient for a SCG update, but caTissue bizlogic requires an extraneous
|
84
99
|
# CPR -> Participant reference.
|
85
|
-
# TODO - file a bug and reference it here
|
86
100
|
qualify_attribute(:collection_protocol_registration, :cascaded)
|
87
101
|
|
88
102
|
# caTissue alert - Bug #65: Although SCG name uniquely identifies a SCG, the SCG name is auto-generated on create
|
89
103
|
# and cannnot be set by the client. Therefore, name is marked as update_only.
|
90
104
|
qualify_attribute(:name, :autogenerated, :update_only)
|
105
|
+
|
106
|
+
# The SCG pathology annotation.
|
107
|
+
add_annotation('Pathology', :package => 'pathology_scg', :service => 'pathologySCG')
|
91
108
|
|
92
109
|
# caTissue alert - Bug #64: Initialize the SCG consent_tier_statuses to an empty set.
|
93
110
|
def initialize(params=nil)
|
@@ -223,6 +240,17 @@ module CaTissue
|
|
223
240
|
super
|
224
241
|
end
|
225
242
|
end
|
243
|
+
|
244
|
+
CONSENT_TIER_STATUS_ATTRS = [:consent_tier_statuses]
|
245
|
+
|
246
|
+
def mandatory_attributes
|
247
|
+
attrs = super
|
248
|
+
if registration and not registration.consent_tier_responses.empty? then
|
249
|
+
attrs + CONSENT_TIER_STATUS_ATTRS
|
250
|
+
else
|
251
|
+
attrs
|
252
|
+
end
|
253
|
+
end
|
226
254
|
|
227
255
|
def validate
|
228
256
|
super
|
@@ -230,60 +258,58 @@ module CaTissue
|
|
230
258
|
validate_event_parameters
|
231
259
|
end
|
232
260
|
|
233
|
-
#
|
234
|
-
#
|
235
|
-
# If the SCG status was created or was updated from +Pending+ to +Collected+,
|
236
|
-
# then fetch the saved SCG. Otherwise, forego fetching the saved SCG.
|
261
|
+
# Relaxes the {CaRuby::Persistable#saved_fetch_attributes} condition for a SCG as follows:
|
262
|
+
# * If the SCG status was updated from +Pending+ to +Collected+, then fetch the saved SCG event parameters.
|
237
263
|
#
|
238
|
-
# @
|
239
|
-
|
240
|
-
|
264
|
+
# @param (see CaRuby::Persistable#saved_fetch_attributes)
|
265
|
+
# @return (see CaRuby::Persistable#saved_fetch_attributes)
|
266
|
+
def saved_fetch_attributes(operation)
|
267
|
+
operation == :update && status_changed_to_complete? ? EVENT_PARAM_ATTRS : super
|
268
|
+
end
|
269
|
+
|
270
|
+
# Relaxes the {CaRuby::Persistable#saved_fetch_attributes} condition for a SCG as follows:
|
271
|
+
# * If the SCG status was updated from +Pending+ to +Collected+, then fetch the saved SCG event parameters.
|
272
|
+
#
|
273
|
+
# @param (see CaRuby::Persistable#saved_fetch_attributes)
|
274
|
+
# @return (see CaRuby::Persistable#saved_fetch_attributes)
|
275
|
+
def autogenerated?(operation)
|
276
|
+
operation == :update && status_changed_to_complete? ? EVENT_PARAM_ATTRS : super
|
241
277
|
end
|
242
278
|
|
243
279
|
private
|
244
|
-
|
245
|
-
|
246
|
-
|
280
|
+
|
281
|
+
EVENT_PARAM_ATTRS = [:specimen_event_parameters]
|
282
|
+
|
247
283
|
# @see #fetch_saved
|
248
284
|
def status_changed_to_complete?
|
249
|
-
if
|
250
|
-
logger.debug {
|
251
|
-
true
|
252
|
-
elsif collected? and (snapshot.nil? or snapshot[:collection_status] == 'Pending') then
|
253
|
-
logger.debug { format_saved_fetch_message(true, "updated to status Complete") }
|
285
|
+
if collected? and snapshot and snapshot[:collection_status] == 'Pending' then
|
286
|
+
logger.debug { "Saved #{qp} event parameters must be fetched from the database to reflect the current database state, since the status was changed from Pending to Complete." }
|
254
287
|
true
|
255
288
|
else
|
256
|
-
logger.debug { format_saved_fetch_message(false, "not updated from pending to complete") }
|
257
289
|
false
|
258
290
|
end
|
259
291
|
end
|
260
|
-
|
261
|
-
def format_saved_fetch_message(fetch, reason)
|
262
|
-
args = fetch ? [qp, 'must', reason] : [qp, 'does not need to', reason]
|
263
|
-
SAVED_FETCH_MSG % args
|
264
|
-
end
|
265
292
|
|
266
293
|
def each_defaults_dependent
|
267
294
|
# visit ReceivedEventParameters first
|
268
295
|
rep = received_event_parameters
|
269
296
|
yield rep if rep
|
270
297
|
# add other dependent defaults
|
271
|
-
|
298
|
+
each_dependent { |dep| yield dep unless ReceivedEventParameters === dep }
|
272
299
|
end
|
273
300
|
|
274
301
|
# Adds defaults as follows:
|
275
|
-
# *
|
276
|
-
# *
|
277
|
-
# *
|
278
|
-
# otherwise the {CaTissue::Site
|
279
|
-
# *
|
280
|
-
# *
|
302
|
+
# * The default collection event is the first event in the protocol registered with this SCG.
|
303
|
+
# * The default collection status is 'Complete' if there is a received event, 'Pending' otherwise.
|
304
|
+
# * The default collection site is the CP site, if this SCG is {#received?} and there is only CP one,
|
305
|
+
# otherwise the {CaTissue::Site.default_site}.
|
306
|
+
# * The default conset tier status is 'Complete' if there is a received event, 'Pending' otherwise.
|
307
|
+
# * A default ReceivedEventParameters is added to this SCG if the collection status is
|
281
308
|
# 'Complete' and there is no other ReceivedEventParameters. The receiver is an arbitrary
|
282
309
|
# protocol coordinator.
|
283
310
|
#
|
284
|
-
#
|
285
|
-
#
|
286
|
-
#
|
311
|
+
# @raise [ValidationError] if the default ReceivedEventParameters could not be created because
|
312
|
+
# there is no protocol or protocol coordinator
|
287
313
|
# @see CollectionProtocol#first_event
|
288
314
|
def add_defaults_local
|
289
315
|
super
|
@@ -322,16 +348,22 @@ module CaTissue
|
|
322
348
|
# ensure that there is a CT status for each consent tier
|
323
349
|
registration.consent_tier_responses.each do |ctr|
|
324
350
|
ct = ctr.consent_tier
|
351
|
+
# skip if there is a status for the response tier
|
325
352
|
next if ctses.include?(ct)
|
326
|
-
|
353
|
+
# make a new status
|
354
|
+
cts = CaTissue::ConsentTierStatus.new(:consent_tier => ct)
|
355
|
+
cts.add_defaults
|
327
356
|
consent_tier_statuses << cts
|
328
357
|
logger.debug { "Made default #{qp} #{cts.qp} for consent tier #{ct.qp}." }
|
329
358
|
end
|
330
359
|
end
|
331
360
|
|
332
361
|
def default_site
|
333
|
-
|
334
|
-
cp.
|
362
|
+
return if collection_event.nil?
|
363
|
+
cp = collection_event.protocol || return
|
364
|
+
site = cp.default_site || return
|
365
|
+
logger.debug { "Default #{qp} site is #{site}." }
|
366
|
+
site
|
335
367
|
end
|
336
368
|
|
337
369
|
# Returns the first event in the protocol registered with this SCG.
|
@@ -340,7 +372,9 @@ module CaTissue
|
|
340
372
|
pcl = registration.protocol || return
|
341
373
|
# if no protocol event, then add the default event
|
342
374
|
pcl.add_defaults if pcl.events.empty?
|
343
|
-
pcl.first_event
|
375
|
+
ev = pcl.first_event || return
|
376
|
+
logger.debug { "Default #{qp} collection event is the registration protocol #{pcl.qp} first event #{ev.qp}." }
|
377
|
+
ev
|
344
378
|
end
|
345
379
|
|
346
380
|
def create_default_received_event_parameters
|
@@ -353,13 +387,17 @@ module CaTissue
|
|
353
387
|
raise ValidationError.new("SCG with status Complete default CollectionEventParameters could not be created since there is no collection protocol coordinator: #{self}")
|
354
388
|
end
|
355
389
|
# make the REP
|
356
|
-
CaTissue::SpecimenEventParameters.create_parameters(:received, self, :user => rcvr)
|
390
|
+
ev = CaTissue::SpecimenEventParameters.create_parameters(:received, self, :user => rcvr)
|
391
|
+
logger.debug { "Made default #{qp} received event parameter #{ev.qp}." }
|
392
|
+
ev
|
357
393
|
end
|
358
394
|
|
359
395
|
def create_default_collection_event_parameters
|
360
396
|
rep = received_event_parameters || return
|
361
397
|
# make the CEP from the REP
|
362
|
-
CaTissue::SpecimenEventParameters.create_parameters(:collection, self, :user => rep.user, :timestamp => rep.timestamp)
|
398
|
+
ev = CaTissue::SpecimenEventParameters.create_parameters(:collection, self, :user => rep.user, :timestamp => rep.timestamp)
|
399
|
+
logger.debug { "Made default #{qp} collected event parameter #{ev.qp}." }
|
400
|
+
ev
|
363
401
|
end
|
364
402
|
|
365
403
|
# Verifies that each registration consent tier response has a corresponding SCG consent tier status.
|
@@ -46,14 +46,11 @@ module CaTissue
|
|
46
46
|
end
|
47
47
|
event_params = klass.new(params)
|
48
48
|
case scg_or_specimen
|
49
|
-
|
50
|
-
event_params.
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
raise ArgumentError.new("Missing SpecimenEventParameters scg_or_specimen factory argument")
|
55
|
-
else
|
56
|
-
raise ArgumentError.new("Unsupported SpecimenEventParameters factory argument - expected SpecimenCollectionGroup or Specimen, found #{scg_or_specimen.class}")
|
49
|
+
when SpecimenCollectionGroup then event_params.specimen_collection_group = scg_or_specimen
|
50
|
+
when Specimen then event_params.specimen = scg_or_specimen
|
51
|
+
when nil then raise ArgumentError.new("Missing SpecimenEventParameters scg_or_specimen factory argument")
|
52
|
+
else
|
53
|
+
raise ArgumentError.new("Unsupported SpecimenEventParameters factory argument - expected SpecimenCollectionGroup or Specimen, found #{scg_or_specimen.class}")
|
57
54
|
end
|
58
55
|
event_params
|
59
56
|
end
|
@@ -34,7 +34,7 @@ module CaTissue
|
|
34
34
|
# Unlike Specimen, a child SpecimenRequirement is not cascaded by caTissue.
|
35
35
|
# It is not auto-generated, i.e. it is not created from a template when the
|
36
36
|
# parent CPE is created.
|
37
|
-
|
37
|
+
qualify_attribute(:child_specimens, :logical)
|
38
38
|
|
39
39
|
# Overrides {Resource#owner} to return the parent_specimen, if it exists, or the collection_protocol_event otherwise.
|
40
40
|
def owner
|