Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 45c3c24a

Von Werner Hahn vor fast 7 Jahren hinzugefügt

  • ID 45c3c24a1f37a97b8fe2f73af72aad439b686381
  • Vorgänger 11d2ae57
  • Nachfolger 5a7d0c52

WebshopApi: ShopPart Controller

Unterschiede anzeigen:

SL/Controller/ShopPart.pm
1
package SL::Controller::ShopPart;
2

  
3
use strict;
4

  
5
use parent qw(SL::Controller::Base);
6

  
7
use SL::BackgroundJob::ShopPartMassUpload;
8
use SL::System::TaskServer;
9
use Data::Dumper;
10
use SL::Locale::String qw(t8);
11
use SL::DB::ShopPart;
12
use SL::DB::Shop;
13
use SL::DB::File;
14
use SL::DB::ShopImage;
15
use SL::DB::Default;
16
use SL::Helper::Flash;
17
use SL::Controller::Helper::ParseFilter;
18
use MIME::Base64;
19

  
20
use Rose::Object::MakeMethods::Generic
21
(
22
   scalar                 => [ qw(price_sources) ],
23
  'scalar --get_set_init' => [ qw(shop_part file shops) ],
24
);
25

  
26
__PACKAGE__->run_before('check_auth');
27
__PACKAGE__->run_before('add_javascripts', only => [ qw(edit_popup list_articles) ]);
28
__PACKAGE__->run_before('load_pricesources',    only => [ qw(create_or_edit_popup) ]);
29

  
30
#
31
# actions
32
#
33

  
34
sub action_create_or_edit_popup {
35
  my ($self) = @_;
36

  
37
  $self->render_shop_part_edit_dialog();
38
}
39

  
40
sub action_update_shop {
41
  my ($self, %params) = @_;
42

  
43
  my $shop_part = SL::DB::Manager::ShopPart->find_by(id => $::form->{shop_part_id});
44
  die unless $shop_part;
45

  
46
  require SL::Shop;
47
  my $shop = SL::Shop->new( config => $shop_part->shop );
48

  
49
  my $connect = $shop->check_connectivity;
50
  if($connect->{success}){
51
    my $return    = $shop->connector->update_part($self->shop_part, 'all');
52

  
53
    # the connector deals with parsing/result verification, just needs to return success or failure
54
    if ( $return == 1 ) {
55
      my $now = DateTime->now;
56
      my $attributes->{last_update} = $now;
57
      $self->shop_part->assign_attributes(%{ $attributes });
58
      $self->shop_part->save;
59
      $self->js->html('#shop_part_last_update_' . $shop_part->id, $now->to_kivitendo('precision' => 'minute'))
60
             ->flash('info', t8("Updated part [#1] in shop [#2] at #3", $shop_part->part->displayable_name, $shop_part->shop->description, $now->to_kivitendo('precision' => 'minute') ) )
61
             ->render;
62
    } else {
63
      $self->js->flash('error', t8('The shop part wasn\'t updated.'))->render;
64
    }
65
  }else{
66
    $self->js->flash('error', t8('The shop part wasn\'t updated. #1', $connect->{data}->{version}))->render;
67
  }
68

  
69

  
70
}
71

  
72
sub action_show_files {
73
  my ($self) = @_;
74

  
75
  my $images = SL::DB::Manager::ShopImage->get_all( where => [ 'files.object_id' => $::form->{id}, ], with_objects => 'file', sort_by => 'position' );
76

  
77
  $self->render('shop_part/_list_images', { header => 0 }, IMAGES => $images);
78
}
79

  
80
sub action_ajax_delete_file {
81
  my ( $self ) = @_;
82
  $self->file->delete;
83

  
84
  $self->js
85
    ->run('kivi.ShopPart.show_images',$self->file->object_id)
86
    ->render();
87
}
88

  
89
sub action_get_categories {
90
  my ($self) = @_;
91

  
92
  require SL::Shop;
93
  my $shop = SL::Shop->new( config => $self->shop_part->shop );
94

  
95
  my $connect = $shop->check_connectivity;
96
  if($connect->{success}){
97
    my $categories = $shop->connector->get_categories;
98

  
99
    $self->js
100
      ->run(
101
        'kivi.ShopPart.shop_part_dialog',
102
        t8('Shopcategories'),
103
        $self->render('shop_part/categories', { output => 0 }, CATEGORIES => $categories )
104
      )
105
      ->reinit_widgets;
106
      $self->js->render;
107
  }else{
108
    $self->js->flash('error', t8('Can\'t connect to shop. #1', $connect->{data}->{version}))->render;
109
  }
110

  
111
}
112

  
113
sub action_show_price_n_pricesource {
114
  my ($self) = @_;
115

  
116
  my ( $price, $price_src_str ) = $self->get_price_n_pricesource($::form->{pricesource});
117

  
118
  if( $price_src_str eq 'sellprice'){
119
    $price_src_str = t8('Sellprice');
120
  }elsif( $price_src_str eq 'listprice'){
121
    $price_src_str = t8('Listprice');
122
  }elsif( $price_src_str eq 'lastcost'){
123
    $price_src_str = t8('Lastcost');
124
  }
125
  $self->js->html('#price_' . $self->shop_part->id, $::form->format_amount(\%::myconfig,$price,2))
126
           ->html('#active_price_source_' . $self->shop_part->id, $price_src_str)
127
           ->render;
128
}
129

  
130
sub action_show_stock {
131
  my ($self) = @_;
132
  my ( $stock_local, $stock_onlineshop, $active_online );
133

  
134
  require SL::Shop;
135
  my $shop = SL::Shop->new( config => $self->shop_part->shop );
136

  
137
  if($self->shop_part->last_update) {
138
    my $shop_article = $shop->connector->get_article($self->shop_part->part->partnumber);
139
    $stock_onlineshop = $shop_article->{data}->{mainDetail}->{inStock};
140
    $active_online = $shop_article->{data}->{active};
141
  }
142

  
143
  $stock_local = $self->shop_part->part->onhand;
144

  
145
  $self->js->html('#stock_' . $self->shop_part->id, $::form->format_amount(\%::myconfig,$stock_local,0)."/".$::form->format_amount(\%::myconfig,$stock_onlineshop,0))
146
           ->html('#toogle_' . $self->shop_part->id,$active_online)
147
           ->render;
148
}
149

  
150
sub action_get_n_write_categories {
151
  my ($self) = @_;
152

  
153
  my @shop_parts =  @{ $::form->{shop_parts_ids} || [] };
154
  foreach my $part(@shop_parts){
155

  
156
    my $shop_part = SL::DB::Manager::ShopPart->get_all( where => [id => $part], with_objects => ['part', 'shop'])->[0];
157
    require SL::DB::Shop;
158
    my $shop = SL::Shop->new( config => $shop_part->shop );
159
    my $online_article = $shop->connector->get_article($shop_part->part->partnumber);
160
    my $online_cat = $online_article->{data}->{categories};
161
    my @cat = ();
162
    for(keys %$online_cat){
163
      my @cattmp;
164
      push @cattmp,$online_cat->{$_}->{id};
165
      push @cattmp,$online_cat->{$_}->{name};
166
      push @cat,\@cattmp;
167
    }
168
    my $attributes->{shop_category} = \@cat;
169
    my $active->{active} = $online_article->{data}->{active};
170
    $shop_part->assign_attributes(%{$attributes}, %{$active});
171
    $shop_part->save;
172
  }
173
  $self->redirect_to( action => 'list_articles' );
174
}
175

  
176
sub action_save_categories {
177
  my ($self) = @_;
178

  
179
  my @categories =  @{ $::form->{categories} || [] };
180

  
181
    my @cat = ();
182
    foreach my $cat ( @categories) {
183
      my @cattmp;
184
      push( @cattmp,$cat );
185
      push( @cattmp,$::form->{"cat_id_${cat}"} );
186
      push( @cat,\@cattmp );
187
    }
188

  
189
  my $categories->{shop_category} = \@cat;
190

  
191
  my $params = delete($::form->{shop_part}) || { };
192

  
193
  $self->shop_part->assign_attributes(%{ $params });
194
  $self->shop_part->assign_attributes(%{ $categories });
195

  
196
  $self->shop_part->save;
197

  
198
  flash('info', t8('The categories has been saved.'));
199

  
200
  $self->js->run('kivi.ShopPart.close_dialog')
201
           ->flash('info', t8("Updated categories"))
202
           ->render;
203
}
204

  
205
sub action_reorder {
206
  my ($self) = @_;
207
  require SL::DB::ShopImage;
208
  SL::DB::ShopImage->reorder_list(@{ $::form->{image_id} || [] });
209

  
210
  $self->render(\'', { type => 'json' });
211
}
212

  
213
sub action_list_articles {
214
  my ($self) = @_;
215

  
216
  my %filter      = ($::form->{filter} ? parse_filter($::form->{filter}) : query => [ 'shop.obsolete' => 0 ]);
217
  my $sort_by     = $::form->{sort_by} ? $::form->{sort_by} : 'part.partnumber';
218
  $sort_by .=$::form->{sort_dir} ? ' DESC' : ' ASC';
219

  
220
  my $articles = SL::DB::Manager::ShopPart->get_all( %filter ,with_objects => [ 'part','shop' ], sort_by => $sort_by );
221

  
222
  foreach my $article (@{ $articles}) {
223
    my $images = SL::DB::Manager::ShopImage->get_all_count( where => [ 'files.object_id' => $article->part->id, ], with_objects => 'file', sort_by => 'position' );
224
    $article->{images} = $images;
225
  }
226

  
227
  $self->render('shop_part/_list_articles', title => t8('Webshops articles'), SHOP_PARTS => $articles);
228
}
229

  
230
sub action_upload_status {
231
  my ($self) = @_;
232
  my $job     = SL::DB::BackgroundJob->new(id => $::form->{job_id})->load;
233
  my $html    = $self->render('shop_part/_upload_status', { output => 0 }, job => $job);
234

  
235
  $self->js->html('#status_mass_upload', $html);
236
  $self->js->run('kivi.ShopPart.massUploadFinished') if $job->data_as_hash->{status} == SL::BackgroundJob::ShopPartMassUpload->DONE();
237
  $self->js->render;
238
}
239

  
240
sub action_mass_upload {
241
  my ($self) = @_;
242

  
243
  my @shop_parts =  @{ $::form->{shop_parts_ids} || [] };
244

  
245
  my $job = SL::DB::BackgroundJob->new(
246
        type                 => 'once',
247
        active               => 1,
248
        package_name         => 'ShopPartMassUpload',
249
        )->set_data(
250
        shop_part_record_ids => [ @shop_parts ],
251
        todo                 => $::form->{upload_todo},
252
        status               => SL::BackgroundJob::ShopPartMassUpload->WAITING_FOR_EXECUTION(),
253
        conversation         => [ ],
254
        num_uploaded         => 0,
255
   )->update_next_run_at;
256

  
257
   SL::System::TaskServer->new->wake_up;
258

  
259
   my $html = $self->render('shop_part/_upload_status', { output => 0 }, job => $job);
260

  
261
   $self->js
262
      ->html('#status_mass_upload', $html)
263
      ->run('kivi.ShopPart.massUploadStarted')
264
      ->render;
265
}
266

  
267
sub action_update {
268
  my ($self) = @_;
269

  
270
  $self->create_or_update;
271
}
272

  
273
sub render_shop_part_edit_dialog {
274
  my ($self) = @_;
275

  
276
  $self->js
277
    ->run(
278
      'kivi.ShopPart.shop_part_dialog',
279
      t8('Shop part'),
280
      $self->render('shop_part/edit', { output => 0 })
281
    )
282
    ->reinit_widgets;
283

  
284
  $self->js->render;
285
}
286

  
287
sub create_or_update {
288
  my ($self) = @_;
289

  
290
  my $is_new = !$self->shop_part->id;
291

  
292
  my $params = delete($::form->{shop_part}) || { };
293

  
294
  $self->shop_part->assign_attributes(%{ $params });
295

  
296
  $self->shop_part->save;
297

  
298
  my ( $price, $price_src_str ) = $self->get_price_n_pricesource($self->shop_part->active_price_source);
299
if(!$is_new){
300
  flash('info', $is_new ? t8('The shop part has been created.') : t8('The shop part has been saved.'));
301
  $self->js->html('#shop_part_description_' . $self->shop_part->id, $self->shop_part->shop_description)
302
           ->html('#shop_part_active_' . $self->shop_part->id, $self->shop_part->active)
303
           ->html('#price_' . $self->shop_part->id, $::form->format_amount(\%::myconfig,$price,2))
304
           ->html('#active_price_source_' . $self->shop_part->id, $price_src_str)
305
           ->run('kivi.ShopPart.close_dialog')
306
           ->flash('info', t8("Updated shop part"))
307
           ->render;
308
         }else{
309
    $self->redirect_to(controller => 'Part', action => 'edit', 'part.id' => $self->shop_part->part_id);
310
  }
311
}
312

  
313
#
314
# internal stuff
315
#
316
sub add_javascripts  {
317
  $::request->{layout}->add_javascripts(qw(kivi.ShopPart.js));
318
}
319

  
320
sub load_pricesources {
321
  my ($self) = @_;
322

  
323
  my $pricesources;
324
  push( @{ $pricesources } , { id => "master_data/sellprice", name => t8("Master Data")." - ".t8("Sellprice") },
325
                             { id => "master_data/listprice", name => t8("Master Data")." - ".t8("Listprice") },
326
                             { id => "master_data/lastcost",  name => t8("Master Data")." - ".t8("Lastcost") }
327
                             );
328
  my $pricegroups = SL::DB::Manager::Pricegroup->get_all;
329
  foreach my $pg ( @$pricegroups ) {
330
    push( @{ $pricesources } , { id => "pricegroup/".$pg->id, name => t8("Pricegroup") . " - " . $pg->pricegroup} );
331
  };
332

  
333
  $self->price_sources( $pricesources );
334
}
335

  
336
sub get_price_n_pricesource {
337
  my ($self,$pricesource) = @_;
338

  
339
  my ( $price_src_str, $price_src_id ) = split(/\//,$pricesource);
340

  
341
  require SL::DB::Pricegroup;
342
  require SL::DB::Part;
343
  my $price;
344
  if ($price_src_str eq "master_data") {
345
    my $part       = SL::DB::Manager::Part->find_by( id => $self->shop_part->part_id );
346
    $price         = $part->$price_src_id;
347
    $price_src_str = $price_src_id;
348
    }else{
349
    my $part       = SL::DB::Manager::Part->get_all( where => [id => $self->shop_part->part_id, 'prices.'.pricegroup_id => $price_src_id], with_objects => ['prices'],limit => 1)->[0];
350
    #my $part       = SL::DB::Manager::Part->find_by( id => $self->shop_part->part_id, 'prices.'.pricegroup_id => $price_src_id );
351
    my $pricegrp   = SL::DB::Manager::Pricegroup->find_by( id => $price_src_id )->pricegroup;
352
    $price         = $part->prices->[0]->price;
353
    $price_src_str = $pricegrp;
354
  }
355
  return($price,$price_src_str);
356
}
357

  
358
sub check_auth {
359
  $::auth->assert('shop_part_edit');
360
}
361

  
362
sub init_shop_part {
363
  if ($::form->{shop_part_id}) {
364
    SL::DB::Manager::ShopPart->find_by(id => $::form->{shop_part_id});
365
  } else {
366
    SL::DB::ShopPart->new(shop_id => $::form->{shop_id}, part_id => $::form->{part_id});
367
  };
368
}
369

  
370
sub init_file {
371
  my $file = $::form->{id} ? SL::DB::File->new(id => $::form->{id})->load : SL::DB::File->new;
372
  return $file;
373
}
374

  
375
sub init_shops {
376
  SL::DB::Shop->shops_dd;
377
}
378

  
379
1;
380

  
381
__END__
382

  
383
=encoding utf-8
384

  
385

  
386
=head1 NAME
387

  
388
SL::Controller::ShopPart - Controller for managing ShopParts
389

  
390
=head1 SYNOPSIS
391

  
392
ShopParts are configured in a tab of the corresponding part.
393

  
394
=head1 ACTIONS
395

  
396
=over 4
397

  
398
=item C<action_update_shop>
399

  
400
To be called from the "Update" button of the shoppart, for manually syncing/upload one part with its shop. Calls some ClientJS functions to modifiy original page.
401

  
402
=item C<action_show_files>
403

  
404

  
405

  
406
=item C<action_ajax_delete_file>
407

  
408

  
409

  
410
=item C<action_get_categories>
411

  
412

  
413

  
414
=item C<action_show_price_n_pricesource>
415

  
416

  
417

  
418
=item C<action_show_stock>
419

  
420

  
421

  
422
=item C<action_get_n_write_categories>
423

  
424
Can be used to sync the categories of a shoppart with the categories from online.
425

  
426
=item C<action_save_categories>
427

  
428
The ShopwareConnector works with the CategoryID @categories[x][0] in others/new Connectors it must be tested
429
Each assigned categorie is saved with id,categorie_name an multidimensional array and could be expanded with categoriepath or what is needed
430

  
431
=item C<action_reorder>
432

  
433

  
434

  
435
=item C<action_upload_status>
436

  
437

  
438

  
439
=item C<action_mass_upload>
440

  
441

  
442

  
443
=item C<action_update>
444

  
445

  
446

  
447
=item C<create_or_update>
448

  
449

  
450

  
451
=item C<render_shop_part_edit_dialog>
452

  
453
when self->shop_part is called in template, it will be an existing shop_part with id,
454
or a new shop_part with only part_id and shop_id set
455

  
456
=item C<add_javascripts>
457

  
458

  
459
=item C<load_pricesources>
460

  
461
the price sources to use for the article: sellprice, lastcost,
462
listprice, or one of the pricegroups. It overwrites the default pricesource from the shopconfig.
463
TODO: implement valid pricerules for the article
464

  
465
=item C<get_price_n_pricesource>
466

  
467

  
468
=item C<check_auth>
469

  
470

  
471
=item C<init_shop_part>
472

  
473

  
474
=item C<init_file>
475

  
476

  
477
=item C<init_shops>
478

  
479
data for drop down filter options
480

  
481
=back
482

  
483
=head1 TODO
484

  
485
CheckAuth
486
Pricesrules, pricessources aren't fully implemented yet.
487

  
488
=head1 AUTHORS
489

  
490
G. Richardson E<lt>information@kivitendo-premium.deE<gt>
491
W. Hahn E<lt>wh@futureworldsearch.netE<gt>
492

  
493
=cut
js/kivi.ShopPart.js
1
namespace('kivi.ShopPart', function(ns) {
2
  var $dialog;
3

  
4
  ns.shop_part_dialog = function(title, html) {
5
    var id            = 'jqueryui_popup_dialog';
6
    var dialog_params = {
7
      id:     id,
8
      width:  800,
9
      height: 500,
10
      modal:  true,
11
      close: function(event, ui) { $dialog.remove(); },
12
    };
13

  
14
    $('#' + id).remove();
15

  
16
    $dialog = $('<div style="display:none" id="' + id + '"></div>').appendTo('body');
17
    $dialog.attr('title', title);
18
    $dialog.html(html);
19
    $dialog.dialog(dialog_params);
20

  
21
    $('.cancel').click(ns.close_dialog);
22

  
23
    return true;
24
  };
25

  
26
  ns.close_dialog = function() {
27
    $dialog.dialog("close");
28
  }
29

  
30
  ns.save_shop_part = function(shop_part_id) {
31
    var form = $('form').serializeArray();
32
    form.push( { name: 'action', value: 'ShopPart/update' }
33
             , { name: 'shop_part_id',  value: shop_part_id }
34
    );
35

  
36
    $.post('controller.pl', form, function(data) {
37
      kivi.eval_json_result(data);
38
    });
39
  }
40

  
41
  ns.add_shop_part = function(part_id,shop_id) {
42
    var form = $('form').serializeArray();
43
    form.push( { name: 'action', value: 'ShopPart/update' }
44
    );
45
    $.post('controller.pl', form, function(data) {
46
      kivi.eval_json_result(data);
47
    });
48
  }
49

  
50
  ns.edit_shop_part = function(shop_part_id) {
51
    $.post('controller.pl', { action: 'ShopPart/create_or_edit_popup', shop_part_id: shop_part_id }, function(data) {
52
      kivi.eval_json_result(data);
53
    });
54
  }
55

  
56
  ns.create_shop_part = function(part_id, shop_id) {
57
    $.post('controller.pl', { action: 'ShopPart/create_or_edit_popup', part_id: part_id, shop_id: shop_id }, function(data) {
58
      kivi.eval_json_result(data);
59
    });
60
  }
61

  
62
  ns.get_all_categories = function(shop_part_id) {
63
    $.post('controller.pl', { action: 'ShopPart/get_categories', shop_part_id: shop_part_id }, function(data) {
64
      kivi.eval_json_result(data);
65
    });
66
  }
67

  
68
  ns.save_categories = function(shop_part_id, shop_id) {
69
    var form = $('form').serializeArray();
70
    form.push( { name: 'action', value: 'ShopPart/save_categories' }
71
             , { name: 'shop_id', value: shop_id }
72
             , { name: 'shop_part_id', value: shop_part_id }
73
    );
74

  
75
    $.post('controller.pl', form, function(data) {
76
      kivi.eval_json_result(data);
77
    });
78
  }
79

  
80
  ns.update_shop_part = function(shop_part_id) {
81
    $.post('controller.pl', { action: 'ShopPart/update_shop', shop_part_id: shop_part_id }, function(data) {
82
      kivi.eval_json_result(data);
83
    });
84
  }
85

  
86
  ns.update_discount_source = function(row, source, discount_str) {
87
    $('#active_discount_source_' + row).val(source);
88
    if (discount_str) $('#discount_' + row).val(discount_str);
89
    $('#update_button').click();
90
  }
91

  
92
  ns.show_images = function(id) {
93
    var url = 'controller.pl?action=ShopPart/show_files&id='+id;
94
    $('#shop_images').load(url);
95
  }
96

  
97
  ns.update_price_n_price_source = function(shop_part_id,price_source) {
98
    $.post('controller.pl', { action: 'ShopPart/show_price_n_pricesource', shop_part_id: shop_part_id, pricesource: price_source }, function(data) {
99
      kivi.eval_json_result(data);
100
    });
101
  }
102

  
103
  ns.update_stock = function(shop_part_id) {
104
    $.post('controller.pl', { action: 'ShopPart/show_stock', shop_part_id: shop_part_id }, function(data) {
105
      kivi.eval_json_result(data);
106
    });
107
  }
108

  
109
  ns.massUploadInitialize = function() {
110
    kivi.popup_dialog({
111
      id: 'status_mass_upload',
112
      dialog: {
113
        title: kivi.t8('Status Shopupload')
114
      }
115
    });
116
  };
117

  
118
  ns.massUploadStarted = function() {
119
    $('#status_mass_upload').data('timerId', setInterval(function() {
120
      $.get("controller.pl", {
121
        action: 'ShopPart/upload_status',
122
        job_id: $('#smu_job_id').val()
123
      }, kivi.eval_json_result);
124
    }, 5000));
125
  };
126

  
127
  ns.massUploadFinished = function() {
128
    clearInterval($('#status_mass_upload').data('timerId'));
129
    $('.ui-dialog-titlebar button.ui-dialog-titlebar-close').prop('disabled', '')
130
  };
131

  
132
  ns.imageUpload = function(id,type,filetype,upload_title,gl) {
133
    kivi.popup_dialog({ url:     'controller.pl',
134
                        data:    { action: 'File/ajax_upload',
135
                                   file_type:   filetype,
136
                                   object_type: type,
137
                                   object_id:   id,
138
                                   is_global:   gl
139
                                 },
140
                        id:     'files_upload',
141
                        dialog: { title: kivi.t8('File upload'), width: 650, height: 240 } });
142
    return true;
143
  }
144

  
145

  
146
  ns.setup = function() {
147
    kivi.ShopPart.massUploadInitialize();
148
    kivi.submit_ajax_form('controller.pl?action=ShopPart/mass_upload','[name=shop_parts]');
149
  };
150

  
151
});
templates/webpages/shop_part/_filter.html
1
[%- USE T8 %]
2
[%- USE L %]
3
[%- USE LxERP %]
4
[%- USE HTML %]
5
<form action='controller.pl' metdod='post' id="shop_part_filter">
6
  [% L.hidden_tag('filter.shop.obsolete', 0) %]
7
 <table id='filter_table'>
8

  
9
    <tr>
10
     <td>[% 'Shop' | $T8 %]</td>
11
     <td>[% L.select_tag('filter.shop_id:eq_ignore_empty', SELF.shops, value_key = 'value', title_key = 'title', default=0) %]</td>
12
    </tr>
13
    <tr>
14
     <td>[% 'Part marked as "Shop article"' %]
15
     <td>[% L.yes_no_tag('filter.part.shop', FORM.filter.part.shop, default='1', with_empty=1, empty_title='---') %]</td>
16
    </tr>
17

  
18
 </table>
19

  
20
 <p>
21
  <a href='#' onClick='javascript:$("#filter_table input").val("");$("#filter_table input[type=checkbox]").prop("checked", 0);'>[% 'Reset' | $T8 %]</a>
22
  <br>
23
 </p>
24
 <p>
25
   [% L.hidden_tag('action', 'ShopPart/dispatch') %]
26
   [% L.submit_tag('action_list_articles',LxERP.t8('renew')) %]
27
 </p>
28
</form>
templates/webpages/shop_part/_list_articles.html
1
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%]
2
[% USE Dumper %]
3

  
4

  
5
<h1>[% title %]</h1>
6
[%- PROCESS 'shop_part/_filter.html' filter=SELF.models.filtered.laundered %]
7
<hr>
8
<form method="post" action="controller.pl" name="shop_parts" id="shopparts">
9
  <div class="data_count">[% 'Number of Data: ' | $T8 %] [% SHOP_PARTS.size %]</div>
