Merge pull request #5191 from solgenomics/topic/quality_control
[sgn.git] / bin / upload_multiple_trial_design.pl
blobe1903b6f99b1397ebd4a81f69515044a1bb28c42
1 #!/usr/bin/perl
3 =head1
5 upload_multiple_trial_design.pl
7 =head1 SYNOPSIS
9 upload_multiple_trial_design.pl -H [dbhost] -D [dbname] -P [dbpass] -w [basepath] -U [dbuser] -i infile -un [username] -e [email address]
11 =head1 COMMAND-LINE OPTIONS
12 ARGUMENTS
13 -H host name (required) Ex: "breedbase_db"
14 -D database name (required) Ex: "breedbase"
15 -U database username Ex: "postgres"
16 -P database userpass Ex: "postgres"
17 -w basepath (required) Ex: /home/production/cxgn/sgn
18 -i path to infile (required)
19 -un username of uploader (required)
20 -e email address of the user
21 if loading trial data from metadata file, phenotypes + layout from infile
23 =head2 DESCRIPTION
25 perl bin/upload_multiple_trial_design.pl -H breedbase_db -D breedbase -U postgres -P postgres -w /home/cxgn/sgn/ -un janedoe -i ~/Desktop/test_multi.xlsx -e 'sk2783@cornell.edu' -iw
27 This script will parse and validate the input file. If there are any warnings or errors during validation it will send a error message to the provided email. It will print any errors and warnings to the console.
28 If there are no errors or warnings (or warnings are ignored) during validation it will then store the data.
29 The input file should be any file supported by the CXGN::File::Parse class.
31 =head1 AUTHOR
33 Srikanth (sk2783@cornell.edu)
35 =cut
37 use strict;
38 use Getopt::Long;
39 use Bio::Chado::Schema;
40 use CXGN::DB::InsertDBH;
41 use Try::Tiny;
42 use DateTime;
43 use Pod::Usage;
44 use CXGN::Trial; # add project metadata
45 use CXGN::Trial::ParseUpload;
46 use CXGN::Trial::TrialCreate;
47 use CXGN::Contact;
48 use CXGN::TrialStatus;
50 my ( $help, $dbhost, $dbname, $basepath, $dbuser, $dbpass, $infile, $username, $email_address, $ignore_warnings);
51 GetOptions(
52 'dbhost|H=s' => \$dbhost,
53 'dbname|D=s' => \$dbname,
54 'dbuser|U=s' => \$dbuser,
55 'dbpass|P=s' => \$dbpass,
56 'basepath|w=s' => \$basepath,
57 'i=s' => \$infile,
58 'user|un=s' => \$username,
59 'email|e=s' => \$email_address,
60 'ignore_warnings|iw!' => \$ignore_warnings,
61 'help' => \$help,
63 pod2usage(1) if $help;
64 if (!$infile || !$username || !$basepath || !$dbname || !$dbhost ) {
65 pod2usage({ -msg => 'Error. Missing options!', -verbose => 1, -exitval => 1 });
68 # Lists of encountered errors and warnings
69 my @errors;
70 my @warnings;
72 # Connect to databases
73 my $dbh;
74 if ($dbpass && $dbuser) {
75 $dbh = DBI->connect(
76 "dbi:Pg:database=$dbname;host=$dbhost",
77 $dbuser,
78 $dbpass,
79 {AutoCommit => 1, RaiseError => 1}
82 else {
83 $dbh = CXGN::DB::InsertDBH->new({
84 dbhost => $dbhost,
85 dbname => $dbname,
86 dbargs => {AutoCommit => 1, RaiseError => 1}
87 });
89 my $chado_schema = Bio::Chado::Schema->connect(sub { $dbh }, { on_connect_do => ['SET search_path TO public, sgn, metadata, phenome;'] });
90 print STDOUT "Database connection ok!\n";
92 my $parsed_data;
93 my $validation_coderef = sub {
94 # Parse uploaded file with appropriate plugin
95 my $parser = CXGN::Trial::ParseUpload->new(chado_schema => $chado_schema, filename => $infile);
96 $parser->load_plugin('MultipleTrialDesignGeneric');
97 $parsed_data = $parser->parse();
99 # Parser has errors, print error messages and quit
100 if ($parser->has_parse_errors()) {
101 my $errors = $parser->get_parse_errors();
102 foreach (@{$errors->{'error_messages'}}) {
103 push @errors, $_;
105 finish();
108 # Parser has warnings, print warning messages and quit unless we're ignoring warnings
109 if ($parser->has_parse_warnings()) {
110 unless ($ignore_warnings) {
111 my $warnings = $parser->get_parse_warnings();
112 foreach (@{$warnings->{'warning_messages'}}) {
113 push @warnings, $_;
115 finish();
120 try {
121 $chado_schema->txn_do($validation_coderef);
122 } catch {
123 push @errors, $_;
126 # Check for parsed data
127 finish("There is no parsed data from the input file!") if !$parsed_data;
129 # Get User ID
130 my $sp_person_id = CXGN::People::Person->get_person_by_username($dbh, $username);
131 finish("User not found in database for username $username!") if !$sp_person_id;
133 # Create and Save Trials
134 my %all_designs = %{$parsed_data};
135 my %saved_trials;
136 my $coderef = sub {
137 for my $trial_name ( keys %all_designs ) {
138 my $trial_design = $all_designs{$trial_name};
139 my %trial_info_hash = (
140 chado_schema => $chado_schema,
141 dbh => $dbh,
142 owner_id => $sp_person_id,
143 trial_year => $trial_design->{'year'},
144 trial_description => $trial_design->{'description'},
145 trial_location => $trial_design->{'location'},
146 trial_name => $trial_name,
147 design_type => $trial_design->{'design_type'},
148 design => $trial_design->{'design_details'},
149 program => $trial_design->{'breeding_program'},
150 upload_trial_file => $infile,
151 operator => $username,
152 owner_id => $sp_person_id
154 my $entry_numbers = $trial_design->{'entry_numbers'};
156 if ($trial_design->{'trial_type'}){
157 $trial_info_hash{trial_type} = $trial_design->{'trial_type'};
159 if ($trial_design->{'plot_width'}){
160 $trial_info_hash{plot_width} = $trial_design->{'plot_width'};
162 if ($trial_design->{'plot_length'}){
163 $trial_info_hash{plot_length} = $trial_design->{'plot_length'};
165 if ($trial_design->{'field_size'}){
166 $trial_info_hash{field_size} = $trial_design->{'field_size'};
168 if ($trial_design->{'planting_date'}){
169 $trial_info_hash{planting_date} = $trial_design->{'planting_date'};
171 if ($trial_design->{'harvest_date'}){
172 $trial_info_hash{harvest_date} = $trial_design->{'harvest_date'};
174 if ($trial_design->{'transplanting_date'}){
175 $trial_info_hash{transplanting_date} = $trial_design->{'transplanting_date'};
177 my $trial_create = CXGN::Trial::TrialCreate->new(\%trial_info_hash);
178 my $current_save = $trial_create->save_trial();
180 if ($current_save->{error}){
181 $chado_schema->txn_rollback();
182 finish($current_save->{'error'});
183 } elsif ($current_save->{'trial_id'}) {
184 my $trial_id = $current_save->{'trial_id'};
185 my $time = DateTime->now();
186 my $timestamp = $time->ymd();
187 my $calendar_funcs = CXGN::Calendar->new({});
188 my $formatted_date = $calendar_funcs->check_value_format($timestamp);
189 my $upload_date = $calendar_funcs->display_start_date($formatted_date);
190 $saved_trials{$trial_id} = $trial_name;
192 my %trial_activity;
193 $trial_activity{'Trial Uploaded'}{'user_id'} = $sp_person_id;
194 $trial_activity{'Trial Uploaded'}{'activity_date'} = $upload_date;
196 my $trial_activity_obj = CXGN::TrialStatus->new({ bcs_schema => $chado_schema });
197 $trial_activity_obj->trial_activities(\%trial_activity);
198 $trial_activity_obj->parent_id($trial_id);
199 my $activity_prop_id = $trial_activity_obj->store();
202 # save entry numbers, if provided
203 if ( $entry_numbers && scalar(keys %$entry_numbers) > 0 && $current_save->{'trial_id'} ) {
204 my %entry_numbers_prop;
205 my @stock_names = keys %$entry_numbers;
207 # Convert stock names from parsed trial template to stock ids for data storage
208 my $stocks = $chado_schema->resultset('Stock::Stock')->search({ uniquename=>{-in=>\@stock_names} });
209 while (my $s = $stocks->next()) {
210 $entry_numbers_prop{$s->stock_id} = $entry_numbers->{$s->uniquename};
213 # Lookup synonyms of accession names
214 my $synonym_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'stock_synonym', 'stock_property')->cvterm_id();
215 my $acc_synonym_rs = $chado_schema->resultset("Stock::Stock")->search({
216 'me.is_obsolete' => { '!=' => 't' },
217 'stockprops.value' => { -in => \@stock_names},
218 'stockprops.type_id' => $synonym_cvterm_id
219 },{join => 'stockprops', '+select'=>['stockprops.value'], '+as'=>['synonym']});
220 while (my $r=$acc_synonym_rs->next) {
221 if ( exists($entry_numbers->{$r->get_column('synonym')}) ) {
222 $entry_numbers_prop{$r->stock_id} = $entry_numbers->{$r->get_column('synonym')};
226 # store entry numbers
227 my $trial = CXGN::Trial->new({ bcs_schema => $chado_schema, trial_id => $current_save->{'trial_id'} });
228 $trial->set_entry_numbers(\%entry_numbers_prop);
234 try {
235 $chado_schema->txn_do($coderef);
236 } catch {
237 push @errors, $_;
240 finish();
242 sub finish {
243 my $error = shift;
244 push @errors, $error if $error;
246 # Print errors and warnings to STDERR
247 foreach (@errors) {
248 print STDERR "ERROR: $_\n";
250 foreach (@warnings) {
251 print STDERR "WARNING: $_\n";
254 # Send email message, if requested
255 # Exit the script: 0 = success, 1 = errors, 2 = warnings
256 if ( scalar(@errors) > 0 ) {
257 if ( $email_address ) {
258 my $email_subject = "Multiple Trial Designs upload failed";
259 my $email_body = "Dear $username,\n\nThere were one or more errors in uploading your trials:\n\n";
260 foreach my $error (@errors) {
261 $error =~ s/<[^>]*>//g;
262 $email_body .= "$error\n";
264 $email_body .= "\nYou will need to fix the errors and upload the corrected file. Thank you\nHave a nice day\n\n";
265 CXGN::Contact::send_email($email_subject, $email_body, $email_address);
267 exit(1);
269 if ( scalar(@warnings) > 0 ) {
270 if ( $email_address ) {
271 my $email_subject = "Multiple Trial Designs upload failed";
272 my $email_body = "Dear $username,\n\nThere were one or more warnings in uploading your trials and the option to ignore warnings was not enabled. The warnings include:\n\n";
273 foreach my $warning (@warnings) {
274 $warning =~ s/<[^>]*>//g;
275 $email_body .= "$warning\n";
277 $email_body .= "\nYou will need to either fix the warnings and upload the corrected file or upload the same file with the option to ignore warnings enabled. Thank you\nHave a nice day\n\n";
278 CXGN::Contact::send_email($email_subject, $email_body, $email_address);
280 exit(2);
282 else {
283 my $bs = CXGN::BreederSearch->new({ dbh=>$dbh, dbname=>$dbname });
284 my $refresh = $bs->refresh_matviews($dbhost, $dbname, $dbuser, $dbpass, 'all_but_genoview', 'concurrent', $basepath);
286 if ( $email_address ) {
287 my $email_subject = "Multiple Trial Designs upload successful";
288 my $email_body = "Dear $username,\n\nCongratulations, all the multiple trial designs have been successfully uploaded into the database\n\nThank you\nHave a nice day\n\n";
289 CXGN::Contact::send_email($email_subject, $email_body, $email_address);
292 exit(0);