Merge pull request #5280 from solgenomics/5714_phenotype_genotype_data_check
[sgn.git] / lib / CXGN / BrAPI / v2 / Studies.pm
blobc86c146d3b4c36ed7599657d2edfa1ff7249139e
1 package CXGN::BrAPI::v2::Studies;
3 use Moose;
4 use Data::Dumper;
5 use SGN::Model::Cvterm;
6 use CXGN::Trial;
7 use CXGN::Trial::Search;
8 use CXGN::Trial::TrialLayout;
9 use CXGN::Trait;
10 use CXGN::Stock;
11 use CXGN::Phenotypes::SearchFactory;
12 use CXGN::Phenotypes::PhenotypeMatrix;
13 use CXGN::BrAPI::Pagination;
14 use CXGN::BrAPI::FileResponse;
15 use CXGN::BrAPI::JSONResponse;
16 use CXGN::TimeUtils;
17 use JSON;
19 extends 'CXGN::BrAPI::v2::Common';
21 sub seasons {
22 my $self = shift;
23 my $year_filter = shift;
24 my $page_size = $self->page_size;
25 my $page = $self->page;
26 my $status = $self->status;
28 my @data;
29 my $total_count = 0;
30 my $year_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($self->bcs_schema,'project year', 'project_property')->cvterm_id();
31 my $project_years_rs = $self->bcs_schema()->resultset("Project::Project")->search_related('projectprops', {'projectprops.type_id'=>$year_cvterm_id});
32 my %unique_years;
33 while (my $p_year = $project_years_rs->next()) {
34 $unique_years{$p_year->value} = $p_year->projectprop_id;
36 my @sorted_years;
37 foreach (sort keys %unique_years){
38 my ($year, $season) = split '\|', $_;
39 if ($year_filter){
40 if ($year eq $year_filter){
41 push @sorted_years, [$year, $season, $_];
43 } else {
44 push @sorted_years, [$year, $season, $_];
48 my ($data_window, $pagination) = CXGN::BrAPI::Pagination->paginate_array(\@sorted_years, $page_size, $page);
49 foreach (@$data_window){
50 my $year = $_->[0] ? $_->[0] : '';
51 my $season = $_->[1] ? $_->[1] : '';
52 my $projectprop_id = $_->[2] ? $_->[2] : '';
53 push @data, {
54 seasonDbId=>qq|$projectprop_id|,
55 season=>$season,
56 year=>$year
59 my %result = (data=>\@data);
60 my @data_files;
61 return CXGN::BrAPI::JSONResponse->return_success(\%result, $pagination, \@data_files, $status, 'Seasons list result constructed');
64 sub study_types {
65 my $self = shift;
66 my $page_size = $self->page_size;
67 my $page = $self->page;
68 my $status = $self->status;
69 my @data;
70 my @data_files;
71 my @project_type_ids = CXGN::Trial::get_all_project_types($self->bcs_schema());
72 my ($data_window, $pagination) = CXGN::BrAPI::Pagination->paginate_array(\@project_type_ids, $page_size, $page);
73 foreach (@$data_window){
74 push @data, $_->[1];
76 my %result = (data=>\@data);
77 return CXGN::BrAPI::JSONResponse->return_success(\%result, $pagination, \@data_files, $status, 'StudyTypes list result constructed');
80 sub search {
81 my $self = shift;
82 my $search_params = shift;
83 my $c = shift;
84 my $page_size = $self->page_size;
85 my $page = $self->page;
86 my $status = $self->status;
87 my $schema = $self->bcs_schema;
88 my $supported_crop = $c->config->{"supportedCrop"};
90 my @program_dbids = $search_params->{programDbIds} ? @{$search_params->{programDbIds}} : ();
91 my @program_names = $search_params->{programNames} ? @{$search_params->{programNames}} : ();
92 my @study_dbids = $search_params->{studyDbIds} ? @{$search_params->{studyDbIds}} : ();
93 my @study_names = $search_params->{studyNames} ? @{$search_params->{studyNames}} : ();
94 my @folder_dbids = $search_params->{trialDbIds} ? @{$search_params->{trialDbIds}} : ();
95 my @folder_names = $search_params->{trialNames} ? @{$search_params->{trialNames}} : ();
96 my @location_ids = $search_params->{locationDbIds} ? @{$search_params->{locationDbIds}} : ();
97 my @location_names = $search_params->{studyLocationNames} ? @{$search_params->{studyLocationNames}} : ();
98 my @study_type_list = $search_params->{studyTypes} ? @{$search_params->{studyTypes}} : ();
99 my @germplasm_dbids = $search_params->{germplasmDbIds} ? @{$search_params->{germplasmDbIds}} : ();
100 my @germplasm_names = $search_params->{germplasmNames} ? @{$search_params->{germplasmNames}} : ();
101 my @year_list = $search_params->{seasonDbIds} ? @{$search_params->{seasonDbIds}} : ();
102 my @obs_variable_ids = $search_params->{observationVariableDbIds} ? @{$search_params->{observationVariableDbIds}} : ();
103 my @study_puis = $search_params->{studyPUI} ? @{$search_params->{studyPUIs}} : ();
104 my @externalReferenceIds = $search_params->{externalReferenceIds} ? @{$search_params->{externalReferenceIds}} : ();
106 # externalReferenceIDs is DEPRECATED,but still supported in BrAPI (if possible, use externalReferenceIds instead).
107 if(!scalar(@externalReferenceIds)){
108 @externalReferenceIds = $search_params->{externalReferenceIDs} ? @{$search_params->{externalReferenceIDs}} : ();
111 my @externalReferenceSource = $search_params->{externalReferenceSources} ? @{$search_params->{externalReferenceSources}} : ();
112 my @crop = $search_params->{commonCropNames} ? @{$search_params->{commonCropNames}} : ();
113 my $active = $search_params->{active} || undef;
114 my $sortBy = $search_params->{sortBy} || undef;
115 my $sortOrder = $search_params->{sortOrder} || undef;
117 if (scalar(@crop)>0 && !grep { lc($_) eq lc($supported_crop) } @crop ){
118 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('commonCropName not found!'));
121 if ($active && lc($active) ne 'true'){
122 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Not found!'));
124 if (scalar(@study_puis)>0 ){
125 push @$status, { 'error' => 'The studyPUI search parameters are not implemented.' };
128 my ($data_out,$total_count) = _search($self,$schema,$page_size,$page,$supported_crop,\@study_dbids,\@location_names,\@location_ids,\@study_type_list,\@study_names,\@program_names,\@program_dbids,\@folder_dbids,\@folder_names,\@obs_variable_ids,\@germplasm_dbids,\@germplasm_names,\@year_list,\@externalReferenceIds,\@externalReferenceSource,$sortBy,$sortOrder);
130 my %result = (data=>$data_out);
131 my @data_files;
132 my $pagination = CXGN::BrAPI::Pagination->pagination_response($total_count,$page_size,$page);
133 return CXGN::BrAPI::JSONResponse->return_success(\%result, $pagination, \@data_files, $status, 'Studies search result constructed');
136 sub detail {
137 my $self = shift;
138 my $study_id = shift;
139 my $main_production_site_url = shift;
140 my $supported_crop = shift;
141 my $page_size = $self->page_size;
142 my $page = $self->page;
143 my $status = $self->status;
145 my ($data_out,$total_count) = _search($self,$self->bcs_schema(),$page_size,$page,$supported_crop,[$study_id]);
147 if ($data_out > 0){
148 my $result = @$data_out[0];
149 my @data_files;
150 my $pagination = CXGN::BrAPI::Pagination->pagination_response($total_count,$page_size,$page);
151 return CXGN::BrAPI::JSONResponse->return_success($result, $pagination, \@data_files, $status, 'Studies search result constructed');
152 } else {
153 return CXGN::BrAPI::JSONResponse->return_error($status, 'StudyDbId not found', 404);
157 sub store {
158 my $self = shift;
159 my $data = shift;
160 my $user_id =shift;
161 my $c = shift;
163 if (!$user_id){
164 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('You must be logged in to add a seedlot!'));
167 my $dbh = $self->bcs_schema()->storage()->dbh();
168 my $schema = $self->bcs_schema;
169 my $person = CXGN::People::Person->new($dbh, $user_id);
170 my $user_name = $person->get_username;
172 my $page_size = $self->page_size;
173 my $page = $self->page;
174 my $status = $self->status;
176 my @study_dbids;
178 foreach my $params (@{$data}) {
179 my $trial_name = $params->{studyName} ? $params->{studyName} : undef;
180 my $trial_description = $params->{studyDescription} ? $params->{studyDescription} : undef;
181 my $trial_year = $params->{seasons} ? $params->{seasons}->[0] : undef;
182 my $trial_location_id = $params->{locationDbId} ? $params->{locationDbId} : undef;
183 my $trial_design_method = $params->{experimentalDesign} ? $params->{experimentalDesign}->{PUI} : undef; #Design type must be either: genotyping_plate, CRD, Alpha, Augmented, Lattice, RCBD, MAD, p-rep, greenhouse, splitplot, or stripplot;
184 my $folder_id = $params->{trialDbId} ? $params->{trialDbId} : undef;
185 my $study_type = $params->{studyType} ? $params->{studyType} : undef;
186 my $field_size = $params->{additionalInfo}->{field_size} ? $params->{additionalInfo}->{field_size} : undef;
187 my $plot_width = $params->{additionalInfo}->{plot_width} ? $params->{additionalInfo}->{plot_width} : undef;
188 my $plot_length = $params->{additionalInfo}->{plot_length} ? $params->{additionalInfo}->{plot_length} : undef;
189 my $raw_additional_info = $params->{additionalInfo} || undef;
190 my $external_references = $params->{externalReferences} || [];
191 my %specific_keys = map { $_ => 1 } ("field_size", "plot_width", "plot_length");
192 my %additional_info;
193 if (defined $raw_additional_info) {
194 foreach my $key (keys %$raw_additional_info) {
195 if (!exists($specific_keys{$key})) {
196 $additional_info{$key} = $raw_additional_info->{$key};
201 # Check that a supported study design type was passed
202 my %supported_methods = map { $_ => 1 } ("CRD","Alpha","MAD","Lattice","Augmented","RCBD","p-rep","splitplot","stripplot","greenhouse","Westcott","Analysis");
203 if (!exists($supported_methods{$trial_design_method})) {
204 return CXGN::BrAPI::JSONResponse->return_error($self->status, "Experimental Design, $trial_design_method, must be one of the following: 'CRD','Alpha','MAD','Lattice','Augmented','RCBD','p-rep','splitplot','stripplot', 'greenhouse','Westcott','Analysis'.", 400);
207 # Check the trial exists
208 my $brapi_trial = $self->bcs_schema()->resultset('Project::Project')->find( { project_id=>$folder_id });
209 if (! defined $brapi_trial) {
210 return CXGN::BrAPI::JSONResponse->return_error($self->status, 'Trial does not exist with that id', 404);
213 my $folder = CXGN::Trial::Folder->new(bcs_schema=>$self->bcs_schema(), folder_id=>$folder_id);
214 my $program;
215 if($folder->breeding_program){
216 $program = $folder->breeding_program->name();
217 } elsif ($folder->name()){
218 $program = $folder->name();
221 # Check that the location exists if it was passed in
222 my $trial_location;
223 if ($trial_location_id) {
224 my $location = $schema->resultset('NaturalDiversity::NdGeolocation')->find({nd_geolocation_id => $trial_location_id});
225 if (!$location) {
226 my $err_string = sprintf('Location with id %s does not exist.',$trial_location_id);
227 warn $err_string;
228 return CXGN::BrAPI::JSONResponse->return_error($self->status, $err_string, 404);
230 $trial_location = $location->description();
233 # Check that a study with this name does not already exist
234 my $metadata_schema = $self->metadata_schema;
235 my $phenome_schema = $self->phenome_schema;
236 my $trial_name_exists = CXGN::Trial::Search->new({
237 bcs_schema => $schema,
238 metadata_schema => $metadata_schema,
239 phenome_schema => $phenome_schema,
240 trial_name_list => [$trial_name]
242 my ($data, $total_count) = $trial_name_exists->search();
243 if ($total_count > 0) {
244 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Study with the name \'%s\' already exists', $trial_name), 409);
247 my $save;
248 my $coderef = sub {
250 # Use the misc_trial type if it doesn't match any of the other ones.
251 my @project_type_ids = CXGN::Trial::get_all_project_types($self->bcs_schema());
252 my %project_type_ids;
253 foreach (@project_type_ids) {
254 $project_type_ids{$_->[1]} = $_->[0];
257 my $trial_type;
258 if ($project_type_ids{$study_type}) {
259 $trial_type = $project_type_ids{$study_type};
260 } else {
261 # Create a new trial type
262 my $misc_type_cvterm = SGN::Model::Cvterm->get_cvterm_row($self->bcs_schema(), 'misc_trial', 'project_type');
263 $trial_type = $misc_type_cvterm->cvterm_id();
266 my %trial_info_hash = (
267 chado_schema => $schema,
268 dbh => $dbh,
269 trial_year => $trial_year,
270 trial_description => $trial_description || '',
271 trial_location => $trial_location,
272 trial_type => $trial_type,
273 trial_type_value => $study_type,
274 trial_name => $trial_name,
275 user_name => $user_name, #not implemented
276 design_type => $trial_design_method,
277 design => {},
278 program => $program,
279 # upload_trial_file => $upload,
280 operator => $user_name,
281 trial_stock_type => 'accession', #can be cross or family name, not implemented
282 additional_info => \%additional_info
285 print STDERR "Trial type is ".$trial_info_hash{'trial_type'}."\n";
287 if ($field_size){
288 $trial_info_hash{field_size} = $field_size;
290 if ($plot_width){
291 $trial_info_hash{plot_width} = $plot_width;
293 if ($plot_length){
294 $trial_info_hash{plot_length} = $plot_length;
297 my $trial_create = CXGN::Trial::TrialCreate->new(\%trial_info_hash);
298 $save = _save_trial($trial_create);
299 my $error = $save->{error};
300 if ($error){
301 $schema->txn_rollback();
302 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('There was an error storing studies. %s', $error, 500));
304 return $save->{project_id};
306 my $trial_id;
307 #save data
308 eval {
309 $trial_id = $schema->txn_do($coderef);
310 if (ref \$trial_id eq 'SCALAR'){
311 push @study_dbids, $trial_id;
313 # Associate the study with the trial
314 my $folder = CXGN::Trial::Folder->new(
316 bcs_schema => $schema,
317 folder_id => $trial_id
320 $folder->associate_parent($folder_id);
323 if ($@) {
324 warn $@;
325 return CXGN::BrAPI::JSONResponse->return_error($self->status, 'There was an error saving the study', 500);
327 # save external references if specified
328 if ($external_references) {
329 my $references = CXGN::BrAPI::v2::ExternalReferences->new({
330 bcs_schema => $schema,
331 external_references => $external_references,
332 table_name => 'project',
333 table_id_key => 'project_id',
334 id => $trial_id,
337 $references->store();
339 if ($references->{'error'}) {
340 return { error => $references->{'error'} };
345 my $data_out;
346 my $total_count=0;
347 # This is servicing a POST request, make sure pagination returns all created objects.
348 $page_size = scalar(@study_dbids);
349 $page = 0;
350 if (scalar(@study_dbids)>0){
351 # my $dbh = $c->dbc->dbh();
352 # my $bs = CXGN::BreederSearch->new( { dbh=>$dbh, dbname=>$c->config->{dbname}, } );
353 # my $refresh = $bs->refresh_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass}, 'stockprop', 'concurrent', $c->config->{basepath});
355 my $supported_crop = $c->config->{"supportedCrop"};
357 ($data_out,$total_count) = _search($self,$schema,$page_size,$page,$supported_crop,\@study_dbids);
360 my %result = (data=>$data_out);
362 my @data_files;
363 my $pagination = CXGN::BrAPI::Pagination->pagination_response($total_count,$page_size,$page);
364 return CXGN::BrAPI::JSONResponse->return_success(\%result, $pagination, \@data_files, $status, 'Studies stored successfully');
367 sub update {
368 #TODO: This needs to update to the object sent. Currently it only changes fields that are sent
369 my $self = shift;
370 my $params = shift;
371 my $user_id =shift;
372 my $c = shift;
374 if (!$user_id){
375 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('You must be logged in to update studies!'));
378 my $trial_id = $params->{studyDbId};
379 my $schema = $self->bcs_schema;
380 my $metadata_schema = $self->metadata_schema;
381 my $phenome_schema = $self->phenome_schema;
383 my $page_size = $self->page_size;
384 my $page = $self->page;
385 my $status = $self->status;
387 my $dbh = $self->bcs_schema()->storage()->dbh();
388 my $person = CXGN::People::Person->new($dbh, $user_id);
389 my @user_roles = $person->get_roles;
391 # get program roles
392 my $program_object = CXGN::BreedersToolbox::Projects->new( { schema => $schema });
393 my $program_ref = $program_object->get_breeding_programs_by_trial($trial_id);
395 my $program_array = @$program_ref[0];
396 my $breeding_program_name = @$program_array[1];
398 my %has_roles = ();
399 map { $has_roles{$_} = 1; } @user_roles;
401 print STDERR "my user roles = @user_roles and trial breeding program = $breeding_program_name \n";
403 # set each new detail that is defined
404 my $study_name = $params->{studyName} ? $params->{studyName} : undef;
405 my $study_description = $params->{studyDescription} ? $params->{studyDescription} : undef;
406 my $study_year = $params->{seasons} ? $params->{seasons}->[0] : undef;
407 my $study_location = $params->{locationDbId} ? $params->{locationDbId} : undef;
408 my $study_design_method = $params->{experimentalDesign} ? $params->{experimentalDesign}->{PUI} : undef; #Design type must be either: genotyping_plate, CRD, Alpha, Augmented, Lattice, RCBD, MAD, p-rep, greenhouse, splitplot, or stripplot;
409 my $folder_id = $params->{trialDbId} ? $params->{trialDbId} : undef;
410 my $study_t = $params->{studyType} ? $params->{studyType} : undef;
411 my $field_size = $params->{additionalInfo}->{field_size} ? $params->{additionalInfo}->{field_size} : undef;
412 my $plot_width = $params->{additionalInfo}->{plot_width} ? $params->{additionalInfo}->{plot_width} : undef;
413 my $plot_length = $params->{additionalInfo}->{plot_length} ? $params->{additionalInfo}->{plot_length} : undef;
414 my $raw_additional_info = $params->{additionalInfo} || undef;
415 my %specific_keys = map { $_ => 1 } ("field_size", "plot_width", "plot_length");
416 my %additional_info;
417 if (defined $raw_additional_info) {
418 foreach my $key (keys %$raw_additional_info) {
419 if (!exists($specific_keys{$key})) {
420 $additional_info{$key} = $raw_additional_info->{$key};
424 my $planting_date = $params->{startDate} ? $params->{startDate} : undef;
425 my $harvest_date = $params->{endDate} ? $params->{endDate} : undef;
427 # Check that a supported study design type was passed
428 my %supported_methods = map { $_ => 1 } ("CRD","Alpha","MAD","Lattice","Augmented","RCBD","p-rep","splitplot","stripplot","greenhouse","Westcott","Analysis");
429 if (!exists($supported_methods{$study_design_method})) {
430 return CXGN::BrAPI::JSONResponse->return_error($self->status, "Experimental Design, $study_design_method, must be one of the following: 'CRD','Alpha','MAD','Lattice','Augmented','RCBD','p-rep','splitplot','stripplot','greenhouse','Westcott','Analysis'.", 400);
433 # Check the brapi trial exists
434 my $brapi_trial = $self->bcs_schema()->resultset('Project::Project')->find( { project_id=>$folder_id });
435 if (! defined $brapi_trial) {
436 return CXGN::BrAPI::JSONResponse->return_error($self->status, 'Trial does not exist with that id', 404);
439 # Get the trial (brapi trial) parent
440 my $folder = CXGN::Trial::Folder->new(bcs_schema=>$self->bcs_schema(), folder_id=>$folder_id);
441 # Get the breeding program for that brapi trial
442 my $program = $folder->breeding_program->project_id();
444 # Check that the location exists if it was passed in
445 if ($study_location) {
446 my $location = $schema->resultset('NaturalDiversity::NdGeolocation')->find({nd_geolocation_id => $study_location});
447 if (!$location) {
448 my $err_string = sprintf('Location with id %s does not exist.',$study_location);
449 warn $err_string;
450 return CXGN::BrAPI::JSONResponse->return_error($self->status, $err_string, 404);
454 # eval {
456 # Use the misc_trial type if it doesn't match any of the other ones.
457 my @project_type_ids = CXGN::Trial::get_all_project_types($self->bcs_schema());
458 my %project_type_ids;
459 foreach (@project_type_ids) {
460 $project_type_ids{$_->[1]} = $_->[0];
463 my $trial_type;
464 if ($project_type_ids{$study_t}) {
465 $trial_type = $project_type_ids{$study_t};
466 } else {
467 # Create a new trial type
468 my $misc_type_cvterm = SGN::Model::Cvterm->get_cvterm_row($self->bcs_schema(), 'misc_trial', 'project_type');
469 $trial_type = $misc_type_cvterm->cvterm_id();
472 my $trial_name_exists = CXGN::Trial::Search->new({
473 bcs_schema => $schema,
474 metadata_schema => $metadata_schema,
475 phenome_schema => $phenome_schema,
476 trial_name_list => [$study_name]
478 my ($data, $total_count) = $trial_name_exists->search();
480 # Check that the object found was not the object we are trying to update
481 my $non_object_match = 0;
482 foreach (@$data){
483 if ($_->{trial_id} ne $trial_id) {
484 $non_object_match = 1;
487 if($total_count>0 && $non_object_match eq 1){
488 return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf("Can't create trial: Trial name already exists\n"), 409);
490 my $trial = CXGN::Trial->new({
491 bcs_schema => $schema,
492 metadata_schema => $metadata_schema,
493 phenome_schema => $phenome_schema,
494 trial_id => $trial_id
496 if ($study_name) { $trial->set_name($study_name); }
497 if ($folder_id) {
498 $trial->set_breeding_program($program);
499 my $update_folder = CXGN::Trial::Folder->new({
500 bcs_schema => $schema,
501 folder_id => $trial_id
503 $update_folder->associate_parent($folder_id);
505 if ($study_location) { $trial->set_location($study_location); }
506 if ($study_year) { $trial->set_year($study_year); }
507 if ($trial_type) { $trial->set_project_type($trial_type, $study_t); }
508 if ($planting_date) {
509 if ($planting_date eq '') { $trial->remove_planting_date($trial->get_planting_date()); }
510 else { $trial->set_planting_date($planting_date); }
512 if ($harvest_date) {
513 if ($harvest_date eq '') { $trial->remove_harvest_date($trial->get_harvest_date()); }
514 else { $trial->set_harvest_date($harvest_date); }
516 if ($study_description) { $trial->set_description($study_description); }
517 if ($field_size) { $trial->set_field_size($field_size); }
518 if ($plot_width) { $trial->set_plot_width($plot_width); }
519 if ($plot_length) { $trial->set_plot_length($plot_length); }
520 if ($study_design_method) { $trial->set_design_type($study_design_method); }
521 if (%additional_info) { $trial->set_additional_info(\%additional_info); }
522 # };
524 my $supported_crop = $c->config->{"supportedCrop"};
526 my ($data_out,$total_count) = _search($self,$self->bcs_schema(),$page_size,$page,$supported_crop,[$trial_id]);
528 my $result = @$data_out[0];
529 my @data_files;
530 my $pagination = CXGN::BrAPI::Pagination->pagination_response($total_count,$page_size,$page);
532 return CXGN::BrAPI::JSONResponse->return_success($result, $pagination, \@data_files, $status, 'Studies result constructed');
536 sub _search {
537 my $self = shift;
538 my $schema = shift;
539 my $page_size = shift;
540 my $page = shift;
541 my $supported_crop = shift;
542 my $study_dbids = shift;
543 my $location_names = shift;
544 my $location_ids = shift;
545 my $study_type_list = shift;
546 my $study_names = shift;
547 my $program_names = shift;
548 my $program_dbids = shift;
549 my $folder_dbids = shift;
550 my $folder_names = shift;
551 my $obs_variable_ids = shift;
552 my $germplasm_dbids = shift;
553 my $germplasm_names = shift;
554 my $year_list = shift;
555 my $externalReferenceIds = shift;
556 my $externalReferenceSources = shift;
557 my $sort_by = shift;
558 my $sort_order = shift;
560 if($sort_order){
561 if(lc $sort_order eq "asc"){
562 $sort_order = ' ASC'
563 } elsif (lc $sort_order eq "desc"){
564 $sort_order = ' DESC';
565 } else{
566 $sort_order = undef;
567 return CXGN::BrAPI::JSONResponse->return_error($self->status, "sortOrder valid values are: asc or desc", 400);
571 if($sort_by){
572 my %sort_by_items = (
573 "locationDbId" => " location.value ",
574 "studyDbId" => " study.project_id ",
575 "studyName" => " study.name",
576 "trialDbId" => " folder.project_id ",
577 "trialName" => " folder.name "
579 if ($sort_by_items{$sort_by}){
580 $sort_by = " ORDER BY " . $sort_by_items{$sort_by} ;
581 } else {
582 return CXGN::BrAPI::JSONResponse->return_error($self->status, "sortBy valid values are only: locationDbId, studyDbId, studyName, trialDbId or trialName at the moment.", 400);
586 # my $c = shift;
587 my $page_obj = CXGN::Page->new();
588 my $main_production_site_url = $page_obj->get_hostname();
590 my $trial_search = CXGN::Trial::Search->new({
591 bcs_schema=>$schema,
592 location_list=>$location_names,
593 location_id_list=>$location_ids,
594 trial_type_list=>$study_type_list,
595 # trial_type_ids=>$study_type_ids,
596 trial_id_list=>$study_dbids,
597 trial_name_list=>$study_names,
598 trial_name_is_exact=>1,
599 program_list=>$program_names,
600 program_id_list=>$program_dbids,
601 folder_id_list => $folder_dbids,
602 folder_name_list => $folder_names,
603 trait_list => $obs_variable_ids,
604 accession_list => $germplasm_dbids,
605 accession_name_list => $germplasm_names,
606 year_list => $year_list,
607 externalReferenceSources => $externalReferenceSources,
608 externalReferenceIds => $externalReferenceIds,
609 limit => $page_size,
610 offset => $page_size*$page,
611 sort_by => $sort_by,
612 order_by => $sort_order,
613 field_trials_only => 1,
615 my ($data, $total_count) = $trial_search->search();
616 #print STDERR Dumper $data;
618 my @data_out;
619 foreach (@$data){
621 my $additional_info = {
622 programDbId => qq|$_->{breeding_program_id}|,
623 programName => $_->{breeding_program_name},
625 # Join the additional info with the existing additional info
626 if ($_->{additional_info}) {
627 foreach my $key (keys %{$_->{additional_info}}){
628 $additional_info->{$key} = $_->{additional_info}->{$key};
632 my @seasons = ( $_->{"year"} );
634 my $planting_date;
635 if ($_->{project_planting_date}) {
636 $planting_date = CXGN::TimeUtils::date_to_iso_timestamp($_->{project_planting_date});
637 if($planting_date eq "") { $planting_date = undef; }
639 my $harvest_date;
640 if ($_->{project_harvest_date}) {
641 $harvest_date = CXGN::TimeUtils::date_to_iso_timestamp($_->{project_harvest_date});
642 if($harvest_date eq "") { $harvest_date = undef;}
645 my ($brapi_contacts, @data_links, $data_agreement, %experimental_design, $folder_id, $folder_name);
647 # my $t = CXGN::Trial->new({ bcs_schema => $self->bcs_schema, trial_id => $_->{trial_id} });
648 # my $contacts = $t->get_trial_contacts();
649 # foreach (@$contacts){
650 # push @$brapi_contacts, {
651 # contactDbId => $_->{sp_person_id},
652 # name => $_->{salutation}." ".$_->{first_name}." ".$_->{last_name},
653 # instituteName => $_->{organization},
654 # email => $_->{email},
655 # type => $_->{user_type},
656 # orcid => ''
657 # };
659 # my $additional_files = $t->get_additional_uploaded_files();
660 # foreach (@$additional_files){
661 # push @data_links, {
662 # scientificType => 'Additional File',
663 # name => $_->[4],
664 # url => $main_production_site_url.'/breeders/phenotyping/download/'.$_->[0],
665 # provenance => undef,
666 # dataFormat => undef,
667 # description => undef,
668 # fileFormat => undef,
669 # version => undef
670 # };
673 # my $phenotype_files = $t->get_phenotype_metadata();
674 # foreach (@$phenotype_files){
675 # push @data_links, {
676 # scientificType => 'Uploaded Phenotype File',
677 # name => $_->[4],
678 # url => $main_production_site_url.'/breeders/phenotyping/download/'.$_->[0],
679 # provenance => undef,
680 # dataFormat => undef,
681 # description => undef,
682 # fileFormat => undef,
683 # version => undef
684 # };
686 # $data_agreement = $t->get_data_agreement() ? $t->get_data_agreement() : '';
688 # if ($t->get_design_type()){
689 # $experimental_design = {
690 # PUI => $t->get_design_type(),
691 # description => $t->get_design_type() };
693 # $folder_id = $t->get_folder()->id();
694 # $folder_name = $t->get_folder()->name();
696 if ($_->{design}){
697 $experimental_design{'PUI'} = $_->{design};
698 $experimental_design{'description'} = $_->{design};
701 if ($_->{folder_id}){
702 $folder_id = $_->{folder_id};
703 $folder_name = $_->{folder_name};
704 } else {
705 $folder_id = $_->{breeding_program_id};
706 $folder_name = $_->{breeding_program_name};
709 my $trial_type = $_->{trial_type} ne 'misc_trial' ? $_->{trial_type} : $_->{trial_type_value};
711 my $references = CXGN::BrAPI::v2::ExternalReferences->new({
712 bcs_schema => $schema,
713 table_name => 'project',
714 table_id_key => 'project_id',
715 id => qq|$_->{trial_id}|,
717 my $external_references = $references->search();
718 my @formatted_external_references = %{$external_references} ? values %{$external_references} : [];
721 my %data_obj = (
722 active => JSON::true,
723 additionalInfo => $additional_info,
724 commonCropName => $supported_crop,
725 contacts => $brapi_contacts,
726 culturalPractices => undef,
727 dataLinks => \@data_links,
728 documentationURL => "",
729 endDate => $harvest_date ? $harvest_date : undef,
730 environmentParameters => undef,
731 experimentalDesign => \%experimental_design,
732 externalReferences => @formatted_external_references,
733 growthFacility => undef,
734 lastUpdate => undef,
735 license => $data_agreement,
736 locationDbId => $_->{location_id},
737 locationName => $_->{location_name},
738 observationLevels => undef,
739 observationUnitsDescription => undef,
740 seasons => \@seasons,
741 startDate => $planting_date ? $planting_date : undef,
742 studyCode => undef,
743 studyDbId => qq|$_->{trial_id}|,
744 studyDescription => $_->{description},
745 studyName => $_->{trial_name},
746 studyPUI => undef,
747 studyType => $trial_type,
748 trialDbId => qq|$folder_id|,
749 trialName => $folder_name
751 push @data_out, \%data_obj;
753 return (\@data_out,$total_count);
756 sub _save_trial {
757 my $self = shift;
758 my $chado_schema = $self->get_chado_schema();
759 my $trial_name = $self->get_trial_name();
760 $trial_name =~ s/^\s+|\s+$//g; #trim whitespace from both ends
762 if (!$trial_name) {
763 print STDERR "Trial not saved: Can't create trial without a trial name\n";
764 return { error => "Trial not saved: Can't create trial without a trial name" };
767 if ($self->trial_name_already_exists()) {
768 print STDERR "Can't create trial: Trial name already exists\n";
769 return { error => sprintf("Trial not saved: Trial name %s already exists.", $trial_name) };
772 if (!$self->get_breeding_program_id()) {
773 print STDERR "Can't create trial: Breeding program does not exist\n";
774 return { error => "Trial not saved: breeding program does not exist" };
777 my $project_year_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'project year', 'project_property');
778 my $project_design_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'design', 'project_property');
779 my $field_size_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'field_size', 'project_property');
780 my $plot_width_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'plot_width', 'project_property');
781 my $plot_length_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'plot_length', 'project_property');
782 my $field_trial_is_planned_to_be_genotyped_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'field_trial_is_planned_to_be_genotyped', 'project_property');
783 my $field_trial_is_planned_to_cross_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'field_trial_is_planned_to_cross', 'project_property');
784 my $has_plant_entries_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'project_has_plant_entries', 'project_property');
785 my $has_subplot_entries_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'project_has_subplot_entries', 'project_property');
786 my $trial_stock_type_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'trial_stock_type', 'project_property');
787 my $additional_info_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($chado_schema,'project_additional_info', 'project_property');
789 # Create the trial (brapi study)
790 my $project = $chado_schema->resultset('Project::Project')
791 ->create({
792 name => $trial_name,
793 description => $self->get_trial_description(),
796 # Gets the trial (brapi study)
797 my $t = CXGN::Project->new({
798 bcs_schema => $chado_schema,
799 trial_id => $project->project_id()
802 print STDERR "TRIAL TYPE = ".ref($t)."!!!!\n";
804 my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $chado_schema);
805 $geolocation_lookup->set_location_name($self->get_trial_location());
806 my $geolocation = $geolocation_lookup->get_geolocation();
808 my $nd_experiment_type_id = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'field_layout', 'experiment_type')->cvterm_id();
809 my $nd_experiment = $chado_schema->resultset('NaturalDiversity::NdExperiment')
810 ->create({
811 nd_geolocation_id => $geolocation->nd_geolocation_id(),
812 type_id => $nd_experiment_type_id,
814 #link location to the trial (brapi study)
815 $nd_experiment->find_or_create_related('nd_experiment_projects',{project_id => $project->project_id()});
817 my $source_field_trial_ids = $t->set_field_trials_source_field_trials($self->get_field_trial_from_field_trial);
819 $t->set_location($geolocation->nd_geolocation_id()); # set location also as a project prop
820 $t->set_breeding_program($self->get_breeding_program_id);
821 if ($self->get_trial_type){
822 $t->set_project_type($self->get_trial_type, $self->get_trial_type_value);
825 if ($self->get_planting_date){
826 $t->set_planting_date($self->get_planting_date);
828 if ($self->get_harvest_date){
829 $t->set_harvest_date($self->get_harvest_date);
832 if ($self->has_trial_year) {
833 $project->create_projectprops({
834 $project_year_cvterm->name() => $self->get_trial_year()
837 if ($self->has_design_type) {
838 $project->create_projectprops({
839 $project_design_cvterm->name() => $self->get_design_type()
841 } else {
842 return {error => 'A design type is required'};
844 if ($self->has_field_size && $self->get_field_size){
845 $project->create_projectprops({
846 $field_size_cvterm->name() => $self->get_field_size
849 if ($self->has_plot_width && $self->get_plot_width){
850 $project->create_projectprops({
851 $plot_width_cvterm->name() => $self->get_plot_width
854 if ($self->has_plot_length && $self->get_plot_length){
855 $project->create_projectprops({
856 $plot_length_cvterm->name() => $self->get_plot_length
859 if ($self->has_trial_stock_type && $self->get_trial_stock_type){
860 $project->create_projectprops({
861 $trial_stock_type_cvterm->name() => $self->get_trial_stock_type
864 if ($self->get_additional_info) {
865 $project->create_projectprops({
866 $additional_info_cvterm_id->name() => encode_json($self->get_additional_info)
870 return { project_id => $project->project_id() };