modified material sources
[sgn.git] / lib / SGN / Controller / AJAX / Order.pm
blob20d1bc23d455aee240b7afddb3d51fd0c2b755e6
2 package SGN::Controller::AJAX::Order;
4 use Moose;
5 use CXGN::Stock::Order;
6 use CXGN::Stock::OrderBatch;
7 use Data::Dumper;
8 use JSON;
9 use DateTime;
10 use CXGN::People::Person;
11 use CXGN::Contact;
13 use File::Basename qw | basename dirname|;
14 use File::Copy;
15 use File::Slurp;
16 use File::Spec::Functions;
17 use Digest::MD5;
18 use File::Path qw(make_path);
19 use File::Spec::Functions qw / catfile catdir/;
21 use LWP::UserAgent;
22 use LWP::Simple;
23 use HTML::Entities;
24 use URI::Encode qw(uri_encode uri_decode);
25 use Tie::UrlEncoder; our(%urlencode);
28 BEGIN { extends 'Catalyst::Controller::REST' }
30 __PACKAGE__->config(
31 default => 'application/json',
32 stash_key => 'rest',
33 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
37 sub submit_order : Path('/ajax/order/submit') : ActionClass('REST'){ }
39 sub submit_order_POST : Args(0) {
40 my $self = shift;
41 my $c = shift;
42 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
43 my $people_schema = $c->dbic_schema('CXGN::People::Schema');
44 my $dbh = $c->dbc->dbh();
45 my $list_id = $c->req->param('list_id');
46 my $time = DateTime->now();
47 my $timestamp = $time->ymd()."_".$time->hms();
48 my $request_date = $time->ymd();
49 # print STDERR "LIST ID =".Dumper($list_id)."\n";
51 if (!$c->user()) {
52 print STDERR "User not logged in... not adding a catalog item.\n";
53 $c->stash->{rest} = {error_string => "You must be logged in to add a catalog item." };
54 return;
56 my $user_id = $c->user()->get_object()->get_sp_person_id();
57 my $user_name = $c->user()->get_object()->get_username();
58 my $user_role = $c->user->get_object->get_user_type();
60 my $list = CXGN::List->new( { dbh=>$dbh, list_id=>$list_id });
61 my $items = $list->elements();
62 # print STDERR "ITEMS =".Dumper($items)."\n";
63 my $catalog_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'stock_catalog_json', 'stock_property')->cvterm_id();
64 my %group_by_contact_id;
65 my @all_new_rows;
66 my @all_items = @$items;
67 foreach my $ordered_item (@all_items) {
68 my @ona_info = ();
69 my @ordered_item_split = split /,/, $ordered_item;
70 my $number_of_fields = @ordered_item_split;
71 my $item_name = $ordered_item_split[0];
72 my $item_rs = $schema->resultset("Stock::Stock")->find( { uniquename => $item_name });
73 my $item_id = $item_rs->stock_id();
74 my $item_info_rs = $schema->resultset("Stock::Stockprop")->find({stock_id => $item_id, type_id => $catalog_cvterm_id});
75 my $item_info_string = $item_info_rs->value();
76 my $item_info_hash = decode_json $item_info_string;
77 my $contact_person_id = $item_info_hash->{'contact_person_id'};
78 my $item_type = $item_info_hash->{'item_type'};
79 my $item_source = $item_info_hash->{'material_source'};
80 $group_by_contact_id{$contact_person_id}{'item_list'}{$item_name}{'item_type'} = $item_type;
81 $group_by_contact_id{$contact_person_id}{'item_list'}{$item_name}{'material_source'} = $item_source;
83 my $quantity_string = $ordered_item_split[1];
84 my @quantity_info = split /:/, $quantity_string;
85 my $quantity = $quantity_info[1];
86 $quantity =~ s/^\s+|\s+$//g;
87 $group_by_contact_id{$contact_person_id}{'item_list'}{$item_name}{'quantity'} = $quantity;
89 my $ona_additional_info;
90 if ($number_of_fields == 3) {
91 my $optional_field = $ordered_item_split[2];
92 my @optional_field_array = split /:/, $optional_field;
93 my $optional_title = $optional_field_array[0];
94 $optional_title =~ s/^\s+|\s+$//g;
95 print STDERR "OPTIONAL TITLE =".Dumper($optional_title)."\n";
96 my $optional_info = $optional_field_array[1];
97 $optional_info =~ s/^\s+|\s+$//g;
98 print STDERR "OPTIONAL INFO =".Dumper($optional_info)."\n";
99 if ($optional_title eq 'Comments') {
100 $group_by_contact_id{$contact_person_id}{'item_list'}{$item_name}{'comments'} = $optional_info;
101 } elsif ($optional_title eq 'Additional Info') {
102 $group_by_contact_id{$contact_person_id}{'item_list'}{$item_name}{'additional_info'} = $optional_info;
103 $ona_additional_info = $optional_info;
104 print STDERR "ONA ADDITIONAL INFO =".Dumper($ona_additional_info)."\n";
106 } elsif ($number_of_fields == 4) {
107 my $additional_info_field = $ordered_item_split[2];
108 my @additional_info_array = split /:/, $additional_info_field;
109 my $additional_info = $additional_info_array[1];
110 $additional_info =~ s/^\s+|\s+$//g;
111 $group_by_contact_id{$contact_person_id}{'item_list'}{$item_name}{'additional_info'} = $additional_info;
112 $ona_additional_info = $additional_info;
113 my $comments_field = $ordered_item_split[3];
114 my @comments_array = split /:/, $comments_field;
115 my $comments = $comments_array[1];
116 $comments =~ s/^\s+|\s+$//g;
117 $group_by_contact_id{$contact_person_id}{'item_list'}{$item_name}{'comments'} = $comments;
120 @ona_info = ($item_source, $item_name, $quantity, $ona_additional_info, $request_date);
121 $group_by_contact_id{$contact_person_id}{'ona'}{$item_name} = \@ona_info;
124 my $ordering_service_name = $c->config->{ordering_service_name};
125 my $ordering_service_url = $c->config->{ordering_service_url};
126 my $ona_new_id;
127 my @item_list;
128 my @contact_email_list;
129 foreach my $contact_id (keys %group_by_contact_id) {
130 my @history = ();
131 my $history_info = {};
132 my $item_ref = $group_by_contact_id{$contact_id}{'item_list'};
133 my %item_hashes = %{$item_ref};
134 my @item_list = map { { $_ => $item_hashes{$_} } } keys %item_hashes;
136 my $new_order = CXGN::Stock::Order->new( { people_schema => $people_schema, dbh => $dbh});
137 $new_order->order_from_id($user_id);
138 $new_order->order_to_id($contact_id);
139 $new_order->order_status("submitted");
140 $new_order->create_date($timestamp);
141 my $order_id = $new_order->store();
142 # print STDERR "ORDER ID =".($order_id)."\n";
143 if (!$order_id){
144 $c->stash->{rest} = {error_string => "Error saving your order",};
145 return;
148 $history_info ->{'submitted'} = $timestamp;
149 push @history, $history_info;
151 my $order_prop = CXGN::Stock::OrderBatch->new({ bcs_schema => $schema, people_schema => $people_schema});
152 $order_prop->clone_list(\@item_list);
153 $order_prop->parent_id($order_id);
154 $order_prop->history(\@history);
155 my $order_prop_id = $order_prop->store_sp_orderprop();
156 # print STDERR "ORDER PROP ID =".($order_prop_id)."\n";
158 if (!$order_prop_id){
159 $c->stash->{rest} = {error_string => "Error saving your order",};
160 return;
163 my $contact_person = CXGN::People::Person -> new($dbh, $contact_id);
164 my $contact_email = $contact_person->get_contact_email();
165 push @contact_email_list, $contact_email;
167 if ($ordering_service_name eq 'ONA') {
168 my $each_contact_id_ona = $group_by_contact_id{$contact_id}{'ona'};
169 my $order_location;
170 foreach my $item (keys %{$each_contact_id_ona}) {
171 my @new_order_row = ();
172 my $ona_ref = $each_contact_id_ona->{$item};
173 $order_location = $ona_ref->[0];
174 @new_order_row = @$ona_ref;
175 splice @new_order_row, 1, 0, $order_id;
176 push @all_new_rows, [@new_order_row];
179 my $order_file_name = $order_location.'_orders.csv';
180 my $id_string;
181 my $form_id;
182 my $ua = LWP::UserAgent->new;
183 $ua->credentials( 'api.ona.io:443', 'DJANGO', $c->config->{ordering_service_username}, $c->config->{ordering_service_password} );
184 my $login_resp = $ua->get("https://api.ona.io/api/v1/user.json");
185 my $server_endpoint_1 = "https://api.ona.io/api/v1/data";
186 my $resp = $ua->get($server_endpoint_1);
188 if ($resp->is_success) {
189 my $message = $resp->decoded_content;
190 my $all_info = decode_json $message;
191 foreach my $info (@$all_info) {
192 my %info_hash = %{$info};
193 if ($info_hash{'id_string'} eq $order_location) {
194 $form_id = $info_hash{'id'};
199 if ($form_id) {
200 my ($previous_order_temp_file, $previous_order_uri1) = $c->tempfile( TEMPLATE => 'download/previous_ona_order_infoXXXXX');
201 my $previous_order_temp_file_path = $previous_order_temp_file->filename;
203 my $order_ona_id;
204 my $server_endpoint_2 = "https://api.ona.io/api/v1/metadata?xform=".$form_id;
205 my $resp_d = $ua->get($server_endpoint_2);
206 if ($resp_d->is_success) {
207 my $message_d = $resp_d->decoded_content;
208 my $message_hash_d = decode_json $message_d;
209 foreach my $t (@$message_hash_d) {
210 if ($t->{'data_value'} eq $order_file_name) {
211 # print STDERR "DELETE INFO =".Dumper($t)."\n";
212 getstore($t->{media_url}, $previous_order_temp_file_path);
213 $order_ona_id = $t->{id};
217 my @previous_order_rows;
218 my @all_order_rows;
219 if ($order_ona_id) {
220 open(my $fh, '<', $previous_order_temp_file_path)
221 or die "Could not open file!";
222 my $old_header_row = <$fh>;
223 while ( my $row = <$fh> ){
224 chomp $row;
225 push @previous_order_rows, [split ',', $row];
227 push @all_order_rows, (@previous_order_rows);
230 push @all_order_rows, (@all_new_rows);
232 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema');
233 my $ona_header = '"location","orderNo","accessionName","requestedNumberOfClones","additionalInfo","requestDate"';
234 my $template_file_name = $order_location.'_orders';
235 my $user_id = $c->user()->get_object()->get_sp_person_id();
236 my $user_name = $c->user()->get_object()->get_username();
237 my $time = DateTime->now();
238 my $timestamp = $time->ymd()."_".$time->hms();
239 my $subdirectory_name = "ona_order_info";
240 my $archived_file_name = catfile($user_id, $subdirectory_name,$template_file_name.".csv");
241 my $archive_path = $c->config->{archive_path};
242 my $file_destination = catfile($archive_path, $archived_file_name);
243 my $dir = $c->tempfiles_subdir('/download');
244 my $rel_file = $c->tempfile( TEMPLATE => 'download/ona_order_infoXXXXX');
245 my $tempfile = $c->config->{basepath}."/".$rel_file.".csv";
246 # print STDERR "TEMPFILE =".Dumper($tempfile)."\n";
247 open(my $FILE, '> :encoding(UTF-8)', $tempfile) or die "Cannot open tempfile $tempfile: $!";
249 print $FILE $ona_header."\n";
250 my $order_row = 0;
251 foreach my $row (@all_order_rows) {
252 my @row_array = ();
253 @row_array = @$row;
254 my $csv_format = join(',',@row_array);
255 print $FILE $csv_format."\n";
256 $order_row++;
258 close $FILE;
260 open(my $F, "<", $tempfile) || die "Can't open file ".$self->tempfile();
261 binmode $F;
262 my $md5 = Digest::MD5->new();
263 $md5->addfile($F);
264 close($F);
266 if (!-d $archive_path) {
267 mkdir $archive_path;
270 if (! -d catfile($archive_path, $user_id)) {
271 mkdir (catfile($archive_path, $user_id));
274 if (! -d catfile($archive_path, $user_id,$subdirectory_name)) {
275 mkdir (catfile($archive_path, $user_id, $subdirectory_name));
277 my $md_row = $metadata_schema->resultset("MdMetadata")->create({
278 create_person_id => $user_id,
280 $md_row->insert();
281 my $file_row = $metadata_schema->resultset("MdFiles")->create({
282 basename => basename($file_destination),
283 dirname => dirname($file_destination),
284 filetype => 'orders',
285 md5checksum => $md5->hexdigest(),
286 metadata_id => $md_row->metadata_id(),
288 $file_row->insert();
289 my $file_id = $file_row->file_id();
291 move($tempfile,$file_destination);
292 unlink $tempfile;
293 print STDERR "FILE ID =".Dumper($file_id)."\n";
294 print STDERR "FILE DESTINATION =".Dumper($file_destination)."\n";
296 if ($order_ona_id) {
297 my $server_endpoint_3 = "https://api.ona.io/api/v1/metadata";
298 my $delete_resp = $ua->delete(
299 $server_endpoint_3."/$order_ona_id"
301 if ($delete_resp->is_success) {
302 print STDERR "Deleted order file on ONA $order_ona_id.\n";
303 } else {
304 print STDERR "ERROR: Did not delete order file on ONA $order_ona_id.\n";
305 #print STDERR Dumper $delete_resp;
309 my $server_endpoint_4 = "https://api.ona.io/api/v1/metadata";
310 my $add_resp = $ua->post(
311 $server_endpoint_4,
312 Content_Type => 'form-data',
313 Content => [
314 data_file => [ $file_destination, $file_destination, Content_Type => 'text/plain', ],
315 "xform"=>$form_id,
316 "data_type"=>"media",
317 "data_value"=>$file_destination
321 if ($add_resp->is_success) {
322 my $message = $add_resp->decoded_content;
323 my $message_hash = decode_json $message;
324 $ona_new_id = $message_hash->{id};
325 if (!$ona_new_id){
326 $c->stash->{rest} = {error_string => "Error sending your order to BANANA ORDERING SYSTEM"};
327 return;
330 } else {
331 $c->stash->{rest} = {error_string => "BANANA ORDERING SYSTEM hasn't been set up for $order_location. Please contact admin."};
332 return;
337 my $host = $c->config->{main_production_site_url};
338 my $project_name = $c->config->{project_name};
339 my $subject="Ordering Notification from $project_name";
340 my $body=<<END_HEREDOC;
342 You have an order submitted to $project_name ($host/order/stocks/view).
343 Please do *NOT* reply to this message.
345 Thank you,
346 $project_name Team
348 END_HEREDOC
350 foreach my $each_email (@contact_email_list) {
351 CXGN::Contact::send_email($subject,$body,$each_email);
354 if ($ona_new_id) {
355 $c->stash->{rest}->{success} .= 'Your order has been sent successfully to Banana Ordering System.';
356 } else {
357 $c->stash->{rest}->{success} .= 'Your order has been submitted successfully and the vendor has been notified.';
363 sub get_user_current_orders :Path('/ajax/order/current') Args(0) {
364 my $self = shift;
365 my $c = shift;
366 my $schema = $c->dbic_schema("Bio::Chado::Schema");
367 my $people_schema = $c->dbic_schema('CXGN::People::Schema');
368 my $dbh = $c->dbc->dbh;
369 my $user_id;
371 if (!$c->user){
372 $c->stash->{rest} = {error=>'You must be logged in to view your current orders!'};
373 $c->detach();
376 if ($c->user){
377 $user_id = $c->user()->get_object()->get_sp_person_id();
380 my $orders = CXGN::Stock::Order->new({ dbh => $dbh, people_schema => $people_schema, order_from_id => $user_id});
381 my $all_orders_ref = $orders->get_orders_from_person_id();
382 my @current_orders;
383 my @all_orders = @$all_orders_ref;
384 foreach my $order (@all_orders) {
385 if (($order->[3]) ne 'completed') {
386 push @current_orders, [qq{<a href="/order/details/view/$order->[0]">$order->[0]</a>}, $order->[1], $order->[2], $order->[3], $order->[5], $order->[6]]
389 $c->stash->{rest} = {data => \@current_orders};
392 sub get_user_completed_orders :Path('/ajax/order/completed') Args(0) {
393 my $self = shift;
394 my $c = shift;
395 my $schema = $c->dbic_schema("Bio::Chado::Schema");
396 my $people_schema = $c->dbic_schema('CXGN::People::Schema');
397 my $dbh = $c->dbc->dbh;
398 my $user_id;
400 if (!$c->user){
401 $c->stash->{rest} = {error=>'You must be logged in to view your completed orders!'};
402 $c->detach();
405 if ($c->user){
406 $user_id = $c->user()->get_object()->get_sp_person_id();
409 my $orders = CXGN::Stock::Order->new({ dbh => $dbh, people_schema => $people_schema, order_from_id => $user_id});
410 my $all_orders_ref = $orders->get_orders_from_person_id();
411 my @completed_orders;
412 my @all_orders = @$all_orders_ref;
413 foreach my $order (@all_orders) {
414 if (($order->[3]) eq 'completed') {
415 push @completed_orders, [qq{<a href="/order/details/view/$order->[0]">$order->[0]</a>}, $order->[1], $order->[2], $order->[3], $order->[4], $order->[5], $order->[6]]
419 $c->stash->{rest} = {data => \@completed_orders};
424 sub get_vendor_current_orders :Path('/ajax/order/vendor_current_orders') Args(0) {
425 my $self = shift;
426 my $c = shift;
427 my $schema = $c->dbic_schema("Bio::Chado::Schema");
428 my $people_schema = $c->dbic_schema('CXGN::People::Schema');
429 my $dbh = $c->dbc->dbh;
430 my $user_id;
432 if (!$c->user){
433 $c->stash->{rest} = {error=>'You must be logged in to view your orders!'};
434 $c->detach();
437 if ($c->user){
438 $user_id = $c->user()->get_object()->get_sp_person_id();
441 my $orders = CXGN::Stock::Order->new({ dbh => $dbh, people_schema => $people_schema, order_to_id => $user_id});
442 my $vendor_orders_ref = $orders->get_orders_to_person_id();
444 my @vendor_current_orders;
445 my @all_vendor_orders = @$vendor_orders_ref;
446 foreach my $vendor_order (@all_vendor_orders) {
447 if (($vendor_order->{'order_status'}) ne 'completed') {
448 push @vendor_current_orders, $vendor_order
452 $c->stash->{rest} = {data => \@vendor_current_orders};
457 sub get_vendor_completed_orders :Path('/ajax/order/vendor_completed_orders') Args(0) {
458 my $self = shift;
459 my $c = shift;
460 my $schema = $c->dbic_schema("Bio::Chado::Schema");
461 my $people_schema = $c->dbic_schema('CXGN::People::Schema');
462 my $dbh = $c->dbc->dbh;
463 my $user_id;
465 if (!$c->user){
466 $c->stash->{rest} = {error=>'You must be logged in to view your orders!'};
467 $c->detach();
470 if ($c->user) {
471 $user_id = $c->user()->get_object()->get_sp_person_id();
474 my $orders = CXGN::Stock::Order->new({ dbh => $dbh, people_schema => $people_schema, order_to_id => $user_id});
475 my $vendor_orders_ref = $orders->get_orders_to_person_id();
477 my @vendor_completed_orders;
478 my @all_vendor_orders = @$vendor_orders_ref;
479 foreach my $vendor_order (@all_vendor_orders) {
480 if (($vendor_order->{'order_status'}) eq 'completed') {
481 push @vendor_completed_orders, $vendor_order
485 $c->stash->{rest} = {data => \@vendor_completed_orders};
490 sub update_order :Path('/ajax/order/update') :Args(0) {
491 my $self = shift;
492 my $c = shift;
493 my $people_schema = $c->dbic_schema('CXGN::People::Schema');
494 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
495 my $dbh = $c->dbc->dbh;
496 my $order_id = $c->req->param('order_id');
497 my $new_status = $c->req->param('new_status');
498 my $contact_person_comments = $c->req->param('contact_person_comments');
499 my $time = DateTime->now();
500 my $timestamp = $time->ymd()."_".$time->hms();
501 my $user_id;
503 if (!$c->user){
504 $c->stash->{rest} = {error=>'You must be logged in to update the orders!'};
505 $c->detach();
508 if ($c->user) {
509 $user_id = $c->user()->get_object()->get_sp_person_id();
512 my $order_obj;
513 if ($new_status eq 'completed') {
514 $order_obj = CXGN::Stock::Order->new({ dbh => $dbh, people_schema => $people_schema, sp_order_id => $order_id, order_to_id => $user_id, order_status => $new_status, completion_date => $timestamp, comments => $contact_person_comments});
515 } else {
516 $order_obj = CXGN::Stock::Order->new({ dbh => $dbh, people_schema => $people_schema, sp_order_id => $order_id, order_to_id => $user_id, order_status => $new_status, comments => $contact_person_comments});
519 my $updated_order = $order_obj->store();
520 # print STDERR "UPDATED ORDER ID =".Dumper($updated_order)."\n";
521 if (!$updated_order){
522 $c->stash->{rest} = {error_string => "Error updating the order",};
523 return;
526 my $orderprop_rs = $people_schema->resultset('SpOrderprop')->find( { sp_order_id => $order_id } );
527 my $orderprop_id = $orderprop_rs->sp_orderprop_id();
528 my $details_json = $orderprop_rs->value();
529 print STDERR "ORDER PROP ID =".Dumper($orderprop_id)."\n";
530 my $detail_hash = JSON::Any->jsonToObj($details_json);
532 my $order_history_ref = $detail_hash->{'history'};
533 my @order_history = @$order_history_ref;
534 my $new_status_record = {};
535 $new_status_record->{$new_status} = $timestamp;
536 push @order_history, $new_status_record;
537 $detail_hash->{'history'} = \@order_history;
539 my $order_prop = CXGN::Stock::OrderBatch->new({ bcs_schema => $schema, people_schema => $people_schema, sp_order_id => $order_id, prop_id => $orderprop_id});
540 $order_prop->history(\@order_history);
541 my $updated_orderprop = $order_prop->store_sp_orderprop();
543 if (!$updated_orderprop){
544 $c->stash->{rest} = {error_string => "Error updating the order",};
545 return;
548 $c->stash->{rest} = {success => "1",};