10
  <table id="shoplist" width="100%" >
11
    <thead>
12
      <tr class="listheading">
13
      <th>[% L.checkbox_tag('check_all') %]</th>
14
    <th>[% IF FORM.sort_by == 'shop.description' %]
15
      <a href ="controller.pl?action=ShopPart/list_articles&sort_by=shop.description&sort_dir=[% 1 - FORM.sort_dir %]" class="sort_link">
16
        [% 'Shop Host/Connector' | $T8 %][% IF FORM.sort_dir == 0 %]<img border="0" src="image/down.png">[% ELSE %]<img border="0" src="image/up.png">[% END %]</a>
17
    [% ELSE %]
18
      <a href ="controller.pl?action=ShopPart/list_articles&sort_by=shop.description&sort_dir=0" class="sort_link">
19
        [% 'Shop Host/Connector' | $T8 %]</a>
20
    [% END %]
21
    </th>
22
    <th>[% IF FORM.sort_by == 'part.partnumber' %]
23
      <a href ="controller.pl?action=ShopPart/list_articles&sort_by=part.partnumber&sort_dir=[% 1 - FORM.sort_dir %]" class="sort_link">
24
        [% 'Partnumber' | $T8 %][% IF FORM.sort_dir == 0 %]<img border="0" src="image/down.png">[% ELSE %]<img border="0" src="image/up.png">[% END %]</a>
