Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision ce1ca334

Von Werner Hahn vor mehr als 7 Jahren hinzugefügt

  • ID ce1ca33441d60e07f4107c626c2396baf428d911
  • Vorgänger 55685c0d
  • Nachfolger 13e28674

Shopmodul: Artikel überarbeitet
Dinge aus Connector ausgelagert, die auch für andere Conectoren
gültigkeit haben
Output des Backgroundjob MassUpload überarbeitet
POD
Typo

Unterschiede anzeigen:

SL/BackgroundJob/ShopPartMassUpload.pm
1 1
package SL::BackgroundJob::ShopPartMassUpload;
2
#ShopPartMassUpload
2

  
3 3
use strict;
4 4
use warnings;
5 5

  
......
7 7

  
8 8
use SL::DBUtils;
9 9
use SL::DB::ShopPart;
10
      use SL::Shop;
10
use SL::Shop;
11 11

  
12 12
use constant WAITING_FOR_EXECUTION        => 0;
13 13
use constant UPLOAD_TO_WEBSHOP            => 1;
......
15 15

  
16 16
# Data format:
17 17
# my $data                  = {
18
#     shop_part_record_ids       => [ 603, 604, 605],
19
#     num_order_created           => 0,
20
#     orders_ids                  => [1,2,3]
21
#     conversation_errors         => [ { id => 603 , item => 2, message => "Out of stock"}, ],
18
#     shop_part_record_ids         => [ 603, 604, 605 ],
19
#     todo                         => $::form->{upload_todo},
20
#     status                       => SL::BackgroundJob::ShopPartMassUpload->WAITING_FOR_EXECUTION(),
21
#     num_uploaded                 => 0,
22
#     conversation                 => [ { id => 603 , number => 2, message => "Ok" or $@ }, ],
22 23
# };
23 24

  
24 25
sub update_webarticles {
......
28 29
  my $db      = $job_obj->db;
29 30

  
30 31
  $job_obj->set_data(UPLOAD_TO_WEBSHOP())->save;
31

  
32
  my $num_uploaded = 0;
32 33
  foreach my $shop_part_id (@{ $job_obj->data_as_hash->{shop_part_record_ids} }) {
33 34
    my $data  = $job_obj->data_as_hash;
34 35
    eval {
35 36
      my $shop_part = SL::DB::Manager::ShopPart->find_by(id => $shop_part_id);
36 37
      unless($shop_part){
37
        push @{ $data->{conversion_errors} }, { id => $shop_part_id, number => '', message => 'Shoppart not found' };
38
        push @{ $data->{conversion} }, { id => $shop_part_id, number => '', message => 'Shoppart not found' };
38 39
      }
39 40

  
40 41
      my $shop = SL::Shop->new( config => $shop_part->shop );
41 42

  
42
      my $part_hash = $shop_part->part->as_tree;
43
      require SL::JSON;
44

  
45
      my $json      = SL::JSON::to_json($part_hash);
46
      my $return    = $shop->connector->update_part($shop_part, $json, $data->{todo});
43
      my $return    = $shop->connector->update_part($shop_part, $data->{todo});
47 44
      if ( $return == 1 ) {
48 45
        my $now = DateTime->now;
49 46
        my $attributes->{last_update} = $now;
50 47
        $shop_part->assign_attributes(%{ $attributes });
51 48
        $shop_part->save;
49
        $data->{num_uploaded} = $num_uploaded++;
50
        push @{ $data->{conversion} }, { id => $shop_part_id, number => $shop_part->part->partnumber, message => 'uploaded' };
52 51
      }else{
53
      push @{ $data->{conversion_errors} }, { id => $shop_part_id, number => '', message => $return };
52
      push @{ $data->{conversion} }, { id => $shop_part_id, number => $shop_part->part->partnumber, message => $return };
54 53
      }
55 54
      1;
56 55
    } or do {
57
      push @{ $data->{conversion_errors} }, { id => $shop_part_id, number => '', message => $@ };
56
      push @{ $data->{conversion} }, { id => $shop_part_id, number => '', message => $@ };
58 57
    };
59 58

  
60 59
    $job_obj->update_attributes(data_as_hash => $data);
SL/Controller/ShopPart.pm
44 44
  require SL::Shop;
45 45
  my $shop = SL::Shop->new( config => $shop_part->shop );
46 46

  
47
  my $part_hash = $shop_part->part->as_tree;
48
  my $json      = SL::JSON::to_json($part_hash);
49
  my $return    = $shop->connector->update_part($self->shop_part, $json,'all');
47
  my $return    = $shop->connector->update_part($self->shop_part, 'all');
50 48

  
51 49
  # the connector deals with parsing/result verification, just needs to return success or failure
52 50
  if ( $return == 1 ) {
......
99 97

  
100 98
}
101 99

  
102
sub action_update {
103
  my ($self) = @_;
104

  
105
  $self->create_or_update;
106
}
107

  
108 100
sub action_show_price_n_pricesource {
109 101
  my ($self) = @_;
110 102

  
......
148 140
    my $online_cat = $online_article->{data}->{categories};
149 141
    my @cat = ();
150 142
    for(keys %$online_cat){
151
    # The ShopwareConnector works with the CategoryID @categories[x][0] in others/new Connectors it must be tested
152
    # Each assigned categorie is saved with id,categorie_name an multidimensional array and could be expanded with categoriepath or what is needed
153 143
      my @cattmp;
154
      push( @cattmp,$online_cat->{$_}->{id} );
155
      push( @cattmp,$online_cat->{$_}->{name} );
156
      push( @cat,\@cattmp );
144
      push @cattmp,$online_cat->{$_}->{id};
145
      push @cattmp,$online_cat->{$_}->{name};
146
      push @cat,\@cattmp;
157 147
    }
158 148
    my $attributes->{shop_category} = \@cat;
159 149
    my $active->{active} = $online_article->{data}->{active};
......
163 153
  $self->redirect_to( action => 'list_articles' );
164 154
}
165 155

  
166
sub create_or_update {
167
  my ($self) = @_;
168

  
169
  my $is_new = !$self->shop_part->id;
170

  
171
  # in edit.html all variables start with shop_part
172
  my $params = delete($::form->{shop_part}) || { };
173

  
174
  $self->shop_part->assign_attributes(%{ $params });
175

  
176
  $self->shop_part->save;
177

  
178
  my ( $price, $price_src_str ) = $self->get_price_n_pricesource($self->shop_part->active_price_source);
179

  
180
  flash('info', $is_new ? t8('The shop part has been created.') : t8('The shop part has been saved.'));
181
  $self->js->html('#shop_part_description_' . $self->shop_part->id, $self->shop_part->shop_description)
182
           ->html('#shop_part_active_' . $self->shop_part->id, $self->shop_part->active)
183
           ->html('#price_' . $self->shop_part->id, $::form->format_amount(\%::myconfig,$price,2))
184
           ->html('#active_price_source_' . $self->shop_part->id, $price_src_str)
185
           ->run('kivi.ShopPart.close_dialog')
186
           ->flash('info', t8("Updated shop part"))
187
           ->render;
188
}
189

  
190
sub render_shop_part_edit_dialog {
191
  my ($self) = @_;
192

  
193
  # when self->shop_part is called in template, it will be an existing shop_part with id,
194
  # or a new shop_part with only part_id and shop_id set
195
  $self->js
196
    ->run(
197
      'kivi.ShopPart.shop_part_dialog',
198
      t8('Shop part'),
199
      $self->render('shop_part/edit', { output => 0 })
200
    )
201
    ->reinit_widgets;
202

  
203
  $self->js->render;
204
}
205

  
206 156
sub action_save_categories {
207 157
  my ($self) = @_;
208 158

  
209 159
  my @categories =  @{ $::form->{categories} || [] };
210 160

  
211
    # The ShopwareConnector works with the CategoryID @categories[x][0] in others/new Connectors it must be tested
212
    # Each assigned categorie is saved with id,categorie_name an multidimensional array and could be expanded with categoriepath or what is needed
213 161
    my @cat = ();
214 162
    foreach my $cat ( @categories) {
215 163
      my @cattmp;
......
275 223

  
276 224
  my @shop_parts =  @{ $::form->{shop_parts_ids} || [] };
277 225

  
278
  my $job                   = SL::DB::BackgroundJob->new(
279
    type                    => 'once',
280
    active                  => 1,
281
    package_name            => 'ShopPartMassUpload',
282
  )->set_data(
283
     shop_part_record_ids         => [ @shop_parts ],
284
     todo                         => $::form->{upload_todo},
285
     status                       => SL::BackgroundJob::ShopPartMassUpload->WAITING_FOR_EXECUTION(),
286
     conversation_errors          => [ ],
226
  my $job = SL::DB::BackgroundJob->new(
227
        type                 => 'once',
228
        active               => 1,
229
        package_name         => 'ShopPartMassUpload',
230
        )->set_data(
231
        shop_part_record_ids => [ @shop_parts ],
232
        todo                 => $::form->{upload_todo},
233
        status               => SL::BackgroundJob::ShopPartMassUpload->WAITING_FOR_EXECUTION(),
234
        conversation         => [ ],
235
        num_uploaded         => 0,
287 236
   )->update_next_run_at;
288 237

  
289 238
   SL::System::TaskServer->new->wake_up;
290 239

  
291
   my $html = $self->render('shop_part/_transfer_status', { output => 0 }, job => $job);
240
   my $html = $self->render('shop_part/_upload_status', { output => 0 }, job => $job);
292 241

  
293 242
   $self->js
294 243
      ->html('#status_mass_upload', $html)
......
296 245
      ->render;
297 246
}
298 247

  
248
sub action_update {
249
  my ($self) = @_;
250

  
251
  $self->create_or_update;
252
}
253

  
254
sub render_shop_part_edit_dialog {
255
  my ($self) = @_;
256

  
257
  $self->js
258
    ->run(
259
      'kivi.ShopPart.shop_part_dialog',
260
      t8('Shop part'),
261
      $self->render('shop_part/edit', { output => 0 })
262
    )
263
    ->reinit_widgets;
264

  
265
  $self->js->render;
266
}
267

  
268
sub create_or_update {
269
  my ($self) = @_;
270

  
271
  my $is_new = !$self->shop_part->id;
272

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

  
275
  $self->shop_part->assign_attributes(%{ $params });
276

  
277
  $self->shop_part->save;
278

  
279
  my ( $price, $price_src_str ) = $self->get_price_n_pricesource($self->shop_part->active_price_source);
280

  
281
  flash('info', $is_new ? t8('The shop part has been created.') : t8('The shop part has been saved.'));
282
  $self->js->html('#shop_part_description_' . $self->shop_part->id, $self->shop_part->shop_description)
283
           ->html('#shop_part_active_' . $self->shop_part->id, $self->shop_part->active)
284
           ->html('#price_' . $self->shop_part->id, $::form->format_amount(\%::myconfig,$price,2))
285
           ->html('#active_price_source_' . $self->shop_part->id, $price_src_str)
286
           ->run('kivi.ShopPart.close_dialog')
287
           ->flash('info', t8("Updated shop part"))
288
           ->render;
289
}
290

  
299 291
#
300 292
# internal stuff
301 293
#
......
306 298
sub load_pricesources {
307 299
  my ($self) = @_;
308 300

  
309
  # the price sources to use for the article: sellprice, lastcost,
310
  # listprice, or one of the pricegroups. It overwrites the default pricesource from the shopconfig.
311
  # TODO: implement valid pricerules for the article
312 301
  my $pricesources;
313 302
  push( @{ $pricesources } , { id => "master_data/sellprice", name => t8("Master Data")." - ".t8("Sellprice") },
314 303
                             { id => "master_data/listprice", name => t8("Master Data")." - ".t8("Listprice") },
315
                             { id => "master_data/lastcost",  name => t8("Master Data")." - ".t8("Lastcost") }
304
                             { id => "master_data/lastcost",  nam => t8("Master Data")." - ".t8("Lastcost") }
316 305
                             );
317 306
  my $pricegroups = SL::DB::Manager::Pricegroup->get_all;
318 307
  foreach my $pg ( @$pricegroups ) {
......
331 320
  require SL::DB::Part;
332 321
  my $price;
333 322
  if ($price_src_str eq "master_data") {
334
    my $part       = SL::DB::Manager::Part->get_all( where => [id => $self->shop_part->part_id], with_objects => ['prices'],limit => 1)->[0];
323
    my $part       = SL::DB::Manager::Part->find_by( id => $self->shop_part->part_id );
335 324
    $price         = $part->$price_src_id;
336 325
    $price_src_str = $price_src_id;
337 326
    }else{
338 327
    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];
328
    #my $part       = SL::DB::Manager::Part->find_by( id => $self->shop_part->part_id, 'prices.'.pricegroup_id => $price_src_id );
339 329
    my $pricegrp   = SL::DB::Manager::Pricegroup->find_by( id => $price_src_id )->pricegroup;
340 330
    $price         = $part->prices->[0]->price;
341 331
    $price_src_str = $pricegrp;
......
362 352
}
363 353

  
364 354
sub init_shops {
365
  # data for drop down filter options
366 355
  require SL::DB::Shop;
367 356
  my @shops_dd = [ { title => t8("all") ,   value =>'' } ];
368 357
  my $shops = SL::DB::Mangager::Shop->get_all( where => [ obsolete => 0 ] );
369 358
  my @tmp = map { { title => $_->{description}, value => $_->{id} } } @{ $shops } ;
370 359
  return @shops_dd;
371

  
372
}
373

  
374
sub init_producers {
375
  # data for drop down filter options
376
  my @producers_dd = [ { title => t8("all") ,   value =>'' } ];
377
  return @producers_dd;
378

  
379 360
}
380 361

  
381 362
1;
......
387 368

  
388 369
=head1 NAME
389 370

  
390
  SL::Controller::ShopPart - Controller for managing ShopParts
371
SL::Controller::ShopPart - Controller for managing ShopParts
391 372

  
392 373
=head1 SYNOPSIS
393 374

  
394
  ShopParts are configured in a tab of the corresponding part.
395

  
396
=head1 FUNCTIONS
375
ShopParts are configured in a tab of the corresponding part.
397 376

  
377
=head1 ACTIONS
398 378

  
399 379
=over 4
400 380

  
401 381
=item C<action_update_shop>
402 382

  
403
  To be called from the "Update" button of the shoppart, for manually syncing/upload one part with its shop. Generates a  Calls some ClientJS functions to modifiy original page.
383
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.
384

  
385
=item C<action_show_files>
386

  
387

  
388

  
389
=item C<action_ajax_delete_file>
390

  
391

  
392

  
393
=item C<action_get_categories>
394

  
395

  
396

  
397
=item C<action_show_price_n_pricesource>
398

  
399

  
400

  
401
=item C<action_show_stock>
402

  
403

  
404 404

  
405 405
=item C<action_get_n_write_categories>
406 406

  
407
  Can be used to sync the categories of a shoppart with the categories from online.
407
Can be used to sync the categories of a shoppart with the categories from online.
408

  
409
=item C<action_save_categories>
410

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

  
414
=item C<action_reorder>
415

  
416

  
417

  
418
=item C<action_upload_status>
419

  
420

  
421

  
422
=item C<action_mass_upload>
423

  
424

  
425

  
426
=item C<action_update>
427

  
428

  
429

  
430
=item C<create_or_update>
431

  
432

  
433

  
434
=item C<render_shop_part_edit_dialog>
435

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

  
439
=item C<add_javascripts>
440

  
441

  
442
=item C<load_pricesources>
443

  
444
the price sources to use for the article: sellprice, lastcost,
445
listprice, or one of the pricegroups. It overwrites the default pricesource from the shopconfig.
446
TODO: implement valid pricerules for the article
447

  
448
=item C<get_price_n_pricesource>
449

  
450

  
451
=item C<check_auth>
452

  
453

  
454
=item C<init_shop_part>
455

  
456

  
457
=item C<init_file>
458

  
459

  
460
=item C<init_shops>
461

  
462
data for drop down filter options
408 463

  
409 464
=back
410 465

  
411 466
=head1 TODO
412 467

  
413
  Pricesrules, pricessources aren't fully implemented yet.
468
CheckAuth
469
Pricesrules, pricessources aren't fully implemented yet.
414 470

  
415 471
=head1 AUTHORS
416 472

  
417
  G. Richardson E<lt>information@kivitendo-premium.deE<gt>
418
  W. Hahn E<lt>wh@futureworldsearch.netE<gt>
473
G. Richardson E<lt>information@kivitendo-premium.deE<gt>
474
W. Hahn E<lt>wh@futureworldsearch.netE<gt>
419 475

  
420 476
=cut
SL/DB/ShopPart.pm
5 5

  
6 6
use strict;
7 7

  
8
use SL::DBUtils;
8 9
use SL::DB::MetaSetup::ShopPart;
9 10
use SL::DB::Manager::ShopPart;
10 11
use SL::DB::Helper::AttrHTML;
......
13 14
__PACKAGE__->meta->initialize;
14 15
__PACKAGE__->attr_html('shop_description');
15 16

  
17
sub get_tax_and_price {
18
  my ( $self ) = @_;
19

  
20
  require SL::DB::Part;
21
  my $tax_n_price;
22
  my ( $price_src_str, $price_src_id ) = split(/\//,$self->active_price_source);
23
  my $price;
24
  my $part;
25
  if ($price_src_str eq "master_data") {
26
    $part = SL::DB::Manager::Part->find_by( id => $self->part_id );
27
    $price = $part->$price_src_id;
28
  }else{
29
    $part = SL::DB::Manager::Part->find_by( id => $self->part_id );
30
    $price =  $part->prices->[0]->price;
31
  }
32

  
33
  my $taxrate;
34
  my $dbh  = $::form->get_standard_dbh();
35
  my $b_id = $part->buchungsgruppen_id;
36
  my $t_id = $self->shop->taxzone_id;
37

  
38
  my $sql_str = "SELECT a.rate AS taxrate from tax a
39
  WHERE a.taxkey = (SELECT b.taxkey_id
40
  FROM chart b LEFT JOIN taxzone_charts c ON b.id = c.income_accno_id
41
  WHERE c.taxzone_id = $t_id
42
  AND c.buchungsgruppen_id = $b_id)";
43

  
44
  my $rate = selectall_hashref_query($::form, $dbh, $sql_str);
45
  $taxrate = @$rate[0]->{taxrate}*100;
46

  
47
  $tax_n_price->{price} = $price;
48
  $tax_n_price->{tax}   = $taxrate;
49
  return $tax_n_price;
50
}
51

  
52
sub get_images {
53
  my ( $self ) = @_;
54

  
55
  require SL::DB::ShopImage;
56
  my $images = SL::DB::Manager::ShopImage->get_all( where => [ 'files.object_id' => $self->{part_id}, ], with_objects => 'file', sort_by => 'position' );
57
  my @upload_img = ();
58
  foreach my $img (@{ $images }) {
59
    my $file               = SL::File->get(id => $img->file->id );
60
    my ($path, $extension) = (split /\./, $file->file_name);
61
    my $content            = File::Slurp::read_file($file->get_file);
62
    my $temp ={ ( link        => 'data:' . $file->mime_type . ';base64,' . MIME::Base64::encode($content, ""), #$content, # MIME::Base64::encode($content),
63
                  description => $img->file->title,
64
                  position    => $img->position,
65
                  extension   => $extension,
66
                  path        => $path,
67
                      )}    ;
68
    push( @upload_img, $temp);
69
  }
70
  return @upload_img;
71
}
16 72

  
17 73
1;
74

  
75
__END__
76

  
77
=pod
78

  
79
=encoding utf-8
80

  
81
=head1 NAME
82

  
83
SL::DB::ShopPart - Model for the 'shop_parts' table
84

  
85
=head1 SYNOPSIS
86

  
87
This is a standard Rose::DB::Object based model and can be used as one.
88

  
89
=head1 METHODS
90

  
91
=over 4
92

  
93
=item C<get_tax_and_price>
94

  
95
Returns the price and the taxrate for an shop_article
96

  
97
=item C<get_images>
98

  
99
Returns the images for the shop_article
100

  
101
=back
102

  
103
=head1 TODO
104

  
105
Prices, pricesources, pricerules could be implemented
106

  
107
=head1 AUTHORS
108

  
109
Werner Hahn E<lt>wh@futureworldsearch.netE<gt>
110

  
111
=cut
SL/ShopConnector/Shopware.pm
206 206
}
207 207

  
208 208
sub update_part {
209
  my ($self, $shop_part, $json, $todo) = @_;
209
  my ($self, $shop_part, $todo) = @_;
210 210

  
211 211
  #shop_part is passed as a param
212 212
  die unless ref($shop_part) eq 'SL::DB::ShopPart';
......
214 214
  my $url = $self->url;
215 215
  my $part = SL::DB::Part->new(id => $shop_part->{part_id})->load;
216 216

  
217
  # TODO: Prices (pricerules, pricegroups, multiple prices)
217
  # CVARS to map
218 218
  my $cvars = { map { ($_->config->name => { value => $_->value_as_text, is_valid => $_->is_valid }) } @{ $part->cvars_by_config } };
219 219

  
220 220
  my @cat = ();
......
223 223
    push ( @cat, $temp );
224 224
  }
225 225

  
226
  my $images = SL::DB::Manager::ShopImage->get_all( where => [ 'files.object_id' => $part->{id}, ], with_objects => 'file', sort_by => 'position' );
227
  my @upload_img = ();
228
  foreach my $img (@{ $images }) {
229
    my $file               = SL::File->get(id => $img->file->id );
230
    my ($path, $extension) = (split /\./, $file->file_name);
231
    my $content            = File::Slurp::read_file($file->get_file);
232
    my $temp ={ ( link        => 'data:' . $file->mime_type . ';base64,' . MIME::Base64::encode($content, ""), #$content, # MIME::Base64::encode($content),
233
                  description => $img->file->title,
234
                  position    => $img->position,
235
                  extension   => $extension,
236
                  path        => $path,
237
                      )}    ;
238
    push( @upload_img, $temp);
239
  }
240

  
241
  my ($import,$data,$data_json);
242
#  if( $shop_part->last_update){
243
    my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
244
# Shopware RestApi schreibt Fehleremail wenn Artikel nicht gefunden. es braucht aber irgendeine Abfrage, ob der Artikel schon im Shop ist.
245
# LWP->post = neuanlegen LWP->put = update
246
    $data       = $self->connector->get($url . "api/articles/$partnumber?useNumberAsId=true");
247
    $data_json  = $data->content;
248
    $import     = SL::JSON::decode_json($data_json);
249
#  }
250

  
251
  # get the right price
252
  # TODO In extra Helper??
253
  my ( $price_src_str, $price_src_id ) = split(/\//,$shop_part->active_price_source);
254
  require SL::DB::Part;
255
  my $price;
256
  if ($price_src_str eq "master_data") {
257
    my $part = SL::DB::Manager::Part->get_all( where => [id => $shop_part->part_id], with_objects => ['prices'],limit => 1)->[0];
258
    $price = $part->$price_src_id;
259
  }else{
260
    my $part = SL::DB::Manager::Part->get_all( where => [id => $shop_part->part_id, 'prices.'.pricegroup_id => $price_src_id], with_objects => ['prices'],limit => 1)->[0];
261
    $price =  $part->prices->[0]->price;
262
  }
263

  
264
  # get the right taxrate for the article
265
  # TODO In extra Helper??
266
  my $taxrate;
267
  my $dbh  = $::form->get_standard_dbh();
268
  my $b_id = $part->buchungsgruppen_id;
269
  my $t_id = $shop_part->shop->taxzone_id;
270

  
271
  my $sql_str = "SELECT a.rate AS taxrate from tax a
272
  WHERE a.taxkey = (SELECT b.taxkey_id
273
  FROM chart b LEFT JOIN taxzone_charts c ON b.id = c.income_accno_id
274
  WHERE c.taxzone_id = $t_id
275
  AND c.buchungsgruppen_id = $b_id)";
276

  
277
  my $rate = selectall_hashref_query($::form, $dbh, $sql_str);
278
  $taxrate = @$rate[0]->{taxrate}*100;
279

  
226
  my @upload_img = $shop_part->get_images;
227
  my $tax_n_price = $shop_part->get_tax_and_price;
228
  my $price = $tax_n_price->{price};
229
  my $taxrate = $tax_n_price->{tax};
280 230
  # mapping to shopware still missing attributes,metatags
281 231
  my %shop_data;
282 232

  
......
339 289

  
340 290
  my $upload_content;
341 291
  my $upload;
292
  my ($import,$data,$data_json);
293
  my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
294
  # Shopware RestApi sends an erroremail if configured and part not found. But it needs this info to decide if update or create a new article
295
  # LWP->post = create LWP->put = update
296
    $data       = $self->connector->get($url . "api/articles/$partnumber?useNumberAsId=true");
297
    $data_json  = $data->content;
298
    $import     = SL::JSON::decode_json($data_json);
342 299
  if($import->{success}){
343 300
    #update
344 301
    my $partnumber  = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
......
354 311
  # don't know if this is needed
355 312
  if(@upload_img) {
356 313
    my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
357
    my $imgup      = $self->connector->put($url . "api/generatearticleimages/$partnumber?usenumberasid=true");
314
    my $imgup      = $self->connector->put($url . "api/generatearticleimages/$partnumber?useNumberAsId=true");
358 315
  }
359 316

  
360 317
  return $upload_content->{success};
......
365 322

  
366 323
  my $url       = $self->url;
367 324
  $partnumber   = $::form->escape($partnumber);#shopware don't accept / in articlenumber
368
  my $data      = $self->connector->get($url . "api/articles/$partnumber?usenumberasid=true");
325
  my $data      = $self->connector->get($url . "api/articles/$partnumber?useNumberAsId=true");
369 326
  my $data_json = $data->content;
370 327
  return SL::JSON::decode_json($data_json);
371 328
}
js/kivi.ShopPart.js
1 1
namespace('kivi.ShopPart', function(ns) {
2 2
  var $dialog;
3 3

  
4
  // this is called by sub render, with a certain prerendered html (edit.html,categories.html)
5 4
  ns.shop_part_dialog = function(title, html) {
6 5
    var id            = 'jqueryui_popup_dialog';
7 6
    var dialog_params = {
......
28 27
    $dialog.dialog("close");
29 28
  }
30 29

  
31

  
32
  // save existing shop_part_id with new params from form, calls create_or_update and saves to db
33 30
  ns.save_shop_part = function(shop_part_id) {
34 31
    var form = $('form').serializeArray();
35 32
    form.push( { name: 'action', value: 'ShopPart/update' }
......
41 38
    });
42 39
  }
43 40

  
44
  // add part to a shop
45 41
  ns.add_shop_part = function(part_id,shop_id) {
46 42
    var form = $('form').serializeArray();
47 43
    form.push( { name: 'action', value: 'ShopPart/update' }
......
51 47
    });
52 48
  }
53 49

  
54
  // this is called from tabs/_shop.html, opens edit_window (render)
55 50
  ns.edit_shop_part = function(shop_part_id) {
56 51
    $.post('controller.pl', { action: 'ShopPart/create_or_edit_popup', shop_part_id: shop_part_id }, function(data) {
57 52
      kivi.eval_json_result(data);
58 53
    });
59 54
  }
60 55

  
61
  // does the same as edit_shop_part (existing), but with part_id and shop_id, opens edit window (render)
62 56
  ns.create_shop_part = function(part_id, shop_id) {
63 57
    $.post('controller.pl', { action: 'ShopPart/create_or_edit_popup', part_id: part_id, shop_id: shop_id }, function(data) {
64 58
      kivi.eval_json_result(data);
65 59
    });
66 60
  }
67 61

  
68
  // gets all categories from the webshop
69 62
  ns.get_all_categories = function(shop_part_id) {
70
    //var form = new Array; //$('form').serializeArray();
71
    //form.push( { name: 'action', value: 'ShopPart/get_categories' }
72
    //         , { name: 'shop_part_id', value: shop_part_id }
73
    //);
74 63
    $.post('controller.pl', { action: 'ShopPart/get_categories', shop_part_id: shop_part_id }, function(data) {
75 64
      kivi.eval_json_result(data);
76 65
    });
77
    //$.post('controller.pl', form, function(data) {
78
    //  kivi.eval_json_result(data);
79
    //});
80 66
  }
81
  // write categories in kivi DB not in the shops DB TODO: create new categories in the shops db
67

  
82 68
  ns.save_categories = function(shop_part_id, shop_id) {
83 69
    var form = $('form').serializeArray();
84 70
    form.push( { name: 'action', value: 'ShopPart/save_categories' }
......
108 94
    $('#shop_images').load(url);
109 95
  }
110 96

  
111
  //shows the Name and price in _shop.html. Pricerules not implemented yet, just master_data and pricegroups
112 97
  ns.update_price_n_price_source = function(shop_part_id,price_source) {
113 98
    $.post('controller.pl', { action: 'ShopPart/show_price_n_pricesource', shop_part_id: shop_part_id, pricesource: price_source }, function(data) {
114 99
      kivi.eval_json_result(data);
115 100
    });
116 101
  }
117
  //shows the local and the online stock
102

  
118 103
  ns.update_stock = function(shop_part_id) {
119 104
    $.post('controller.pl', { action: 'ShopPart/show_stock', shop_part_id: shop_part_id }, function(data) {
120 105
      kivi.eval_json_result(data);
templates/webpages/shop_part/_list_articles.html
75 75
      </td>
76 76
      <td style="vertical-align:middle;text-align:center;">
77 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;" onclick="kivi.ShopPart.part_toggle_active([% shop_part.id %] ,[% shop_part.active %]);" onMouseOver="this.style.cursor='pointer'">&nbsp; </div>
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 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;" onclick="kivi.ShopPart.part_toggle_active([% shop_part.id %] ,[% shop_part.active %]);" onMouseOver="this.style.cursor='pointer'">&nbsp; </div>
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 81
        [% END %]
82 82
      </td>
83 83
      <td>[% L.html_tag('span',LxERP.t8(), id => 'active_price_source_' _ shop_part.id) %] </td>
templates/webpages/shop_part/_transfer_status.html
17 17
    [% IF !data.status %]
18 18
     [% LxERP.t8("waiting for job to be started") %]
19 19
    [% ELSIF data.status == 1 %]
20
     [% LxERP.t8("Creating orders") %]
20
     [% LxERP.t8("Uploading Data") %]
21 21
    [% ELSE %]
22 22
     [% LxERP.t8("Done.") %]
23 23
    [% END %]
24 24
   </td>
25 25
  </tr>
26 26
  <tr>
27
   <th valign="top" align="left">[% LxERP.t8("Number of orders created:") %]</th>
28
   <td valign="top">[% IF data.status > 0 %][% HTML.escape(data.num_created) %] / [% HTML.escape(data.record_ids.size) %][% ELSE %]–[% END %]</td>
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 29
  </tr>
30 30

  
31 31
  <tr>
32
   <th valign="top" align="left">[% LxERP.t8("Errors during conversion:") %]</th>
32
   <th valign="top" align="left">[% LxERP.t8("Conversion:") %]</th>
33 33
   <td valign="top">
34 34
[% IF !data.status %]
35 35
36
[% ELSIF !data.conversion_errors.size %]
37
 [% LxERP.t8("No errors have occurred.") %]
38
[% ELSE %]
39 36
    <table>
40 37
     <tr class="listheader">
41
      <th>[% LxERP.t8("Shop Order") %]</th>
42
      <th>[% LxERP.t8("Error") %]</th>
38
      <th>[% LxERP.t8("Part") %]</th>
39
      <th>[% LxERP.t8("Partnumber") %]</th>
40
      <th>[% LxERP.t8("Message") %]</th>
43 41
     </tr>
44 42

  
45
 [% FOREACH error = data.conversion_errors %]
43
 [% FOREACH message = data.conversion %]
46 44
     <tr>
47 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>
48
      <td valign="top">[% HTML.escape(error.message) %]</td>
46
      <td valign="top">[% HTML.escape(message.message) %]</td>
49 47
     </tr>
50 48
 [% END %]
51 49
    </table>
templates/webpages/shop_part/_upload_status.html
2 2
[%- USE Dumper -%]
3 3
[% SET data = job.data_as_hash %]
4 4

  
5

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

  
8 7
[% L.hidden_tag('', job.id, id="smu_job_id") %]
......
18 17
    [% IF !data.status %]
19 18
     [% LxERP.t8("waiting for job to be started") %]
20 19
    [% ELSIF data.status == 1 %]
21
     [% LxERP.t8("Creating orders") %]
20
     [% LxERP.t8("Uploading Data") %]
22 21
    [% ELSE %]
23 22
     [% LxERP.t8("Done.") %]
24 23
    [% END %]
25 24
   </td>
26 25
  </tr>
27 26
  <tr>
28
   <th valign="top" align="left">[% LxERP.t8("Number of orders created:") %]</th>
29
   <td valign="top">[% IF data.status > 0 %][% HTML.escape(data.num_created) %] / [% HTML.escape(data.record_ids.size) %][% ELSE %]–[% END %]</td>
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>
30 29
  </tr>
31 30

  
32 31
  <tr>
33
   <th valign="top" align="left">[% LxERP.t8("Errors during conversion:") %]</th>
32
   <th valign="top" align="left">[% LxERP.t8("Conversion:") %]</th>
34 33
   <td valign="top">
35
[% IF !data.status %]
36 34
37
[% ELSIF !data.conversion_errors.size %]
38
 [% LxERP.t8("No errors have occurred.") %]
39
[% ELSE %]
40 35
    <table>
41 36
     <tr class="listheader">
42
      <th>[% LxERP.t8("Shop Order") %]</th>
43
      <th>[% LxERP.t8("Error") %]</th>
37
      <th>[% LxERP.t8("Part") %]</th>
38
      <th>[% LxERP.t8("Partnumber") %]</th>
39
      <th>[% LxERP.t8("Message") %]</th>
44 40
     </tr>
45 41

  
46
 [% FOREACH error = data.conversion_errors %]
42
 [% FOREACH message = data.conversion %]
47 43
     <tr>
48
      <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>
49
      <td valign="top">[% HTML.escape(error.message) %]</td>
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>
50 47
     </tr>
51 48
 [% END %]
52 49
    </table>
53
 [% END %]
54 50
 </table>
55 51
</p>

Auch abrufbar als: Unified diff