Auftrags-Controller: weitere Links hierhin bei experimentellen Features
[kivitendo-erp.git] / SL / Controller / ShopOrder.pm
1 package SL::Controller::ShopOrder;
2
3 use strict;
4
5 use parent qw(SL::Controller::Base);
6
7 use SL::BackgroundJob::ShopOrderMassTransfer;
8 use SL::System::TaskServer;
9 use SL::DB::ShopOrder;
10 use SL::DB::ShopOrderItem;
11 use SL::DB::Shop;
12 use SL::DB::History;
13 use SL::DBUtils;
14 use SL::Shop;
15 use SL::Helper::Flash;
16 use SL::Locale::String;
17 use SL::Controller::Helper::ParseFilter;
18 use Rose::Object::MakeMethods::Generic
19 (
20   'scalar --get_set_init' => [ qw(shop_order shops transferred js) ],
21 );
22
23 __PACKAGE__->run_before('check_auth');
24 __PACKAGE__->run_before('setup');
25
26 use Data::Dumper;
27
28 sub action_get_orders {
29   my ( $self ) = @_;
30   my $orders_fetched;
31   my $new_orders;
32   my %new_order;
33   my $active_shops = SL::DB::Manager::Shop->get_all(query => [ obsolete => 0 ]);
34   foreach my $shop_config ( @{ $active_shops } ) {
35     my $shop = SL::Shop->new( config => $shop_config );
36     my $connect = $shop->check_connectivity;
37
38     if( !$connect->{success} ){
39       %new_order  = (
40         number_of_orders => $connect->{data}->{version},
41         shop_id          => $shop->config->description,
42         error            => 1,
43      );
44      $new_orders = \%new_order;
45     }else{
46       $new_orders = $shop->connector->get_new_orders;
47     }
48     push @{ $orders_fetched }, $new_orders ;
49   }
50
51   foreach my $shop_fetched(@{ $orders_fetched }) {
52     if($shop_fetched->{error}){
53       flash_later('error', t8('From shop "#1" :  #2 ', $shop_fetched->{shop_id}, $shop_fetched->{number_of_orders},));
54     }else{
55       flash_later('info', t8('From shop #1 :  #2 shoporders have been fetched.', $shop_fetched->{shop_id}, $shop_fetched->{number_of_orders},));
56     }
57   }
58   $self->redirect_to(controller => "ShopOrder", action => 'list');
59 }
60
61 sub action_list {
62   my ( $self ) = @_;
63
64   my %filter = ($::form->{filter} ? parse_filter($::form->{filter}) : query => [ transferred => 0, obsolete => 0 ]);
65   my $transferred = $::form->{filter}->{transferred_eq_ignore_empty} ne '' ? $::form->{filter}->{transferred_eq_ignore_empty} : '';
66   my $sort_by = $::form->{sort_by} ? $::form->{sort_by} : 'order_date';
67   $sort_by .=$::form->{sort_dir} ? ' DESC' : ' ASC';
68   my $shop_orders = SL::DB::Manager::ShopOrder->get_all( %filter, sort_by => $sort_by,
69                                                       with_objects => ['shop_order_items', 'kivi_customer', 'shop'],
70                                                     );
71
72   foreach my $shop_order(@{ $shop_orders }){
73
74     my $open_invoices = SL::DB::Manager::Invoice->get_all_count(
75       query => [customer_id => $shop_order->{kivi_customer_id},
76               paid => {lt_sql => 'amount'},
77       ],
78     );
79     $shop_order->{open_invoices} = $open_invoices;
80   }
81   $self->_setup_list_action_bar;
82   $self->render('shop_order/list',
83                 title       => t8('ShopOrders'),
84                 SHOPORDERS  => $shop_orders,
85                 TOOK        => $transferred,
86               );
87 }
88
89 sub action_show {
90   my ( $self ) = @_;
91   my $id = $::form->{id} || {};
92   my $shop_order = SL::DB::ShopOrder->new( id => $id )->load( with => ['kivi_customer'] );
93   die "can't find shoporder with id $id" unless $shop_order;
94
95   my $proposals = $shop_order->check_for_existing_customers;
96
97   $self->render('shop_order/show',
98                 title       => t8('Shoporder'),
99                 IMPORT      => $shop_order,
100                 PROPOSALS   => $proposals,
101               );
102
103 }
104
105 sub action_delete_order {
106   my ( $self ) = @_;
107
108   $self->shop_order->obsolete(1);
109   $self->shop_order->save;
110   $self->redirect_to(controller => "ShopOrder", action => 'list', filter => { 'transferred:eq_ignore_empty' => 0 });
111 }
112
113 sub action_undelete_order {
114   my ( $self ) = @_;
115
116   $self->shop_order->obsolete(0);
117   $self->shop_order->save;
118   $self->redirect_to(controller => "ShopOrder", action => 'show', id => $self->shop_order->id);
119 }
120
121 sub action_transfer {
122   my ( $self ) = @_;
123
124   my $customer = SL::DB::Manager::Customer->find_by(id => $::form->{customer});
125   die "Can't find customer" unless $customer;
126   my $employee = SL::DB::Manager::Employee->current;
127   die "Can't find employee" unless $employee;
128
129   die "Can't load shop_order form form->import_id" unless $self->shop_order;
130   my $order = $self->shop_order->convert_to_sales_order(customer => $customer, employee => $employee);
131
132   if ($order->{error}){
133     flash_later('error',@{$order->{errors}});
134     $self->redirect_to(controller => "ShopOrder", action => 'show', id => $self->shop_order->id);
135   }else{
136     $order->db->with_transaction( sub {
137       $order->calculate_prices_and_taxes;
138       $order->save;
139
140       my $snumbers = "ordernumber_" . $order->ordnumber;
141       SL::DB::History->new(
142                         trans_id    => $order->id,
143                         snumbers    => $snumbers,
144                         employee_id => SL::DB::Manager::Employee->current->id,
145                         addition    => 'SAVED',
146                         what_done   => 'Shopimport -> Order',
147                       )->save();
148       foreach my $item(@{ $order->orderitems }){
149         $item->parse_custom_variable_values->save;
150         $item->{custom_variables} = \@{ $item->cvars_by_config };
151         $item->save;
152       }
153
154       $self->shop_order->transferred(1);
155       $self->shop_order->transfer_date(DateTime->now_local);
156       $self->shop_order->save;
157       $self->shop_order->link_to_record($order);
158     }) || die $order->db->error;
159     my $order_controller = $::instance_conf->get_feature_experimental ? 'Order' :'oe.pl';
160     $self->redirect_to(controller => $order_controller, action => 'edit', type => 'sales_order', vc => 'customer', id => $order->id);
161   }
162 }
163
164 sub action_mass_transfer {
165   my ($self) = @_;
166   my @shop_orders =  @{ $::form->{id} || [] };
167
168   my $job                   = SL::DB::BackgroundJob->new(
169     type                    => 'once',
170     active                  => 1,
171     package_name            => 'ShopOrderMassTransfer',
172   )->set_data(
173      shop_order_record_ids       => [ @shop_orders ],
174      num_order_created           => 0,
175      num_delivery_order_created  => 0,
176      status                      => SL::BackgroundJob::ShopOrderMassTransfer->WAITING_FOR_EXECUTION(),
177      conversion_errors         => [ ],
178    )->update_next_run_at;
179
180    SL::System::TaskServer->new->wake_up;
181
182    my $html = $self->render('shop_order/_transfer_status', { output => 0 }, job => $job);
183
184    $self->js
185       ->html('#status_mass_transfer', $html)
186       ->run('kivi.ShopOrder.massTransferStarted')
187       ->render;
188 }
189
190 sub action_transfer_status {
191   my ($self)  = @_;
192   my $job     = SL::DB::BackgroundJob->new(id => $::form->{job_id})->load;
193   my $html    = $self->render('shop_order/_transfer_status', { output => 0 }, job => $job);
194
195   $self->js->html('#status_mass_transfer', $html);
196   $self->js->run('kivi.ShopOrder.massTransferFinished') if $job->data_as_hash->{status} == SL::BackgroundJob::ShopOrderMassTransfer->DONE();
197   $self->js->render;
198
199 }
200
201 sub action_apply_customer {
202   my ( $self, %params ) = @_;
203   my $shop = SL::DB::Manager::Shop->find_by( id => $self->shop_order->shop_id );
204   my $what = $::form->{create_customer}; # new from billing, customer or delivery address
205   my %address = ( 'name'                  => $::form->{$what.'_name'},
206                   'department_1'          => $::form->{$what.'_company'},
207                   'department_2'          => $::form->{$what.'_department'},
208                   'street'                => $::form->{$what.'_street'},
209                   'zipcode'               => $::form->{$what.'_zipcode'},
210                   'city'                  => $::form->{$what.'_city'},
211                   'email'                 => $::form->{$what.'_email'},
212                   'country'               => $::form->{$what.'_country'},
213                   'phone'                 => $::form->{$what.'_phone'},
214                   'email'                 => $::form->{$what.'_email'},
215                   'greeting'              => $::form->{$what.'_greeting'},
216                   'taxincluded_checked'   => $shop->pricetype eq "brutto" ? 1 : 0,
217                   'taxincluded'           => $shop->pricetype eq "brutto" ? 1 : 0,
218                   'pricegroup_id'         => (split '\/',$shop->price_source)[0] eq "pricegroup" ?  (split '\/',$shop->price_source)[1] : undef,
219                   'taxzone_id'            => $shop->taxzone_id,
220                   'currency'              => $::instance_conf->get_currency_id,
221                   #'payment_id'            => 7345,# TODO hardcoded
222                 );
223   my $customer;
224   if($::form->{cv_id}){
225     $customer = SL::DB::Customer->new(id => $::form->{cv_id})->load;
226     $customer->assign_attributes(%address);
227     $customer->save;
228   }else{
229     $customer = SL::DB::Customer->new(%address);
230     $customer->save;
231   }
232   my $snumbers = "customernumber_" . $customer->customernumber;
233   SL::DB::History->new(
234                     trans_id    => $customer->id,
235                     snumbers    => $snumbers,
236                     employee_id => SL::DB::Manager::Employee->current->id,
237                     addition    => 'SAVED',
238                     what_done   => 'Shopimport',
239                   )->save();
240
241   $self->redirect_to(action => 'show', id => $::form->{import_id});
242 }
243
244 sub setup {
245   my ($self) = @_;
246   $::auth->assert('shop_part_edit');
247   $::request->layout->use_javascript("${_}.js")  for qw(kivi.ShopOrder);
248 }
249
250 sub check_auth {
251   $::auth->assert('shop_part_edit');
252 }
253 #
254 # Helper
255 #
256
257 sub init_shop_order {
258   my ( $self ) = @_;
259   return SL::DB::ShopOrder->new(id => $::form->{import_id})->load if $::form->{import_id};
260 }
261
262 sub init_transferred {
263   [ { title => t8("all"),             value => '' },
264     { title => t8("transferred"),     value => 1  },
265     { title => t8("not transferred"), value => 0  }, ]
266 }
267
268 sub init_shops {
269   SL::DB::Shop->shops_dd;
270 }
271
272 sub _setup_list_action_bar {
273   my ($self) = @_;
274
275   for my $bar ($::request->layout->get('actionbar')) {
276     $bar->add(
277         action => [
278           t8('Search'),
279           submit    => [ '#shoporders', { action => "ShopOrder/list" } ],
280         ],
281          link => [
282           t8('Shoporders'),
283           link => [ $self->url_for(action => 'get_orders') ],
284           tooltip => t8('New shop orders'),
285         ],
286         'separator',
287         action => [
288           t8('Execute'),
289           call => [ 'kivi.ShopOrder.setup', id => "mass_transfer" ],
290           tooltip => t8('Transfer all marked'),
291         ],
292     );
293   }
294 }
295
296 1;
297
298 __END__
299
300 =encoding utf-8
301
302 =head1 NAME
303
304 SL::Controller::ShopOrder - Shoporder CRUD Controller
305
306 =head1 DESCRIPTION
307
308 Fetches the shoporders and transfers them to orders.
309
310 Relations for shoporders
311
312 =over 2
313
314 =item shop_order_items
315
316 =item shops
317
318 =item shop_parts
319
320 =back
321
322 =head1 URL ACTIONS
323
324 =over 4
325
326 =item C<action_get_orders>
327
328 Fetches the shoporders with the shopconnector class
329
330 =item C<action_list>
331
332 List the shoporders by different filters.
333 From the List you can transfer shoporders into orders in batch where it is possible or one by one.
334
335 =item C<action_show>
336
337 Shows one order. From here you can apply/change/select customer data and transfer the shoporder to an order.
338
339 =item C<action_delete>
340
341 Marks the shoporder as obsolete. It's for shoporders you don't want to transfer.
342
343 =item C<action_undelete>
344
345 Marks the shoporder obsolete = false
346
347 =item C<action_transfer>
348
349 Transfers one shoporder to an order.
350
351 =item C<action_apply_customer>
352
353 Applys a new customer from the shoporder.
354
355 =back
356
357 =head1 TASKSERVER ACTIONS
358
359 =over 4
360
361 =item C<action_mass_transfer>
362
363 Transfers more shoporders by backgroundjob called from the taskserver to orders.
364
365 =item C<action_transfer_status>
366
367 Shows the backgroundjobdata for the popup status window
368
369 =back
370
371 =head1 SETUP
372
373 =over 4
374
375 =item C<setup>
376
377 =back
378
379 =head1 INITS
380
381 =over 4
382
383 =item C<init_shoporder>
384
385 =item C<init_transfered>
386
387 Transferstatuses for the filter dropdown
388
389 =item C<init_shops>
390
391 Filter dropdown Shops
392
393 =back
394
395 =head1 TODO
396
397 Implements different payments, pricesources and pricegroups. Till now not needed.
398
399 =head1 BUGS
400
401 None yet. :)
402
403 =head1 AUTHOR
404
405 W. Hahn E<lt>wh@futureworldsearch.netE<gt>
406
407 =cut