25
    [% ELSE %]
26
      <a href ="controller.pl?action=ShopPart/list_articles&sort_by=part.partnumber&sort_dir=0" class="sort_link">
27
        [% 'Partnumber' | $T8 %]</a>
28
    [% END %]
29
    </th>
30
    <th>[% IF FORM.sort_by == 'part.description' %]
31
      <a href ="controller.pl?action=ShopPart/list_articles&sort_by=part.description&sort_dir=[% 1 - FORM.sort_dir %]" class="sort_link">
32
        [% 'Description' | $T8 %][% IF FORM.sort_dir == 0 %]<img border="0" src="image/down.png">[% ELSE %]<img border="0" src="image/up.png">[% END %]</a>
33
    [% ELSE %]
34
      <a href ="controller.pl?action=ShopPart/list_articles&sort_by=part.description&sort_dir=0" class="sort_link">
35
        [% 'Description' | $T8 %]</a>
36
    [% END %]
37
    </th>
38
      <th>[% 'Info' | $T8 %]</th>
39
      <th>[% 'Active' | $T8 %]</th>
40
      <th>[% 'Price source' | $T8 %]</th>
41
      <th>[% 'Price' | $T8 %]</th>
42
    <th>[% IF FORM.sort_by == 'part.onhand' %]
43
      <a href ="controller.pl?action=ShopPart/list_articles&sort_by=part.onhand&sort_dir=[% 1 - FORM.sort_dir %]" class="sort_link">
