1 package CXGN
::BrAPI
::v2
::ObservationUnits
;
5 use SGN
::Model
::Cvterm
;
8 use CXGN
::Trial
::TrialLayoutSearch
;
9 use CXGN
::BrAPI
::Pagination
;
10 use CXGN
::BrAPI
::JSONResponse
;
11 use CXGN
::BrAPI
::v2
::ExternalReferences
;
13 use CXGN
::List
::Transform
;
14 use Scalar
::Util
qw(looks_like_number);
18 extends
'CXGN::BrAPI::v2::Common';
24 my $page_size = $self->page_size;
25 my $page = $self->page;
26 my $status = $self->status;
31 my ($data,$total_count, $page_size,$page,$status) = _search
($self, $params, $c);
33 my %results = (data
=>$data);
34 my $pagination = CXGN
::BrAPI
::Pagination
->pagination_response($total_count,$page_size,$page);
35 return CXGN
::BrAPI
::JSONResponse
->return_success(\
%results, $pagination, \
@data_files, $status, 'Observation Units search result constructed');
44 my $page_size = $self->page_size;
45 my $page = $self->page;
46 my $status = $self->status;
49 my $data_level = $params->{observationUnitLevelName
} || ['all'];
50 my $years_arrayref = $params->{seasonDbId
} || ($params->{seasonDbIds
} || ());
51 my $location_ids_arrayref = $params->{locationDbId
} || ($params->{locationDbIds
} || ());
52 my $accession_ids_arrayref = $params->{germplasmDbId
} || ($params->{germplasmDbIds
} || ());
53 my $trait_list_arrayref = $params->{observationVariableName
} || ($params->{observationVariableNames
} || ());
54 my $trait_ids_arrayref = $params->{observationVariableDbId
} || ($params->{observationVariableDbIds
} || ());
55 my $program_ids_arrayref = $params->{programDbId
} || ($params->{programDbIds
} || ());
56 my $folder_ids_arrayref = $params->{trialDbId
} || ($params->{trialDbIds
} || ());
57 my $start_time = $params->{observationTimeStampRangeStart
}->[0] || undef;
58 my $end_time = $params->{observationTimeStampRangeEnd
}->[0] || undef;
59 my $observation_unit_db_id = $params->{observationUnitDbId
} || ($params->{observationUnitDbIds
} || ());
60 my $observation_unit_names_list = $params->{observationUnitName
} || ($params->{observationUnitNames
} || ());
61 my $include_observations = $params->{includeObservations
} || "False";
62 $include_observations = ref($include_observations) eq 'ARRAY' ?
${$include_observations}[0] : $include_observations;
63 my $level_order_arrayref = $params->{observationUnitLevelOrder
} || ($params->{observationUnitLevelOrders
} || ());
64 my $level_code_arrayref = $params->{observationUnitLevelCode
} || ($params->{observationUnitLevelCodes
} || ());
65 my $levels_relation_arrayref = $params->{observationLevelRelationships
} || ();
66 my $levels_arrayref = $params->{observationLevels
} || ();
67 my $reference_ids_arrayref = $params->{externalReferenceId
} || $params->{externalReferenceID
} || ($params->{externalReferenceIds
} || $params->{externalReferenceIDs
} || ());
68 my $reference_sources_arrayref = $params->{externalReferenceSource
} || ($params->{externalReferenceSources
} || ());
70 my $study_ids_arrayref = $params->{studyDbId
} || ($params->{studyDbIds
} || ());
72 my $phenotype_additional_info_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'phenotype_additional_info', 'phenotype_property')->cvterm_id();
73 my $external_references_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'phenotype_external_references', 'phenotype_property')->cvterm_id();
74 my $plot_geo_json_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'plot_geo_json', 'stock_property')->cvterm_id();
75 my $stock_additional_info_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'stock_additional_info', 'stock_property')->cvterm_id();
77 if ($levels_arrayref){
79 foreach ( @
{$levels_arrayref} ){
80 push @
$level_code_arrayref, $_->{levelCode
} if ($_->{levelCode
});
81 push @
{$data_level}, $_->{levelName
} if ($_->{levelName
});
84 $data_level = ['all'];
87 my $main_production_site_url = $c->config->{main_production_site_url
};
89 my $lt = CXGN
::List
::Transform
->new();
91 if (!$trait_ids_arrayref && $trait_list_arrayref) {
92 $trait_ids_arrayref = $lt->transform($self->bcs_schema, "traits_2_trait_ids", $trait_list_arrayref)->{transform
};
95 my $limit = $page_size;
96 my $offset = $page_size*$page;
97 print STDERR
"ObservationUnits call Checkpoint 1: ".DateTime
->now()."\n";
99 my $layout_search = CXGN
::Trial
::TrialLayoutSearch
->new(
101 bcs_schema
=>$self->bcs_schema,
102 data_level
=>$data_level->[0],
103 trial_list
=>$study_ids_arrayref,
104 location_list
=>$location_ids_arrayref,
105 accession_list
=>$accession_ids_arrayref,
106 folder_list
=>$folder_ids_arrayref,
107 program_list
=>$program_ids_arrayref,
108 observation_unit_id_list
=>$observation_unit_db_id,
109 observation_unit_names_list
=>$observation_unit_names_list,
110 experiment_type
=>'field_layout',
111 include_observations
=> lc($include_observations) eq 'true' ?
1 : 0,
112 xref_id_list
=>$reference_ids_arrayref,
113 xref_source_list
=>$reference_sources_arrayref,
114 order_by
=> ($c && $c->config->{brapi_ou_order_plot_num
}) ?
'NULLIF(regexp_replace(plot_number, \'\D\', \'\', \'g\'), \'\')::numeric' : undef,
119 my ($data,$observations_data) = $layout_search->search();
120 print STDERR
"ObservationUnits call Checkpoint 2: ".DateTime
->now()."\n";
121 #print STDERR Dumper $data;
122 my $start_index = $page*$page_size;
123 my $end_index = $page*$page_size + $page_size - 1;
127 # Get the plot parents of the plants
130 foreach my $obs_unit (@
$data){
131 if ($obs_unit->{obsunit_type_name
} eq 'plant') {
132 push @plant_ids, $obs_unit->{obsunit_stock_id
};
135 if (@plant_ids && scalar @plant_ids > 0) {
136 %plant_parents = $self->_get_plants_plot_parent(\
@plant_ids);
138 print STDERR
"ObservationUnits call Checkpoint 3: ".DateTime
->now()."\n";
139 foreach my $obs_unit (@
$data){
141 ## Formatting observations
142 my $brapi_observations = [];
144 if( lc $include_observations eq 'true' && $observations_data) {
145 my $observation_id = $obs_unit->{obsunit_stock_id
};
146 $brapi_observations = %{$observations_data}{$observation_id} ?
%{$observations_data}{$observation_id} : [];
149 ## Formatting treatments
150 my @brapi_treatments;
152 if ($c->config->{brapi_treatments_no_management_factor
}) {
153 my $treatments = $obs_unit->{treatments
};
154 foreach my $treatment (@
$treatments) {
155 while (my ($factor, $modality) = each %$treatment) {
156 my $modality = $modality ?
$modality : undef;
157 push @brapi_treatments, {
159 modality
=> $modality,
165 ## Getting gps coordinates
168 $sp_rs = $self->bcs_schema->resultset("Stock::Stockprop")->search({ type_id
=> $plot_geo_json_type_id, stock_id
=> $obs_unit->{obsunit_stock_id
} });
170 my %geolocation_lookup;
171 while( my $r = $sp_rs->next()){
172 $geolocation_lookup{$r->stock_id} = $r->value;
174 my $geo_coordinates_string = $geolocation_lookup{$obs_unit->{obsunit_stock_id
}} ?
$geolocation_lookup{$obs_unit->{obsunit_stock_id
}} : undef;
177 if ($geo_coordinates_string){
178 $geo_coordinates = decode_json
$geo_coordinates_string;
181 ## Getting additional info
184 my $rs = $self->bcs_schema->resultset("Stock::Stockprop")->search({ type_id
=> $stock_additional_info_type_id, stock_id
=> $obs_unit->{obsunit_stock_id
} });
185 if ($rs->count() > 0){
186 my $additional_info_json = $rs->first()->value();
187 $additional_info = $additional_info_json ? decode_json
($additional_info_json) : undef;
192 my $entry_type = $obs_unit->{is_a_control
} ?
'check' : 'test';
193 $numbers{entry_type
} = $entry_type;
195 my $replicate = $obs_unit->{rep
};
196 $numbers{replicate
} = $replicate;
198 my $block = $obs_unit->{block
};
199 $numbers{block
} = $block;
209 ## Following code lines add observationUnitParent to additionalInfo, useful for BI
210 if ($obs_unit->{obsunit_type_name
} eq 'plant') {
211 $plant = $obs_unit->{plant_number
};
213 $numbers{plant
} = $plant;
215 if ($plant_parents{$obs_unit->{obsunit_stock_id
}}) {
216 my $plot_object = $plant_parents{$obs_unit->{obsunit_stock_id
}};
217 $plot = $plot_object->{plot_number
};
219 $numbers{plot
} = $plot;
221 $additional_info->{observationUnitParent
} = $plot_object->{id
};
224 $plot = $obs_unit->{plot_number
};
225 $numbers{plot
} = $plot;
228 ## Format position coordinates
229 my $level_name = $obs_unit->{obsunit_type_name
};
231 # print STDERR "LEVEL NAME: ".Dumper(\%numbers);
233 my $level_order = _order
($level_name) + 0;
235 my $level_code = $numbers{$level_name}; ###### eval "\$$level_name" || "";
237 if ( $level_order_arrayref && ! grep { $_ eq $level_order } @
{$level_order_arrayref} ) { next; }
238 if ( $level_code_arrayref && ! grep { $_ eq $level_code } @
{$level_code_arrayref} ) { next; }
240 my @observationLevelRelationships;
242 push @observationLevelRelationships, {
243 levelCode
=> $replicate,
245 levelOrder
=> _order
("rep"),
249 push @observationLevelRelationships, {
251 levelName
=> "block",
252 levelOrder
=> _order
("block"),
256 push @observationLevelRelationships, {
257 levelCode
=> qq|$plot|,
259 levelOrder
=> _order
("plot"),
263 push @observationLevelRelationships, {
265 levelName
=> "plant",
266 levelOrder
=> _order
("plant"),
270 my %observationUnitPosition = (
271 entryType
=> $entry_type,
272 geoCoordinates
=> $geo_coordinates,
273 positionCoordinateX
=> $obs_unit->{col_number
} ?
$obs_unit->{col_number
} + 0 : undef,
274 positionCoordinateXType
=> 'GRID_COL',
275 positionCoordinateY
=> $obs_unit->{row_number
} ?
$obs_unit->{row_number
} + 0 : undef,
276 positionCoordinateYType
=> 'GRID_ROW',
277 observationLevel
=> {
278 levelName
=> $level_name,
279 levelOrder
=> $level_order,
280 levelCode
=> $level_code,
282 observationLevelRelationships
=> \
@observationLevelRelationships,
285 my $brapi_observationUnitPosition = decode_json
(encode_json \
%observationUnitPosition);
287 #Get external references
288 my $references = CXGN
::BrAPI
::v2
::ExternalReferences
->new({
289 bcs_schema
=> $self->bcs_schema,
290 table_name
=> 'stock',
291 table_id_key
=> 'stock_id',
292 id
=> qq|$obs_unit->{obsunit_stock_id
}|
294 my $external_references = $references->search();
295 my @formatted_external_references = %{$external_references} ?
values %{$external_references} : [];
300 my $image_id = CXGN
::Stock
->new({
301 schema
=> $self->bcs_schema,
302 stock_id
=> $obs_unit->{obsunit_stock_id
},
304 @plot_image_ids = $image_id->get_image_ids();
307 foreach my $arrayimage (@plot_image_ids){
308 push @ids, $arrayimage->[0];
311 if ($obs_unit->{family_stock_id
}) {
312 $additional_info->{familyDbId
} = qq|$obs_unit->{family_stock_id
}|;
313 $additional_info->{familyName
} = $obs_unit->{family_uniquename
};
317 externalReferences
=> @formatted_external_references,
318 additionalInfo
=> $additional_info,
319 germplasmDbId
=> $obs_unit->{germplasm_stock_id
} ?
qq|$obs_unit->{germplasm_stock_id
}| : undef,
320 germplasmName
=> $obs_unit->{germplasm_uniquename
} ?
qq|$obs_unit->{germplasm_uniquename
}| : undef,
321 crossDbId
=> $obs_unit->{cross_stock_id
} ?
qq|$obs_unit->{cross_stock_id
}| : undef,
322 crossName
=> $obs_unit->{cross_uniquename
} ?
qq|$obs_unit->{cross_uniquename
}| : undef,
323 locationDbId
=> qq|$obs_unit->{location_id
}|,
324 locationName
=> $obs_unit->{location_name
},
325 observationUnitDbId
=> qq|$obs_unit->{obsunit_stock_id
}|,
326 observations
=> $brapi_observations,
327 observationUnitName
=> $obs_unit->{obsunit_uniquename
},
328 observationUnitPosition
=> $brapi_observationUnitPosition,
329 observationUnitPUI
=> $main_production_site_url . "/stock/" . $obs_unit->{obsunit_stock_id
} . "/view",
330 programName
=> $obs_unit->{breeding_program_name
},
331 programDbId
=> qq|$obs_unit->{breeding_program_id
}|,
332 seedLotDbId
=> $obs_unit->{seedlot_id
} ?
qq|$obs_unit->{seedlot_id
}| : undef,
333 seedLotName
=> $obs_unit->{seedlot_name
} ?
qq|$obs_unit->{seedlot_name
}| : undef,
334 studyDbId
=> qq|$obs_unit->{trial_id
}|,
335 studyName
=> $obs_unit->{trial_name
},
336 plotImageDbIds
=> \
@ids,
337 treatments
=> \
@brapi_treatments,
338 trialDbId
=> $obs_unit->{folder_id
} ?
qq|$obs_unit->{folder_id
}| : qq|$obs_unit->{trial_id
}|,
339 trialName
=> $obs_unit->{folder_name
} ?
$obs_unit->{folder_name
} : $obs_unit->{trial_name
},
341 $total_count = $obs_unit->{full_count
};
344 print STDERR
"ObservationUnits call Checkpoint 4: ".DateTime
->now()."\n";
345 my $results = (data
=>\
@data_window);
347 return ($results,$total_count, $page_size,$page,$status);
350 sub _get_plants_plot_parent
{
352 my $plant_id_array = shift;
353 my $schema = $self->bcs_schema;
355 my $plant_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'plant_of', 'stock_relationship')->cvterm_id();
356 my $plot_number_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'plot number', 'stock_property')->cvterm_id();
357 my $plant_ids_string = join ',', @
{$plant_id_array};
358 my $select = "select stock.stock_id, stock_relationship.subject_id, stockprop.value from stock join stock_relationship on stock.stock_id = stock_relationship.object_id join stockprop on stock_relationship.subject_id = stockprop.stock_id where stockprop.type_id = $plot_number_cvterm_id and stock_relationship.type_id = $plant_cvterm_id and stock.stock_id in ($plant_ids_string);";
359 my $h = $schema->storage->dbh()->prepare($select);
363 while (my ($plant_id, $plot_id, $plot_number) = $h->fetchrow_array()) {
364 $plant_hash{$plant_id} = { id
=> $plot_id, plot_number
=> $plot_number };
372 my $observation_unit_db_id = shift;
375 my $search_params = {
376 observationUnitDbIds
=> [ $observation_unit_db_id ],
377 includeObservations
=> 'true'
381 my ($data,$total_count, $page_size,$page,$status) = _search
($self, $search_params, $c);
382 my $results = $data->[0];
383 my $pagination = CXGN
::BrAPI
::Pagination
->pagination_response($total_count,$page_size,$page);
384 return CXGN
::BrAPI
::JSONResponse
->return_success($results, $pagination, \
@data_files, $status, 'Observation Units search result constructed');
387 sub observationunits_update
{
392 my $page_size = $self->page_size;
393 my $page = $self->page;
394 my $status = $self->status;
396 my $dbh = $self->bcs_schema()->storage()->dbh();
397 my $schema = $self->bcs_schema;
398 my $plot_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'plot', 'stock_type')->cvterm_id();
399 my $plant_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($self->bcs_schema, 'plant', 'stock_type')->cvterm_id();
400 my $stock_geo_json_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'plot_geo_json', 'stock_property');
401 my $plot_number_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'plot number', 'stock_property');
402 my $plant_number_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'plant number', 'stock_property');
403 my $block_number_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'block', 'stock_property');
404 my $is_a_control_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'is a control', 'stock_property');
405 my $rep_number_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'replicate', 'stock_property');
406 my $range_number_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'range', 'stock_property');
407 my $row_number_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'row_number', 'stock_property');
408 my $col_number_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'col_number', 'stock_property');
409 my $additional_info_cvterm = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'stock_additional_info', 'stock_property');
411 foreach my $params (@
$data) {
412 my $observation_unit_db_id = $params->{observationUnitDbId
} ?
$params->{observationUnitDbId
} : undef;
413 my $data_level = $params->{observationUnitLevelName
}->[0] || 'all';
414 my $years_arrayref = $params->{seasonDbId
} ?
$params->{seasonDbId
} : undef;
415 my $location_ids_arrayref = $params->{locationDbId
} ?
$params->{locationDbId
} : undef;
416 my $study_ids_arrayref = $params->{studyDbId
} ?
$params->{studyDbId
} : undef;
417 my $accession_id = $params->{germplasmDbId
} ?
$params->{germplasmDbId
} : undef;
418 my $accession_name = $params->{germplasmName
} ?
$params->{germplasmName
}: undef;
419 my $trait_list_arrayref = $params->{observationVariableDbId
} ?
$params->{observationVariableDbId
} : undef;
420 my $program_ids_arrayref = $params->{programDbId
} ?
$params->{programDbId
} : undef;
421 my $folder_ids_arrayref = $params->{trialDbId
} ?
$params->{trialDbId
} : undef;
422 my $observationUnit_name = $params->{observationUnitName
} ?
$params->{observationUnitName
} : undef;
423 my $observationUnit_position_arrayref = $params->{observationUnitPosition
} ?
$params->{observationUnitPosition
} : undef;
424 my $observationUnit_x_ref = $params->{externalReferences
} ?
$params->{externalReferences
} : undef;
425 my $seedlot_id = $params->{seedLotDbId
} || ""; #not implemented yet
426 my $treatments = $params->{treatments
} || ""; #not implemented yet
428 my $row_number = $params->{observationUnitPosition
}->{positionCoordinateY
} ?
$params->{observationUnitPosition
}->{positionCoordinateY
} : undef;
429 my $col_number = $params->{observationUnitPosition
}->{positionCoordinateX
} ?
$params->{observationUnitPosition
}->{positionCoordinateX
} : undef;
430 my $plot_geo_json = $params->{observationUnitPosition
}->{geoCoordinates
} ?
$params->{observationUnitPosition
}->{geoCoordinates
} : undef;
431 my $level_relations = $params->{observationUnitPosition
}->{observationLevelRelationships
} ?
$params->{observationUnitPosition
}->{observationLevelRelationships
} : undef;
432 my $level_name = $params->{observationUnitPosition
}->{observationLevel
}->{levelName
} || undef;
433 my $level_number = $params->{observationUnitPosition
}->{observationLevel
}->{levelCode
} ?
$params->{observationUnitPosition
}->{observationLevel
}->{levelCode
} : undef;
434 my $raw_additional_info = $params->{additionalInfo
} || undef;
435 my $is_a_control = $raw_additional_info->{control
} ?
$raw_additional_info->{control
} : undef;
437 my $entry_type = $params->{observationUnitPosition
}->{entryType
} ?
$params->{observationUnitPosition
}->{entryType
} : undef;
438 my $is_a_control = $params->{additionalInfo
}->{control
} ?
$params->{additionalInfo
}->{control
} : undef;
440 # BrAPI entryType overrides additionalinfo.control
442 $is_a_control = uc($entry_type) eq 'CHECK' ?
1 : 0;
445 my $range_number = $raw_additional_info->{range
} ?
$raw_additional_info->{range
} : undef;
446 my %specific_keys = map { $_ => 1 } ("observationUnitParent","control","range");
451 foreach (@
$level_relations){
452 if($_->{levelName
} eq 'block'){
453 $block_number = $_->{levelCode
} ?
$_->{levelCode
} : undef;
455 if($_->{levelName
} eq 'rep'){
456 $rep_number = $_->{levelCode
} ?
$_->{levelCode
} : undef;
457 $_->{levelName
} = 'rep';
460 if (defined $raw_additional_info) {
461 foreach my $key (keys %$raw_additional_info) {
462 if (!exists($specific_keys{$key})) {
463 $additional_info{$key} = $raw_additional_info->{$key};
468 #Check if observation_unit_db_id is plot or plant and not other stock type
469 my $stock = $self->bcs_schema->resultset('Stock::Stock')->find({stock_id
=>$observation_unit_db_id});
470 my $stock_type = $stock->type_id;
472 if (( $stock_type ne $plot_cvterm_id && $stock_type ne $plant_cvterm_id ) || ($level_name ne 'plant' && $level_name ne 'plot')){
473 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf("Only 'plot' or 'plant' allowed for observation level and observationUnitDbId."), 400);
477 # if (! defined $accession_id && ! defined $accession_name) {
478 # return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Either germplasmDbId or germplasmName is required.'), 400);
480 # my $germplasm_search_result = $self->_get_existing_germplasm($schema, $accession_id, $accession_name);
481 # if ($germplasm_search_result->{error}) {
482 # return $germplasm_search_result->{error};
484 # $accession_name = $germplasm_search_result->{name};
488 if(defined $accession_id){
489 # Speed can be improved here by adding a simple query
490 my $layout_accession_search = CXGN
::Trial
::TrialLayoutSearch
->new(
494 observation_unit_id_list
=>[$observation_unit_db_id],
495 # experiment_type=>'field_layout',
496 include_observations
=>1,
499 my ($data_accession,$data_accession_observations) = $layout_accession_search->search();
501 my $old_accession_id;
503 foreach my $obs_unit (@
$data_accession){
504 $old_accession = $obs_unit->{germplasm_uniquename
};
505 $old_accession_id = $obs_unit->{germplasm_stock_id
};
508 if($accession_id ne $old_accession_id){
509 if (! defined $accession_id && ! defined $accession_name) {
510 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Either germplasmDbId or germplasmName is required.'), 400);
512 my $germplasm_search_result = $self->_get_existing_germplasm($schema, $accession_id, $accession_name);
513 if ($germplasm_search_result->{error
}) {
514 return $germplasm_search_result->{error
};
516 $accession_name = $germplasm_search_result->{name
};
520 my $plot_of_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'plot_of', 'stock_relationship')->cvterm_id();
521 if ($old_accession && $accession_id && $old_accession_id ne $accession_id) {
522 my $replace_plot_accession_fieldmap = CXGN
::Trial
::FieldMap
->new({
523 bcs_schema
=> $schema,
524 trial_id
=> $study_ids_arrayref,
525 # new_accession => $accession_name,
526 # old_accession => $old_accession,
527 # old_plot_id => $observation_unit_db_id,
528 # old_plot_name => $observationUnit_name,
529 experiment_type
=> 'field_layout'
532 my $return_error = $replace_plot_accession_fieldmap->update_fieldmap_precheck();
534 print STDERR Dumper
$return_error;
535 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Something went wrong. Accession cannot be replaced.'));
538 my $replace_return_error = $replace_plot_accession_fieldmap->replace_plot_accession_fieldMap($observation_unit_db_id, $old_accession_id, $plot_of_type_id);
539 if ($replace_return_error) {
540 print STDERR Dumper
$replace_return_error;
541 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Something went wrong. Accession cannot be replaced.'));
547 #Update: geo coordinates
548 my $geo_coordinates = $observationUnit_position_arrayref->{geoCoordinates
} || undef;
549 if($geo_coordinates) {
551 my $geno_json_string = encode_json
$geo_coordinates;
553 #sub upload coordinates
554 my $upload_plot_gps_txn = sub {
556 my $plots_rs = $schema->resultset("Stock::Stock")->search({stock_id
=> {-in=>$observation_unit_db_id}});
558 while (my $plot=$plots_rs->next){
559 my $previous_plot_gps_rs = $schema->resultset("Stock::Stockprop")->search({stock_id
=>$plot->stock_id, type_id
=>$stock_geo_json_cvterm->cvterm_id});
560 $previous_plot_gps_rs->delete_all();
561 $plot->create_stockprops({$stock_geo_json_cvterm->name() => $geno_json_string});
566 $schema->txn_do($upload_plot_gps_txn);
569 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('An error condition occurred, was not able to upload trial plot GPS coordinates. ($@)'));
575 if ($level_name eq 'plot'){ $schema->resultset("Stock::Stockprop")->update_or_create({ type_id
=>$plot_number_cvterm->cvterm_id, stock_id
=>$observation_unit_db_id, rank
=>0, value
=>$level_number }, { key
=>'stockprop_c1' }); }
576 if ($level_name eq 'plant'){ $schema->resultset("Stock::Stockprop")->update_or_create({ type_id
=>$plant_number_cvterm->cvterm_id, stock_id
=>$observation_unit_db_id, rank
=>0, value
=>$level_number }, { key
=>'stockprop_c1' }); }
578 if ($block_number){ $schema->resultset("Stock::Stockprop")->update_or_create({ type_id
=>$block_number_cvterm->cvterm_id, stock_id
=>$observation_unit_db_id, rank
=>0, value
=>$block_number },{ key
=>'stockprop_c1' }); }
579 if ($is_a_control){ $schema->resultset("Stock::Stockprop")->update_or_create({ type_id
=>$is_a_control_cvterm->cvterm_id, stock_id
=>$observation_unit_db_id, rank
=>0, value
=>$is_a_control },{ key
=>'stockprop_c1' }); }
580 if ($rep_number){ $schema->resultset("Stock::Stockprop")->update_or_create({ type_id
=>$rep_number_cvterm->cvterm_id, stock_id
=>$observation_unit_db_id, rank
=>0, value
=>$rep_number },{ key
=>'stockprop_c1' }); }
581 if ($range_number){ $schema->resultset("Stock::Stockprop")->update_or_create({ type_id
=>$range_number_cvterm->cvterm_id, stock_id
=>$observation_unit_db_id, rank
=>0, value
=>$range_number },{ key
=>'stockprop_c1' }); }
582 if ($row_number){ $schema->resultset("Stock::Stockprop")->update_or_create({ type_id
=>$row_number_cvterm->cvterm_id, stock_id
=>$observation_unit_db_id, rank
=>0, value
=>$row_number },{ key
=>'stockprop_c1' }); }
583 if ($col_number){ $schema->resultset("Stock::Stockprop")->update_or_create({ type_id
=>$col_number_cvterm->cvterm_id, stock_id
=>$observation_unit_db_id, rank
=>0, value
=>$col_number },{ key
=>'stockprop_c1' }); }
584 if (%additional_info){ $schema->resultset("Stock::Stockprop")->update_or_create({ type_id
=>$additional_info_cvterm->cvterm_id, stock_id
=>$observation_unit_db_id, rank
=>0, value
=>encode_json \
%additional_info },{ key
=>'stockprop_c1' }); }
586 #store/update external references
587 if ($observationUnit_x_ref){
588 my $references = CXGN
::BrAPI
::v2
::ExternalReferences
->new({
589 bcs_schema
=> $self->bcs_schema,
590 table_name
=> 'stock',
591 table_id_key
=> 'stock_id',
592 external_references
=> $observationUnit_x_ref,
593 id
=> $observation_unit_db_id
595 my $reference_result = $references->store();
599 my @observation_unit_db_ids;
600 foreach my $params (@
$data) { push @observation_unit_db_ids, $params->{observationUnitDbId
}; }
602 my $search_params = {observationUnitDbIds
=> \
@observation_unit_db_ids };
603 return $self->search($search_params, $c);
606 sub _get_existing_germplasm
{
609 my $accession_id = shift;
610 my $accession_name = shift;
612 if (!looks_like_number
($accession_id)) {
613 return {error
=> CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Verify Germplasm Id.'), 404)};
616 # Get the germplasm name from germplasmDbId. Check if a germplasm name passed exists
617 my $rs = $schema->resultset("Stock::Stock")->search({stock_id
=>$accession_id});
618 if ($rs->count() eq 0 && ! defined $accession_name){
619 return {error
=> CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Germplasm with that id does not exist.'), 404)};
620 } elsif ($rs->count() > 0) {
621 my $stock = $rs->first;
622 $accession_name = $stock->uniquename();
624 # Check that a germplasm exists with that name
625 my $rs = $schema->resultset("Stock::Stock")->search({uniquename
=>$accession_name});
626 if ($rs->count() eq 0) {
627 return {error
=> CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Germplasm with that name does not exist.'), 404)};
631 return {name
=> $accession_name};
634 sub observationunits_store
{
640 my $schema = $self->bcs_schema;
641 my $dbh = $self->bcs_schema()->storage()->dbh();
642 my $person = CXGN
::People
::Person
->new($dbh, $user_id);
643 my $user_name = $person->get_username;
646 my %seen_plot_numbers;
647 foreach my $params (@
{$data}) {
648 my $study_id = $params->{studyDbId
} || undef;
649 my $plot_name = $params->{observationUnitName
} ?
$params->{observationUnitName
} : undef;
650 my $plot_number = $params->{observationUnitPosition
}->{observationLevel
}->{levelCode
} ?
$params->{observationUnitPosition
}->{observationLevel
}->{levelCode
} : undef;
651 my $plot_parent_id = $params->{additionalInfo
}->{observationUnitParent
} ?
$params->{additionalInfo
}->{observationUnitParent
} : undef;
652 my $accession_id = $params->{germplasmDbId
} ?
$params->{germplasmDbId
} : undef;
653 my $accession_name = $params->{germplasmName
} ?
$params->{germplasmName
} : undef;
654 my $entry_type = $params->{observationUnitPosition
}->{entryType
} ?
$params->{observationUnitPosition
}->{entryType
} : undef;
655 my $is_a_control = $params->{additionalInfo
}->{control
} ?
$params->{additionalInfo
}->{control
} : undef;
657 # BrAPI entryType overrides additionalinfo.control
659 $is_a_control = uc($entry_type) eq 'CHECK' ?
1 : 0;
662 my $range_number = $params->{additionalInfo
}->{range
} ?
$params->{additionalInfo
}->{range
} : undef;
663 my $row_number = $params->{observationUnitPosition
}->{positionCoordinateY
} ?
$params->{observationUnitPosition
}->{positionCoordinateY
} : undef;
664 my $col_number = $params->{observationUnitPosition
}->{positionCoordinateX
} ?
$params->{observationUnitPosition
}->{positionCoordinateX
} : undef;
665 my $seedlot_id = $params->{seedLotDbId
} ?
$params->{seedLotDbId
} : undef;
666 my $plot_geo_json = $params->{observationUnitPosition
}->{geoCoordinates
} ?
$params->{observationUnitPosition
}->{geoCoordinates
} : undef;
667 my $levels = $params->{observationUnitPosition
}->{observationLevelRelationships
} ?
$params->{observationUnitPosition
}->{observationLevelRelationships
} : undef;
668 my $ou_level = $params->{observationUnitPosition
}->{observationLevel
}->{levelName
} || undef;
669 my $observationUnit_x_ref = $params->{externalReferences
} ?
$params->{externalReferences
} : undef;
670 my $raw_additional_info = $params->{additionalInfo
} || undef;
671 my %specific_keys = map { $_ => 1 } ("observationUnitParent","control");
673 if (defined $raw_additional_info) {
674 foreach my $key (keys %$raw_additional_info) {
675 if (!exists($specific_keys{$key})) {
676 $additional_info{$key} = $raw_additional_info->{$key};
683 # Required fields check
684 if (! defined $accession_id && ! defined $accession_name) {
685 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Either germplasmDbId or germplasmName is required.'), 400);
688 if ($ou_level ne 'plant' && $ou_level ne 'plot') {
689 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Only "plot" or "plant" allowed for observation level.'), 400);
692 my $project = $self->bcs_schema->resultset("Project::Project")->find({ project_id
=> $study_id });
693 if (! defined $project) {
694 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf("A study with id $study_id does not exist"), 404);
697 # Get the germplasm name from germplasmDbId. Check if a germplasm name passed exists
698 my $germplasm_search_result = $self->_get_existing_germplasm($schema, $accession_id, $accession_name);
699 if ($germplasm_search_result->{error
}) {
700 return $germplasm_search_result->{error
};
702 $accession_name = $germplasm_search_result->{name
};
706 if($_->{levelName
} eq 'block'){
707 $block_number = $_->{levelCode
} ?
$_->{levelCode
} : undef;
709 if($_->{levelName
} eq 'rep'){
710 $rep_number = $_->{levelCode
} ?
$_->{levelCode
} : undef;
711 $_->{levelName
} = 'rep';
715 # The trial designer expects a list of plant names, this object is a plant, so add to single item list
717 if ($ou_level eq 'plant') {
718 # Check that the parent already exists
719 my $plot_parent_name;
720 if ($plot_parent_id) {
721 my $rs = $schema->resultset("Stock::Stock")->search({stock_id
=>$plot_parent_id});
722 if ($rs->count() eq 0){
723 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('Plot with id %s does not exist.', $plot_parent_id), 404);
725 $plot_parent_name = $rs->first()->uniquename();
727 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, sprintf('addtionalInfo.observationUnitParent for observation unit with level "plant" is required'), 404);
731 plot_name
=> $plot_parent_name,
732 plant_names
=> [ $plot_name ],
733 # accession_name => $accession_name,
734 stock_name
=> $accession_name,
735 plot_number
=> $plot_number,
736 block_number
=> $block_number,
737 is_a_control
=> $is_a_control,
738 rep_number
=> $rep_number,
739 range_number
=> $range_number,
740 row_number
=> $row_number,
741 col_number
=> $col_number,
742 # plot_geo_json => $plot_geo_json,
743 additional_info
=> \
%additional_info,
744 external_refs
=> $observationUnit_x_ref
748 plot_name
=> $plot_name,
749 # accession_name => $accession_name,
750 stock_name
=> $accession_name,
751 plot_number
=> $plot_number,
752 block_number
=> $block_number,
753 is_a_control
=> $is_a_control,
754 rep_number
=> $rep_number,
755 range_number
=> $range_number,
756 row_number
=> $row_number,
757 col_number
=> $col_number,
758 # plot_geo_json => $plot_geo_json,
759 additional_info
=> \
%additional_info,
760 external_refs
=> $observationUnit_x_ref
764 $study_plots{$study_id}{$plot_number} = $plot_hash;
765 $seen_plot_numbers{$study_id}{$plot_number}++;
768 # Check that the plot numbers passed are unique per study
769 foreach my $study_design (values %seen_plot_numbers) {
770 foreach my $seen_plot_number (keys %{$study_design}) {
771 if ($study_design->{$seen_plot_number} > 1) {
772 return CXGN
::BrAPI
::JSONResponse
->return_error($self->status, "Plot number '$seen_plot_number' is duplicated in the data sent. Plot Number must be unique", 422);
778 foreach my $study_id (keys %study_plots) {
780 # Get the study design type
781 my $study = $study_plots{$study_id};
782 my $project = $self->bcs_schema->resultset("Project::Project")->find({ project_id
=> $study_id });
783 my $design_prop = $project->projectprops->find({ 'type.name' => 'design' }, { join => 'type' }); #there should be only one design prop.
785 die {error
=> 'Study does not have a study type.', errorCode
=> 500};
787 my $design_type = $design_prop->value;
789 # Get the study location
791 my $location_type_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'project location', 'project_property');
792 my $row = $self->bcs_schema()->resultset('Project::Projectprop')->find({
793 project_id
=> $project->project_id(),
794 type_id
=> $location_type_id->cvterm_id(),
797 print('Row value: ' . $row->value());
798 $location_id = $row->value();
801 die {error
=> sprintf('Erro retrieving the location of the study'), errorCode
=> 500};
804 my $trial_design_store = CXGN
::Trial
::TrialDesignStore
->new({
805 bcs_schema
=> $schema,
806 trial_id
=> $study_id,
807 nd_geolocation_id
=> $location_id,
808 # nd_experiment_id => $nd_experiment->nd_experiment_id(), #optional
810 new_treatment_has_plant_entries
=> 0,
811 new_treatment_has_subplot_entries
=> 0,
812 operator
=> $user_name,
813 trial_stock_type
=> 'accessions',
814 design_type
=> $design_type,
816 operator
=> $user_name
820 my $validate_design_error = $trial_design_store->validate_design();
821 if ($validate_design_error) {
822 die {error
=> sprintf('Error validating study design: ' . $validate_design_error), errorCode
=> 422};
825 $error = $trial_design_store->store();
827 die {error
=> sprintf('ERROR store: ' . $error), errorCode
=> 500};
829 # Refresh the trial layout property
830 my %param = ( schema
=> $schema, trial_id
=> $study_id );
831 if ($design_type eq 'genotyping_plate'){
832 $param{experiment_type
} = 'genotyping_layout';
834 $param{experiment_type
} = 'field_layout';
836 my $trial_layout = CXGN
::Trial
::TrialLayout
->new(\
%param);
837 my $design = $trial_layout->generate_and_cache_layout();
839 foreach my $plot_num (keys %{$design}) {
840 my $observationUnit_x_ref = $study->{$plot_num}->{external_refs
};
841 if ($observationUnit_x_ref){
842 my $references = CXGN
::BrAPI
::v2
::ExternalReferences
->new({
843 bcs_schema
=> $self->bcs_schema,
844 table_name
=> 'stock',
845 table_id_key
=> 'stock_id',
846 external_references
=> $observationUnit_x_ref,
847 id
=> $design->{$plot_num}->{plot_id
}
849 my $reference_result = $references->store();
858 $schema->txn_do($coderef);
861 print "Error: :". Dumper
($_);
862 # print Dumper("Error: $_\n");
863 $error_resp = CXGN
::BrAPI
::JSONResponse
->return_error($self->status, $_->{error
}, $_->{errorCode
} || 500);
865 if ($error_resp) { return $error_resp; }
867 # Get our new OUs by name. Not ideal, but names are unique and its the quickest solution
868 my @observationUnitNames;
869 foreach my $ou (@
{$data}) { push @observationUnitNames, $ou->{observationUnitName
}; }
870 my $search_params = {observationUnitNames
=> \
@observationUnitNames};
871 $self->page_size(scalar @
{$data});
872 return $self->search($search_params, $c);
886 return $levels{$value} + 0;