From 11d2ae5772060a0426dc8722dfe69bf2c6aeceea Mon Sep 17 00:00:00 2001
From: Werner Hahn
Date: Fri, 22 Sep 2017 02:32:53 +0200
Subject: [PATCH] WebshopApi: ShopOrder Controller
---
SL/Controller/ShopOrder.pm | 407 ++++++++++++++++++
SL/DB/Helper/LinkedRecords.pm | 2 +
js/kivi.ShopOrder.js | 35 ++
templates/webpages/shop_order/_filter.html | 38 ++
.../webpages/shop_order/_transfer_status.html | 61 +++
templates/webpages/shop_order/list.html | 204 +++++++++
templates/webpages/shop_order/show.html | 208 +++++++++
7 files changed, 955 insertions(+)
create mode 100644 SL/Controller/ShopOrder.pm
create mode 100644 js/kivi.ShopOrder.js
create mode 100644 templates/webpages/shop_order/_filter.html
create mode 100644 templates/webpages/shop_order/_transfer_status.html
create mode 100644 templates/webpages/shop_order/list.html
create mode 100644 templates/webpages/shop_order/show.html
diff --git a/SL/Controller/ShopOrder.pm b/SL/Controller/ShopOrder.pm
new file mode 100644
index 000000000..e8d804f27
--- /dev/null
+++ b/SL/Controller/ShopOrder.pm
@@ -0,0 +1,407 @@
+package SL::Controller::ShopOrder;
+
+use strict;
+
+use parent qw(SL::Controller::Base);
+
+use SL::BackgroundJob::ShopOrderMassTransfer;
+use SL::System::TaskServer;
+use SL::DB::ShopOrder;
+use SL::DB::ShopOrderItem;
+use SL::DB::Shop;
+use SL::DB::History;
+use SL::DBUtils;
+use SL::Shop;
+use SL::Presenter;
+use SL::Helper::Flash;
+use SL::Locale::String;
+use SL::Controller::Helper::ParseFilter;
+use Rose::Object::MakeMethods::Generic
+(
+ 'scalar --get_set_init' => [ qw(shop_order shops transferred js) ],
+);
+
+__PACKAGE__->run_before('check_auth');
+__PACKAGE__->run_before('setup');
+
+use Data::Dumper;
+
+sub action_get_orders {
+ my ( $self ) = @_;
+ my $orders_fetched;
+ my $new_orders;
+ my %new_order;
+ my $active_shops = SL::DB::Manager::Shop->get_all(query => [ obsolete => 0 ]);
+ foreach my $shop_config ( @{ $active_shops } ) {
+ my $shop = SL::Shop->new( config => $shop_config );
+ my $connect = $shop->check_connectivity;
+
+ if( !$connect->{success} ){
+ %new_order = (
+ number_of_orders => $connect->{data}->{version},
+ shop_id => $shop->config->description,
+ error => 1,
+ );
+ $new_orders = \%new_order;
+ }else{
+ $new_orders = $shop->connector->get_new_orders;
+ }
+ push @{ $orders_fetched }, $new_orders ;
+ }
+
+ foreach my $shop_fetched(@{ $orders_fetched }) {
+ if($shop_fetched->{error}){
+ flash_later('error', t8('From shop "#1" : #2 ', $shop_fetched->{shop_id}, $shop_fetched->{number_of_orders},));
+ }else{
+ flash_later('info', t8('From shop #1 : #2 shoporders have been fetched.', $shop_fetched->{shop_id}, $shop_fetched->{number_of_orders},));
+ }
+ }
+ $self->redirect_to(controller => "ShopOrder", action => 'list');
+}
+
+sub action_list {
+ my ( $self ) = @_;
+
+ my %filter = ($::form->{filter} ? parse_filter($::form->{filter}) : query => [ transferred => 0, obsolete => 0 ]);
+ my $transferred = $::form->{filter}->{transferred_eq_ignore_empty} ne '' ? $::form->{filter}->{transferred_eq_ignore_empty} : '';
+ my $sort_by = $::form->{sort_by} ? $::form->{sort_by} : 'order_date';
+ $sort_by .=$::form->{sort_dir} ? ' DESC' : ' ASC';
+ my $shop_orders = SL::DB::Manager::ShopOrder->get_all( %filter, sort_by => $sort_by,
+ with_objects => ['shop_order_items', 'kivi_customer', 'shop'],
+ );
+
+ foreach my $shop_order(@{ $shop_orders }){
+
+ my $open_invoices = SL::DB::Manager::Invoice->get_all_count(
+ query => [customer_id => $shop_order->{kivi_customer_id},
+ paid => {lt_sql => 'amount'},
+ ],
+ );
+ $shop_order->{open_invoices} = $open_invoices;
+ }
+ $self->_setup_list_action_bar;
+ $self->render('shop_order/list',
+ title => t8('ShopOrders'),
+ SHOPORDERS => $shop_orders,
+ TOOK => $transferred,
+ );
+}
+
+sub action_show {
+ my ( $self ) = @_;
+ my $id = $::form->{id} || {};
+ my $shop_order = SL::DB::ShopOrder->new( id => $id )->load( with => ['kivi_customer'] );
+ die "can't find shoporder with id $id" unless $shop_order;
+
+ my $proposals = $shop_order->check_for_existing_customers;
+
+ $self->render('shop_order/show',
+ title => t8('Shoporder'),
+ IMPORT => $shop_order,
+ PROPOSALS => $proposals,
+ );
+
+}
+
+sub action_delete_order {
+ my ( $self ) = @_;
+
+ $self->shop_order->obsolete(1);
+ $self->shop_order->save;
+ $self->redirect_to(controller => "ShopOrder", action => 'list', filter => { 'transferred:eq_ignore_empty' => 0 });
+}
+
+sub action_undelete_order {
+ my ( $self ) = @_;
+
+ $self->shop_order->obsolete(0);
+ $self->shop_order->save;
+ $self->redirect_to(controller => "ShopOrder", action => 'show', id => $self->shop_order->id);
+}
+
+sub action_transfer {
+ my ( $self ) = @_;
+
+ my $customer = SL::DB::Manager::Customer->find_by(id => $::form->{customer});
+ die "Can't find customer" unless $customer;
+ my $employee = SL::DB::Manager::Employee->current;
+ die "Can't find employee" unless $employee;
+
+ die "Can't load shop_order form form->import_id" unless $self->shop_order;
+ my $order = $self->shop_order->convert_to_sales_order(customer => $customer, employee => $employee);
+
+ if ($order->{error}){
+ flash_later('error',@{$order->{errors}});
+ $self->redirect_to(controller => "ShopOrder", action => 'show', id => $self->shop_order->id);
+ }else{
+ $order->db->with_transaction( sub {
+ $order->calculate_prices_and_taxes;
+ $order->save;
+
+ my $snumbers = "ordernumber_" . $order->ordnumber;
+ SL::DB::History->new(
+ trans_id => $order->id,
+ snumbers => $snumbers,
+ employee_id => SL::DB::Manager::Employee->current->id,
+ addition => 'SAVED',
+ what_done => 'Shopimport -> Order',
+ )->save();
+ foreach my $item(@{ $order->orderitems }){
+ $item->parse_custom_variable_values->save;
+ $item->{custom_variables} = \@{ $item->cvars_by_config };
+ $item->save;
+ }
+
+ $self->shop_order->transferred(1);
+ $self->shop_order->transfer_date(DateTime->now_local);
+ $self->shop_order->save;
+ $self->shop_order->link_to_record($order);
+ }) || die $order->db->error;
+ $self->redirect_to(controller => "oe.pl", action => 'edit', type => 'sales_order', vc => 'customer', id => $order->id);
+ }
+}
+
+sub action_mass_transfer {
+ my ($self) = @_;
+ my @shop_orders = @{ $::form->{id} || [] };
+
+ my $job = SL::DB::BackgroundJob->new(
+ type => 'once',
+ active => 1,
+ package_name => 'ShopOrderMassTransfer',
+ )->set_data(
+ shop_order_record_ids => [ @shop_orders ],
+ num_order_created => 0,
+ num_delivery_order_created => 0,
+ status => SL::BackgroundJob::ShopOrderMassTransfer->WAITING_FOR_EXECUTION(),
+ conversion_errors => [ ],
+ )->update_next_run_at;
+
+ SL::System::TaskServer->new->wake_up;
+
+ my $html = $self->render('shop_order/_transfer_status', { output => 0 }, job => $job);
+
+ $self->js
+ ->html('#status_mass_transfer', $html)
+ ->run('kivi.ShopOrder.massTransferStarted')
+ ->render;
+}
+
+sub action_transfer_status {
+ my ($self) = @_;
+ my $job = SL::DB::BackgroundJob->new(id => $::form->{job_id})->load;
+ my $html = $self->render('shop_order/_transfer_status', { output => 0 }, job => $job);
+
+ $self->js->html('#status_mass_transfer', $html);
+ $self->js->run('kivi.ShopOrder.massTransferFinished') if $job->data_as_hash->{status} == SL::BackgroundJob::ShopOrderMassTransfer->DONE();
+ $self->js->render;
+
+}
+
+sub action_apply_customer {
+ my ( $self, %params ) = @_;
+ my $shop = SL::DB::Manager::Shop->find_by( id => $self->shop_order->shop_id );
+ my $what = $::form->{create_customer}; # new from billing, customer or delivery address
+ my %address = ( 'name' => $::form->{$what.'_name'},
+ 'department_1' => $::form->{$what.'_company'},
+ 'department_2' => $::form->{$what.'_department'},
+ 'street' => $::form->{$what.'_street'},
+ 'zipcode' => $::form->{$what.'_zipcode'},
+ 'city' => $::form->{$what.'_city'},
+ 'email' => $::form->{$what.'_email'},
+ 'country' => $::form->{$what.'_country'},
+ 'phone' => $::form->{$what.'_phone'},
+ 'email' => $::form->{$what.'_email'},
+ 'greeting' => $::form->{$what.'_greeting'},
+ 'taxincluded_checked' => $shop->pricetype eq "brutto" ? 1 : 0,
+ 'taxincluded' => $shop->pricetype eq "brutto" ? 1 : 0,
+ 'pricegroup_id' => (split '\/',$shop->price_source)[0] eq "pricegroup" ? (split '\/',$shop->price_source)[1] : undef,
+ 'taxzone_id' => $shop->taxzone_id,
+ 'currency' => $::instance_conf->get_currency_id,
+ #'payment_id' => 7345,# TODO hardcoded
+ );
+ my $customer;
+ if($::form->{cv_id}){
+ $customer = SL::DB::Customer->new(id => $::form->{cv_id})->load;
+ $customer->assign_attributes(%address);
+ $customer->save;
+ }else{
+ $customer = SL::DB::Customer->new(%address);
+ $customer->save;
+ }
+ my $snumbers = "customernumber_" . $customer->customernumber;
+ SL::DB::History->new(
+ trans_id => $customer->id,
+ snumbers => $snumbers,
+ employee_id => SL::DB::Manager::Employee->current->id,
+ addition => 'SAVED',
+ what_done => 'Shopimport',
+ )->save();
+
+ $self->redirect_to(action => 'show', id => $::form->{import_id});
+}
+
+sub setup {
+ my ($self) = @_;
+ $::auth->assert('shop_part_edit');
+ $::request->layout->use_javascript("${_}.js") for qw(kivi.ShopOrder);
+}
+
+sub check_auth {
+ $::auth->assert('shop_part_edit');
+}
+#
+# Helper
+#
+
+sub init_shop_order {
+ my ( $self ) = @_;
+ return SL::DB::ShopOrder->new(id => $::form->{import_id})->load if $::form->{import_id};
+}
+
+sub init_transferred {
+ [ { title => t8("all"), value => '' },
+ { title => t8("transferred"), value => 1 },
+ { title => t8("not transferred"), value => 0 }, ]
+}
+
+sub init_shops {
+ SL::DB::Shop->shops_dd;
+}
+
+sub _setup_list_action_bar {
+ my ($self) = @_;
+
+ for my $bar ($::request->layout->get('actionbar')) {
+ $bar->add(
+ action => [
+ t8('Search'),
+ submit => [ '#shoporders', { action => "ShopOrder/list" } ],
+ ],
+ link => [
+ t8('Shoporders'),
+ link => [ $self->url_for(action => 'get_orders') ],
+ tooltip => t8('New shop orders'),
+ ],
+ 'separator',
+ action => [
+ t8('Execute'),
+ call => [ 'kivi.ShopOrder.setup', id => "mass_transfer" ],
+ tooltip => t8('Transfer all marked'),
+ ],
+ );
+ }
+}
+
+1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Controller::ShopOrder - Shoporder CRUD Controller
+
+=head1 DESCRIPTION
+
+Fetches the shoporders and transfers them to orders.
+
+Relations for shoporders
+
+=over 2
+
+=item shop_order_items
+
+=item shops
+
+=item shop_parts
+
+=back
+
+=head1 URL ACTIONS
+
+=over 4
+
+=item C
+
+Fetches the shoporders with the shopconnector class
+
+=item C
+
+List the shoporders by different filters.
+From the List you can transfer shoporders into orders in batch where it is possible or one by one.
+
+=item C
+
+Shows one order. From here you can apply/change/select customer data and transfer the shoporder to an order.
+
+=item C
+
+Marks the shoporder as obsolete. It's for shoporders you don't want to transfer.
+
+=item C
+
+Marks the shoporder obsolete = false
+
+=item C
+
+Transfers one shoporder to an order.
+
+=item C
+
+Applys a new customer from the shoporder.
+
+=back
+
+=head1 TASKSERVER ACTIONS
+
+=over 4
+
+=item C
+
+Transfers more shoporders by backgroundjob called from the taskserver to orders.
+
+=item C
+
+Shows the backgroundjobdata for the popup status window
+
+=back
+
+=head1 SETUP
+
+=over 4
+
+=item C
+
+=back
+
+=head1 INITS
+
+=over 4
+
+=item C
+
+=item C
+
+Transferstatuses for the filter dropdown
+
+=item C
+
+Filter dropdown Shops
+
+=back
+
+=head1 TODO
+
+Implements different payments, pricesources and pricegroups. Till now not needed.
+
+=head1 BUGS
+
+None yet. :)
+
+=head1 AUTHOR
+
+W. Hahn Ewh@futureworldsearch.netE
+
+=cut
diff --git a/SL/DB/Helper/LinkedRecords.pm b/SL/DB/Helper/LinkedRecords.pm
index 5ad49257c..bf91e6a7b 100644
--- a/SL/DB/Helper/LinkedRecords.pm
+++ b/SL/DB/Helper/LinkedRecords.pm
@@ -312,6 +312,7 @@ sub sort_linked_records {
'SL::DB::PurchaseInvoice' => sub { $_[0]->invnumber },
'SL::DB::RequirementSpec' => sub { $_[0]->id },
'SL::DB::Letter' => sub { $_[0]->letternumber },
+ 'SL::DB::ShopOrder' => sub { $_[0]->shop_ordernumber },
UNKNOWN => '9999999999999999',
);
my $number_xtor = sub {
@@ -341,6 +342,7 @@ sub sort_linked_records {
'SL::DB::PurchaseInvoice' => 150,
'SL::DB::PurchaseInvoice' => 150,
'SL::DB::Letter' => 200,
+ 'SL::DB::ShopOrder' => 250,
UNKNOWN => 999,
);
my $score_xtor = sub {
diff --git a/js/kivi.ShopOrder.js b/js/kivi.ShopOrder.js
new file mode 100644
index 000000000..21ac4873c
--- /dev/null
+++ b/js/kivi.ShopOrder.js
@@ -0,0 +1,35 @@
+namespace('kivi.ShopOrder', function(ns) {
+ ns.massTransferInitialize = function() {
+ kivi.popup_dialog({
+ id: 'status_mass_transfer',
+ dialog: {
+ title: kivi.t8('Status Shoptransfer'),
+ }
+ });
+ };
+
+ ns.massTransferStarted = function() {
+ $('#status_mass_transfer').data('timerId', setInterval(function() {
+ $.get("controller.pl", {
+ action: 'ShopOrder/transfer_status',
+ job_id: $('#smt_job_id').val()
+ }, kivi.eval_json_result);
+ }, 5000));
+ };
+
+ ns.massTransferFinished = function() {
+ clearInterval($('#status_mass_transfer').data('timerId'));
+ $('.ui-dialog-titlebar button.ui-dialog-titlebar-close').prop('disabled', '')
+ };
+
+ ns.processClose = function() {
+ $('#status_mass_transfer').dialog('close');
+ window.location.href = 'controller.pl?filter.obsolete=0&filter.transferred=0&action=ShopOrder%2flist&db=shop_orders&sort_by=shop_ordernumber';
+ };
+
+ ns.setup = function() {
+ kivi.ShopOrder.massTransferInitialize();
+ kivi.submit_ajax_form('controller.pl?action=ShopOrder/mass_transfer','[name=shop_orders_list]');
+ };
+
+});
diff --git a/templates/webpages/shop_order/_filter.html b/templates/webpages/shop_order/_filter.html
new file mode 100644
index 000000000..b07d7f787
--- /dev/null
+++ b/templates/webpages/shop_order/_filter.html
@@ -0,0 +1,38 @@
+[%- USE T8 %]
+[%- USE L %]
+[%- USE LxERP %]
+[%- USE HTML %]
+
diff --git a/templates/webpages/shop_order/list.html b/templates/webpages/shop_order/list.html
new file mode 100644
index 000000000..1da0b17fa
--- /dev/null
+++ b/templates/webpages/shop_order/list.html
@@ -0,0 +1,204 @@
+[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%]
+[% USE Dumper %]
+
+[% L.stylesheet_tag('webshop') %]
+[%- INCLUDE 'common/flash.html' %]
+[% title %][% 'Number data sets' | $T8 %]: [% SHOPORDERS.size %]
+[%- PROCESS 'shop_order/_filter.html' filter=SELF.models.filtered.laundered %]
+
+
+
+
+
+
+ [%- INCLUDE 'shop_order/_transfer_status.html' %]
+
+
+
diff --git a/templates/webpages/shop_order/show.html b/templates/webpages/shop_order/show.html
new file mode 100644
index 000000000..e9c22e5ee
--- /dev/null
+++ b/templates/webpages/shop_order/show.html
@@ -0,0 +1,208 @@
+[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%]
+[% L.stylesheet_tag('webshop') %]
+[%- INCLUDE 'common/flash.html' %]
+[% title %]
+
+
+
+
+
+
+
+
+ [% 'Shop Headdata' | $T8 %] |
+
+ [% 'Shop Ordernumber' | $T8 %] | [% HTML.escape(IMPORT.shop_ordernumber) %] |
+ [% 'Shop Orderdate' | $T8 %] | [% HTML.escape(IMPORT.order_date.dmy('.')) _ ' ' _ HTML.escape(IMPORT.order_date.hms(':')) %] |
+ [% 'Shop Host' | $T8 %] | [% HTML.escape(IMPORT.host) %] |
+ [% 'Shop OrderIP' | $T8 %] | [% HTML.escape(IMPORT.remote_ip) %] |
+ [% 'Shop Ordernotes' | $T8 %] | [% HTML.escape(IMPORT.shop_customer_comment) %] |
+ [% 'Shop Orderamount' | $T8 %] | [% HTML.escape(IMPORT.amount_as_number) %] |
+ [% 'Shipping costs' | $T8 %] | [% HTML.escape(IMPORT.shipping_costs_as_number) %] |
+
+ |
+
+ [% IF IMPORT.obsolete %]
+ [% 'Shoporder deleted -- ' | $T8 %][% 'revert deleted' | $T8 %]
+ [% ELSE %]
+ [% UNLESS IMPORT.transferred %]
+ [% IF PROPOSALS %]
+
+ [% 'delete order' | $T8 %]
+ [% END # PROPOSALS %]
+ [% ELSE %]
+
+ [% 'Transferred' | $T8 %]
+
+
+
+ [% END %]
+ [% END %]
+ |
+
+
+
+
+
+
+ [% 'Position' | $T8 %] |
+ [% 'Partnumber' | $T8 %] |
+ [% 'Part Description' | $T8 %] |
+ [% 'Qty' | $T8 %] |
+ [% 'Price' | $T8 %] |
+ [% 'Extended' | $T8 %] |
+
+ [% FOREACH pos = IMPORT.shop_order_items %]
+
+ [% count() %] |
+ [% HTML.escape(pos.partnumber) %] |
+ [% HTML.escape(pos.description) %] |
+ [% pos.quantity_as_number%] |
+ [% pos.price_as_number%] |
+ [% SET extended = pos.price * pos.quantity %]
+ [% LxERP.format_amount(extended,2) %] |
+
+ [% END %]
+
+
+
+
+[% # L.dump(IMPORT) %]
--
2.20.1