44
        [% 'Stock Local/Shop' | $T8 %][% IF FORM.sort_dir == 0 %]<img border="0" src="image/down.png">[% ELSE %]<img border="0" src="image/up.png">[% END %]</a>
45
    [% ELSE %]
46
      <a href ="controller.pl?action=ShopPart/list_articles&sort_by=part.onhand&sort_dir=0" class="sort_link">
47
        [% 'Stock Local/Shop' | $T8 %]</a>
48
    [% END %]
49
    </th>
50
      <th>[% 'Last update' | $T8 %]</th>
51
      <th>[% 'Images' | $T8 %]</th>
52
    <th>[% IF FORM.sort_by == 'part.partsgroup_id' %]
53
      <a href ="controller.pl?action=ShopPart/list_articles&sort_by=part.partsgroup_id&sort_dir=[% 1 - FORM.sort_dir %]" class="sort_link">
54
        [% 'Category' %][% IF FORM.sort_dir == 0 %]<img border="0" src="image/down.png">[% ELSE %]<img border="0" src="image/up.png">[% END %]</a>
55
    [% ELSE %]
56
      <a href ="controller.pl?action=ShopPart/list_articles&sort_by=part.partsgroup_id&sort_dir=0" class="sort_link">
57
        [% 'Category' | $T8 %]</a>
58
    [% END %]
59
    </th>
60
    </tr>
61
  </thead>
62
  [%- FOREACH shop_part = SHOP_PARTS %]
63
  [%- # IF shop_part.shop.obsolete %]
64
    <tr class="listrow">
65
      <td>[% L.checkbox_tag('shop_parts_ids[]', checked=0, value=shop_part.id) %]</td>
66
      <td>[% HTML.escape( shop_part.shop.description ) %]/[% HTML.escape( shop_part.shop.connector ) %]</td>
67
      <td>[% HTML.escape( shop_part.part.partnumber ) %]</td>
68
      <td><a href="controller.pl?part.id=[% shop_part.part.id %]&action=Part/edit&callback=[% HTML.url('controller.pl?action=ShopPart/list_articles') %]#shop_variables">[% HTML.escape( shop_part.part.description ) %]</a></td>
69
      <td>
70
        [% IF shop_part.shop_description %]
71
          [% 'Info' | $T8 %]
72
        [% ELSE %]
73
          [% 'No Shopdescription' | $T8 %]
74
        [% END %]
75
      </td>
76
      <td style="vertical-align:middle;text-align:center;">
77
        [% IF shop_part.active %]
78
        <div id="toogle_[% shop_part.id %]" style="background-image:url(image/gruener_punkt.gif);background-repeat:no-repeat;witdh:15px;height:15px;">&nbsp; </div>
79
        [% ELSE %]
80
        <div id="toogle_[% shop_part.id %]" style="background-image:url(image/roter_punkt.gif);background-repeat:no-repeat;witdh:15px;height:15px;">&nbsp; </div>
81
        [% END %]
82
      </td>
83
      <td>[% L.html_tag('span',LxERP.t8(), id => 'active_price_source_' _ shop_part.id) %] </td>
84
      <td>[% L.html_tag('span','Price', id => 'price_' _ shop_part.id) %]</td>
85
      <td>[% L.html_tag('span','Stock', id => 'stock_' _ shop_part.id) %]</td>
86
      <td>[% L.html_tag('span', shop_part.last_update.to_kivitendo('precision' => 'minute'), id => 'shop_part_last_update_' _ shop_part.id ) %]</td>
87
      <td>
88
        [% IF shop_part.images %]
89
          [% shop_part.images %]
90
        [% ELSE %]
91
          [% 'No Shopimages' | $T8 %]
92
        [% END %]
93
      </td>
94
      <td>
95
        [% IF shop_part.shop_category %]
96
          [% IF shop_part.shop_category.1.size > 1%]
97
            [% FOREACH cat = shop_part.shop_category %]
98
              [% HTML.escape(cat.1) %]<br>
99
            [% END %]
100
          [% ELSE %]
101
            [% HTML.escape(shop_part.shop_category.1) %]<br>
102
          [% END %]
103
        [% END %]
104
      </td>
105
    <script type="text/javascript">
106
      $(function() {
107
         kivi.ShopPart.update_price_n_price_source([% shop_part.id %],'[% shop_part.active_price_source %]');
108
         kivi.ShopPart.update_stock([% shop_part.id %]);
109
      });
110
    </script>
111
    </tr>
112
    [%- # END %]
113
  [%- END %]
114
</table>
115

  
116
  <hr>
117
  <div>
118
    [% L.radio_button_tag('upload_todo', value='all', label= LxERP.t8('All Data')) %]
119
    [% L.radio_button_tag('upload_todo', value='price', label= LxERP.t8('Only Price')) %]
120
    [% L.radio_button_tag('upload_todo', value='stock', label= LxERP.t8('Only Stock')) %]
121
    [% L.radio_button_tag('upload_todo', value='price_stock', checked=1, label= LxERP.t8('Price and Stock')) %]
122
    [% L.button_tag("kivi.ShopPart.setup();", LxERP.t8("Upload all marked"), id="mass_transfer") %]
123
  </div>
124
  <div id="status_mass_upload" style="display: none;">
125
    [%- INCLUDE 'shop_part/_upload_status.html' %]
126
  </div>
127
</form>
128
<hr>
129
<script type="text/javascript">
130
<!--
131

  
132
$(function() {
133
  $('#check_all').checkall('INPUT[name^="shop_parts_ids"]');
134
});
135
-->
136
</script>
templates/webpages/shop_part/_list_images.html
1
[%- USE HTML %][%- USE L -%][%- USE P -%][%- USE LxERP -%]
2
[%- USE T8 %][% USE Base64 %]
3
[%- USE Dumper %]
4
<table width="100%" id="images_list">
5
  <thead>
6
    <tr class="listheading">
7
      <th width="10px"><img src="image/updown.png" alt="[%- LxERP.t8('reorder item') %]" class="dragdrop"></th>
8
      <th width="70px"></th>
9
      <th>[% 'Title' | $T8 %]</th>
10
      <th>[% 'Description' | $T8 %]</th>
11
      <th>[% 'Filename' | $T8 %]</th>
12
      <th>[% 'Orig. Size w/h' | $T8 %]</th>
13
      <th>[% 'Action' | $T8 %]</th>
14
    </tr>
15
  </thead>
16
  <tbody>
17
   [%-  FOREACH img = IMAGES %]
18
   [% # Dumper.dump_html(img) %]
19
    <tr class="listrow" id="image_id_[%  img.id %]">
20
      <td><img src="image/updown.png" alt="[%- LxERP.t8('reorder item') %]" class="dragdrop"></td>
21
      <td width="70px"><img src="data:[%  img.thumbnail_content_type %];base64,[%  img.thumbnail_content.encode_base64 %]" alt="[%  img.file.title %]"></td>
22
      <td>[% HTML.escape(img.file.title) %]</td>
23
      <td>[% HTML.escape(img.file.description) %]</td>
24
      <td>[% HTML.escape(img.file.file_name) %]</td>
25
      <td>[% HTML.escape(img.org_file_width) _  ' x ' _ HTML.escape(img.org_file_height) %]</td>
26
      <td>[% L.button_tag("kivi.File.delete_file(" _ img.file_id _ ", 'ShopPart/ajax_delete_file')", LxERP.t8('Delete'), confirm=LxERP.t8("Are you sure?")) %]</td>
27
    </tr>
28
   [%  END %]
29
  </tbody>
30
</table>
31

  
32
[% L.sortable_element('#images_list tbody', url=SELF.url_for(action='reorder'), with='image_id') %]
33
<p>
34
[% L.button_tag("kivi.ShopPart.imageUpload(" _ FORM.id _ ",'shop_image','image', '',0);", LxERP.t8('File upload') ) %]
35
</p>
templates/webpages/shop_part/_transfer_status.html
1
[%- USE LxERP -%][%- USE L -%][%- USE HTML -%]
2
[%- USE Dumper -%]
3
[% SET data = job.data_as_hash %]
4

  
5
<h2>[% LxERP.t8("Watch status") %]</h2>
6

  
7
[% L.hidden_tag('', job.id, id="smu_job_id") %]
8

  
9
JOBID: [% job.id %] <p>
10
 [% LxERP.t8("This status output will be refreshed every five seconds.") %]
11
</p>
12
<p>
13
 <table>
14
  <tr>
15
   <th valign="top" align="left">[% LxERP.t8("Current status:") %]</th>
16
   <td valign="top">
17
    [% IF !data.status %]
18
     [% LxERP.t8("waiting for job to be started") %]
19
    [% ELSIF data.status == 1 %]
20
     [% LxERP.t8("Uploading Data") %]
21
    [% ELSE %]
22
     [% LxERP.t8("Done.") %]
23
    [% END %]
24
   </td>
25
  </tr>
26
  <tr>
27
   <th valign="top" align="left">[% LxERP.t8("Number of data uploaded:") %]</th>
28
   <td valign="top">[% IF data.status > 0 %][% HTML.escape(data.num_uploaded) %] / [% HTML.escape(data.record_ids.size) %][% ELSE %]–[% END %]</td>
29
  </tr>
30

  
31
  <tr>
32
   <th valign="top" align="left">[% LxERP.t8("Conversion:") %]</th>
33
   <td valign="top">
34
[% IF !data.status %]
35
36
    <table>
37
     <tr class="listheader">
38
      <th>[% LxERP.t8("Part") %]</th>
39
      <th>[% LxERP.t8("Partnumber") %]</th>
40
      <th>[% LxERP.t8("Message") %]</th>
41
     </tr>
42

  
43
 [% FOREACH message = data.conversion %]
44
     <tr>
45
      <td valign="top">[% IF error.id %][% L.link(SELF.url_for(controller='ShopOrder', action='show', id=error.id), HTML.escape(error.number), target="_blank") %][% ELSE %]–[% END %]</td>
46
      <td valign="top">[% HTML.escape(message.message) %]</td>
47
     </tr>
48
 [% END %]
49
    </table>
50
 [% END %]
51
 </table>
52
</p>
templates/webpages/shop_part/_upload_status.html
1
[%- USE LxERP -%][%- USE L -%][%- USE HTML -%]
2
[%- USE Dumper -%]
3
[% SET data = job.data_as_hash %]
4

  
5
<h2>[% LxERP.t8("Watch status") %]</h2>
6

  
7
[% L.hidden_tag('', job.id, id="smu_job_id") %]
8

  
9
JOBID: [% job.id %] <p>
10
 [% LxERP.t8("This status output will be refreshed every five seconds.") %]
11
</p>
12
<p>
13
 <table>
14
  <tr>
15
   <th valign="top" align="left">[% LxERP.t8("Current status:") %]</th>
16
   <td valign="top">
17
    [% IF !data.status %]
18
     [% LxERP.t8("waiting for job to be started") %]
19
    [% ELSIF data.status == 1 %]
20
     [% LxERP.t8("Uploading Data") %]
21
    [% ELSE %]
22
     [% LxERP.t8("Done.") %]
23
    [% END %]
24
   </td>
25
  </tr>
26
  <tr>
27
   <th valign="top" align="left">[% LxERP.t8("Number of data uploaded:") %]</th>
28
   <td valign="top">[% IF data.status > 0 %][% HTML.escape(data.num_uploaded) %] / [% HTML.escape(data.shop_part_record_ids.size) %][% ELSE %]–[% END %]</td>
29
  </tr>
30

  
31
  <tr>
32
   <th valign="top" align="left">[% LxERP.t8("Conversion:") %]</th>
33
   <td valign="top">
34
35
    <table>
36
     <tr class="listheader">
37
      <th>[% LxERP.t8("Part") %]</th>
38
      <th>[% LxERP.t8("Partnumber") %]</th>
39
      <th>[% LxERP.t8("Message") %]</th>
40
     </tr>
41

  
42
 [% FOREACH message = data.conversion %]
43
     <tr>
44
      <td valign="top">[% HTML.escape(message.id) %]</td>
45
      <td valign="top">[% HTML.escape(message.number) %]</td>
46
      <td valign="top">[% HTML.escape(message.message) %]</td>
47
     </tr>
48
 [% END %]
49
    </table>
50
 </table>
51
</p>
templates/webpages/shop_part/categories.html
1
[%- USE HTML %]
2
[%- USE T8 %]
3
[%- USE L -%]
4
[%- USE P -%]
5
[%- USE LxERP -%]
6
[%- USE Dumper -%]
7

  
8
[%  LxERP.t8("Part") %]: [% HTML.escape(SELF.shop_part.part.displayable_name) %]<br>
9
[%  LxERP.t8("Shop") %]: [% HTML.escape(SELF.shop_part.shop.description) %]
10
<br>
11
[% # Dumper.dump_html(SELF.shop_part.shop_category) %]
12
<br>
13
[% # Dumper.dump_html(CATEGORIES) %]
14

  
15
<form action="controller.pl" method="post">
16
  [% BLOCK recurse %]
17
    [% # path = '' %]<!-- TODO: Pfad wg neuer Kategorie im Shop anlegen -->
18
    [% FOREACH obj = data %]
19
      <ul>
20
        <li>
21
        [% checked = '' %]
22
        [% # path = path _ obj.name %]
23
        [% # test = path.split('\|') %]
24
        [% # Dumper.dump_html(SELF.shop_part.shop_category) %]
25
        [% IF SELF.shop_part.shop_category.1.grep(obj.name).size %]
26
          [% checked = 'checked' %]
27
        [% ELSE %]
28
          [% FOREACH cat_row = SELF.shop_part.shop_category %]
29
            [% IF cat_row.1.grep(obj.name).size %]
30
              [% checked = 'checked' %]
31
            [% END %]
32
          [% END %]
33
        [% END %]
34
          [% L.checkbox_tag('categories[]',value=obj.id, checked=checked) %][% HTML.escape(obj.name) %][% L.hidden_tag("cat_id_" _ obj.id, obj.name) %]</li>
35
        [% IF obj.childrenCount >= 1 %]
36
          [% # path = path _ '|' %]
37
          [% INCLUDE recurse data=obj.children %]
38
        [% END %]
39
      </ul>
40
    [% END %]
41
  [% END %]
42
  <div><h2>[% LxERP.t8("Shopcategories") %]</h2>
43
      [% FOREACH row = CATEGORIES %]
44
<!-- TODO: Is still hardcoded 'Root' is shopware specified -->
45
        [% IF row.name == 'Root' %]
46
          [% IF row.childrenCount >= 1 %]
47
            [% path = '' %]
48
            [% INCLUDE recurse data=row.children path=path %]
49
          [% END %]
50
        [% END %]
51
      [% END %]
52
  </div>
53
    [% L.button_tag("kivi.ShopPart.save_categories(" _ SELF.shop_part.id _", " _ SELF.shop_part.shop.id _")", LxERP.t8("Save"))  %]</td>
54
</form>
55

  
templates/webpages/shop_part/edit.html
1
[%- USE HTML %]
2
[%- USE T8 %]
3
[%- USE L -%]
4
[%- USE P -%]
5
[%- USE LxERP -%]
6
[%- USE Dumper -%]
7

  
8
<p>
9
[% LxERP.t8("Part") %]: [% HTML.escape(SELF.shop_part.part.displayable_name) %]<br>
10
[% LxERP.t8("Shop") %]: [% HTML.escape(SELF.shop_part.shop.description) %]
11
<p>
12
[% # Dumper.dump_html(SELF) %]
13
<form action="controller.pl" method="post">
14
  <div>
15
    [% IF SELF.shop_part.id %]
16
    [%- L.hidden_tag("shop_part.id", SELF.shop_part.id) %]
17
    [%- L.hidden_tag("shop_part.shop_id", SELF.shop_part.shop_id) %]
18
    [% ELSE %]
19
    [%- L.hidden_tag("shop_part.shop_id", FORM.shop_id) %]
20
    [%- L.hidden_tag("shop_part.part_id", FORM.part_id) %]
21
    [% END %]
22

  
23
    <table>
24
    <tr>
25
     <td>[% LxERP.t8("Description") %]</td>
26
     <td colspan="3">[% L.textarea_tag('shop_part.shop_description', SELF.shop_part.shop_description, wrap="soft", style="width: 350px; height: 150px", class="texteditor") %]</td>
27
    </tr>
28
    <tr>
29
     <td>[% LxERP.t8("Active") %]</td>
30
     <td>[% L.yes_no_tag("shop_part.active", SELF.shop_part.active, default = "yes") %]</td>
31
     <td>[% LxERP.t8("Date") %]</td>
32
     <td>[% L.date_tag("shop_part.show_date", SELF.shop_part.show_date) %]</td>
33
    </tr>
34
    <tr>
35
      <td>[% 'Price Source' | $T8 %]</th>
36
      [% IF SELF.shop_part.active_price_source %]
37
        [% SET price_source = SELF.shop_part.active_price_source %]
38
      [% ELSE %]
39
        [% SET price_source = SELF.shop_part.shop.price_source %]
40
      [% END %]
41
      <td>[% L.select_tag('shop_part.active_price_source', SELF.price_sources, value_key = 'id', title_key = 'name', with_empty = 0, default = price_source, default_value_key='id' ) %]</td>
42
     <td>[% LxERP.t8("Front page") %]</td>
43
     <td>[% L.yes_no_tag('shop_part.front_page', SELF.shop_part.front_page) %]</td>
44
    </tr>
45
    <tr>
46
     <td>[% LxERP.t8("Sort order") %]</td>
47
     <td>[% L.input_tag("shop_part.sortorder", SELF.shop_part.sortorder, size=2) %]</td>
48
     <td>[% LxERP.t8("Meta tag title") %]</td>
49
     <td>[% L.input_tag("shop_part.metatag_title", SELF.shop_part.metatag_title, size=12) %]</td>
50
    </tr>
51
    <tr>
52
     <td>[% LxERP.t8("Meta tag keywords") %]</td>
53
     <td>[% L.input_tag("shop_part.metatag_keywords", SELF.shop_part.metatag_keywords, size=22) %]</td>
54
     <td>[% LxERP.t8("Meta tag description") %]</td>
55
     <td>[% L.textarea_tag("shop_part.metatag_description", SELF.shop_part.metatag_description, rows=4) %]</td>
56
    </tr>
57
    </table>
58
    [% # L.dump(SELF.shop_part) %]
59

  
60
    [% IF SELF.shop_part.id %]
61
    [% L.button_tag("kivi.ShopPart.save_shop_part(" _ SELF.shop_part.id _ ")", LxERP.t8("Save"))  %]</td>
62
    [% ELSE %]
63
    [% L.button_tag("kivi.ShopPart.add_shop_part(" _ FORM.part_id _", " _ FORM.shop_id _")", LxERP.t8("Save"))  %]</td>
64
    [% END %]
65
    [% # L.button_tag("kivi.ShopPart.update_partnumber()", LxERP.t8("Update Partnumber"))  %]</td>
66

  
67
    [% # L.hidden_tag("action", "ShopPart/dispatch") %]
68
    [% # L.submit_tag('action_update', LxERP.t8('Save')) %]
69

  
70

  
71
  </div>
72
</form>
73

  
74

  
75

  
76
[%- IF SELF.shop_part.part.image && INSTANCE_CONF.get_parts_show_image %]
77
         <a href="[% SELF.shop_part.part.image | html %]" target="_blank"><img style="[% INSTANCE_CONF.get_parts_image_css %]" src="[% SELF.shop_part.part.image | html %]"/></a>
78
[%- END %]
79

  
80
[% # SELF.shop_part.shop_description %]
81
[% # L.dump(SELF.shop_part) %]

Auch abrufbar als: Unified diff