Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 60a0462f

Von Werner Hahn vor mehr als 6 Jahren hinzugefügt

  • ID 60a0462faa58167aeae73ee50ac1165ce979291b
  • Vorgänger 23b2cbd7
  • Nachfolger 865dda05

Shopmodul: ActionBar, automatische Prüfung der Shopverbindung beim
speichern
Zusätzliche Felder in der Shopconfig für Pfad, Realm und Protokoll

Unterschiede anzeigen:

SL/Controller/Shop.pm
12 12
use SL::DB::TaxZone;
13 13

  
14 14
use Rose::Object::MakeMethods::Generic (
15
  scalar                  => [ qw(connectors price_types price_sources taxzone_id) ],
15
  scalar                  => [ qw(connectors price_types price_sources taxzone_id protocols) ],
16 16
  'scalar --get_set_init' => [ qw(shop) ]
17 17
);
18 18

  
......
26 26
sub action_list {
27 27
  my ($self) = @_;
28 28

  
29
  $self->_setup_list_action_bar;
29 30
  $self->render('shops/list',
30 31
                title => t8('Shops'),
31 32
                SHOPS => SL::DB::Manager::Shop->get_all_sorted,
32 33
               );
33 34
}
34 35

  
35
sub action_new {
36
  my ($self) = @_;
37

  
38
  $self->shop(SL::DB::Shop->new);
39
  $self->render('shops/form', title       => t8('Add shop'));
40
};
41

  
42 36
sub action_edit {
43 37
  my ($self) = @_;
44 38

  
45
  $self->render('shops/form', title       => t8('Edit shop'));
39
  my $is_new = !$self->shop->id;
40
  $self->_setup_form_action_bar;
41
  $self->render('shops/form', title       => ($is_new ? t8('Add shop') : t8('Edit shop')));
46 42
}
47 43

  
48
sub action_create {
44
sub action_save {
49 45
  my ($self) = @_;
50 46

  
51
  $self->shop(SL::DB::Shop->new);
52
  $self->create_or_update;
53
}
54

  
55
sub action_update {
56
  my ($self) = @_;
47
  my $is_new = !$self->shop->id;
57 48
  $self->create_or_update;
58 49
}
59 50

  
......
75 66
  $self->render(\'', { type => 'json' });
76 67
}
77 68

  
78
#
79
# filters
80
#
69
sub action_check_connectivity {
70
  my ($self) = @_;
71

  
72
  my $ok = 0;
73
  require SL::Shop;
74
  my $shop = SL::Shop->new( config => $self->shop );
75
  my $version = $shop->connector->get_version;
76
  $ok       = $version->{success};
77

  
78
  if($ok) {
79
    flash_later('ok', t8('The connection to the webshop is success. Version: #1 -- Revision: #2', $version->{data}->{version}, $version->{data}->{revision}));
80
    return;
81
  }else{
82
    return $version;
83
  }
84
}
81 85

  
82 86
sub check_auth {
83 87
  $::auth->assert('config');
84 88
}
85 89

  
86 90
sub init_shop {
87
  SL::DB::Shop->new(id => $::form->{id})->load;
91
  SL::DB::Manager::Shop->find_by_or_create(id => $::form->{id} || 0)
92
                              ->assign_attributes(%{ $::form->{shop} });
88 93
}
89 94

  
90 95
#
......
95 100
  my ($self) = @_;
96 101
  my $is_new = !$self->shop->id;
97 102

  
98
  my $params = delete($::form->{shop}) || { };
99

  
100
  $self->shop->assign_attributes(%{ $params });
101

  
102 103
  my @errors = $self->shop->validate;
103

  
104 104
  if (@errors) {
105 105
    flash('error', @errors);
106
    $self->render('shops/form',
107
                   title => $is_new ? t8('Add shop') : t8('Edit shop'));
106
    $self->load_types();
107
    $self->action_edit();
108
    return;
109
  }
110

  
111
  my $version = $self->action_check_connectivity();
112
  if ($version) {
113
    flash('error', t8('The connection to the webshop is not success. Message: #1 -- URL: #2 -- Datatype: #3', $version->{message}, $version->{data}->{version}, $version->{data}->{revision}));
114
    $self->load_types();
115
    $self->action_edit();
108 116
    return;
109 117
  }
110 118

  
......
118 126
  my ($self) = @_;
119 127
  # data for the dropdowns when editing Shop configs
120 128

  
121
  # hardcoded the possible connectors, which correspond to
122
  # SL/ShopConnector/xxxx classes
123
  $self->connectors( [ { id => "xtcommerce", description => "XT Commerce"},
124
                       { id => "shopware",   description => "Shopware" },
125
                       { id => "ideal",      description => "IDeal" }
126
                     ]);
129
  require SL::ShopConnector::ALL;
130
  $self->connectors(SL::ShopConnector::ALL->connectors);
127 131

  
128
  # whether the shop presents its prices as brutto or netto
129 132
  $self->price_types( [ { id => "brutto", name => t8('brutto')}, { id => "netto", name => t8('netto') } ] );
130 133

  
131
  # the possible default price sources to use for the shops: sellprice, lastcost,
132
  # listprice, or one of the pricegroups
134
  $self->protocols( [ { id => "http", name => t8('http') }, { id => "https", name => t8('https') } ] );
135

  
133 136
  my $pricesources;
134 137
  push( @{ $pricesources } , { id => "master_data/sellprice", name => t8("Master Data")." - ".t8("Sellprice") },
135 138
                             { id => "master_data/listprice", name => t8("Master Data")." - ".t8("Listprice") },
......
153 156

  
154 157
};
155 158

  
159
sub _setup_form_action_bar {
160
  my ($self) = @_;
161

  
162
  for my $bar ($::request->layout->get('actionbar')) {
163
    $bar->add(
164
      combobox => [
165
        action => [
166
          t8('Save'),
167
          submit    => [ '#form', { action => "Shop/save" } ],
168
          accesskey => 'enter',
169
        ],
170
         action => [
171
          t8('Delete'),
172
          submit => [ '#form', { action => "Shop/delete" } ],
173
        ],
174
        ],
175
        action => [
176
          t8('Cancel'),
177
          submit => [ '#form', { action => "Shop/list" } ],
178
        ],
179
    );
180
  }
181
}
182

  
183
sub _setup_list_action_bar {
184
  my ($self) = @_;
185

  
186
  for my $bar ($::request->layout->get('actionbar')) {
187
    $bar->add(
188
        link => [
189
          t8('Add'),
190
          link => $self->url_for(action => 'edit'),
191
        ],
192
    );
193
  }
194
}
156 195

  
157 196
1;
158 197

  
SL/DB/MetaSetup/Shop.pm
17 17
  obsolete          => { type => 'boolean', default => 'false', not_null => 1 },
18 18
  orders_to_fetch   => { type => 'integer' },
19 19
  password          => { type => 'text' },
20
  path              => { type => 'text', default => '/', not_null => 1 },
20 21
  port              => { type => 'integer' },
21 22
  price_source      => { type => 'text' },
22 23
  pricetype         => { type => 'text' },
24
  protocol          => { type => 'text', default => 'http', not_null => 1 },
25
  realm             => { type => 'text' },
26
  server            => { type => 'text' },
23 27
  sortkey           => { type => 'integer' },
24 28
  taxzone_id        => { type => 'integer' },
25
  url               => { type => 'text' },
26 29
);
27 30

  
28 31
__PACKAGE__->meta->primary_key_columns([ 'id' ]);
SL/Shop.pm
62 62
=head1 SYNOPSIS
63 63

  
64 64
  my $config = SL::DB::Manager::Shop->get_first();
65
  my $shop = SL::WebShop->new( config => $config );
65
  my $shop = SL::Shop->new( config => $config );
66 66

  
67 67
  From the config we know which Connector class to load, save in $shop->connector
68 68
  and do stuff from there:
SL/ShopConnector/ALL.pm
23 23
  ideal
24 24
);
25 25

  
26
my @shop_connectors =
27
  (
28
    { id => "xtcommerce", description => "XT Commerce"},
29
    { id => "shopware",   description => "Shopware" },
30
    { id => "ideal",      description => "IDeal" }
31
  );
32

  
26 33
sub all_enabled_shop_connectors {
27 34
  my %disabled = map { $_ => 1 } @{ $::instance_conf->get_disabled_shop_connectors || [] };
28 35

  
......
41 48
  $shop_connector_by_connector{$_[1]};
42 49
}
43 50

  
51
sub connectors {
52
  \@shop_connectors;
53
}
44 54
1;
SL/ShopConnector/Base.pm
16 16
sub get_article { die 'get_article needs to be implemented' }
17 17

  
18 18
sub get_categories { die 'get_order needs to be implemented' }
19

  
20
sub get_version { die 'get_order needs to be implemented' }
19 21
1;
20 22

  
21 23
__END__
......
24 26

  
25 27
=head1 NAME
26 28

  
27
SL::ShopConnectorBase - this is the base class for shop connectors
29
  SL::ShopConnectorBase - this is the base class for shop connectors
28 30

  
29 31
=head1 SYNOPSIS
30 32

  
......
41 43

  
42 44
=item C<update_part>
43 45

  
46
=item C<get_article>
47

  
48
=item C<get_categories>
49

  
50
=item C<get_version>
51

  
44 52
=back
45 53

  
46 54
=head1 SEE ALSO
47 55

  
48
L<SL::ShopConnector::ALL>
56
  L<SL::ShopConnector::ALL>
49 57

  
50 58
=head1 BUGS
51 59

  
52
None yet. :)
60
  None yet. :)
53 61

  
54 62
=head1 AUTHOR
55 63

  
56
G. Richardson <lt>information@kivitendo-premium.deE<gt>
64
  G. Richardson <lt>information@kivitendo-premium.deE<gt>
65
  W. Hahn E<lt>wh@futureworldsearch.netE<gt>
57 66

  
58 67
=cut
SL/ShopConnector/Shopware.pm
26 26
sub get_new_orders {
27 27
  my ($self, $id) = @_;
28 28

  
29
  my $url = $self->url;
30

  
29
  my $url       = $self->url;
31 30
  my $ordnumber = $self->config->last_order_number + 1;
32
  my $otf = $self->config->orders_to_fetch;
31
  my $otf       = $self->config->orders_to_fetch;
33 32

  
34 33
  my $i;
35 34
  for ($i=1;$i<=$otf;$i++) {
36 35

  
37
    my $data = $self->connector->get("http://$url/api/orders/$ordnumber?useNumberAsId=true");
36
    my $data      = $self->connector->get($url . "api/orders/$ordnumber?useNumberAsId=true");
38 37
    my $data_json = $data->content;
39
    my $import = SL::JSON::decode_json($data_json);
38
    my $import    = SL::JSON::decode_json($data_json);
40 39
    if ($import->{success}){
41 40

  
42 41
      # Mapping to table shoporders. See http://community.shopware.com/_detail_1690.html#GET_.28Liste.29
......
131 130
      $shop_order->{positions} = $position-1;
132 131

  
133 132
      # Only Customers which are not found will be applied
134
      my $name = $shop_order->billing_lastname ne '' ? "%" . $shop_order->billing_firstname . "%" . $shop_order->billing_lastname . "%" : '';
133
      my $name     = $shop_order->billing_lastname ne '' ? "%" . $shop_order->billing_firstname . "%" . $shop_order->billing_lastname . "%" : '';
135 134
      my $lastname = $shop_order->billing_lastname ne '' ? "%" . $shop_order->billing_lastname . "%" : '';
136
      my $company = $shop_order->billing_company ne '' ? "%" . $shop_order->billing_company . "%" : '';
137
      my $street = $shop_order->billing_street ne '' ?  $shop_order->billing_street : '';
135
      my $company  = $shop_order->billing_company ne '' ? "%" . $shop_order->billing_company . "%" : '';
136
      my $street   = $shop_order->billing_street ne '' ?  $shop_order->billing_street : '';
138 137
      # Fuzzysearch for street to find e.g. "Dorfstrasse - Dorfstr. - Dorfstraße"
139
      my $dbh = $::form->get_standard_dbh();
138
      my $dbh      = $::form->get_standard_dbh();
140 139
      my $fs_query = "SELECT id FROM customer WHERE ( ( (    name ILIKE ?
141 140
                                                          OR name ILIKE ?
142 141
                                                        )
......
148 147
                                                      OR email ILIKE ?
149 148
                                                    )";
150 149
      my @values = ($lastname, $company, $shop_order->billing_zipcode, $street, $shop_order->billing_zipcode, $shop_order->billing_email);
151
      my @c_ids = selectall_array_query($::form, $dbh, $fs_query, @values);
150
      my @c_ids  = selectall_array_query($::form, $dbh, $fs_query, @values);
152 151

  
153 152
      if(!scalar(@c_ids)){
154 153

  
......
200 199
      $ordnumber++;
201 200
    }
202 201
  }
203
  my $shop = $self->config->description;
202
  my $shop           = $self->config->description;
204 203
  my @fetched_orders = ($shop,$i);
205 204
  return \@fetched_orders;
206 205
};
......
208 207
sub get_categories {
209 208
  my ($self) = @_;
210 209

  
211
  my $url = $self->url;
212

  
213
  my $data = $self->connector->get("http://$url/api/categories");
214

  
215
  my $data_json = $data->content;
216
  my $import = SL::JSON::decode_json($data_json);
217
  my @daten = @{$import->{data}};
210
  my $url        = $self->url;
211
  my $data       = $self->connector->get($url . "api/categories");
212
  my $data_json  = $data->content;
213
  my $import     = SL::JSON::decode_json($data_json);
214
  my @daten      = @{$import->{data}};
218 215
  my %categories = map { ($_->{id} => $_) } @daten;
219 216

  
220 217
  for(@daten) {
......
226 223
  return \@daten;
227 224
}
228 225

  
226
sub get_version {
227
  my ($self) = @_;
228

  
229
  my $url       = $self->url;
230
  my $data      = $self->connector->get($url . "api/version");
231
  my $type = $data->content_type;
232
  my $status_line = $data->status_line;
233

  
234
  if($data->is_success && $type eq 'application/json'){
235
    my $data_json = $data->content;
236
    return SL::JSON::decode_json($data_json);
237
  }else{
238
    my %return = ( success => 0,
239
                   data  => { version => $url . ": " . $status_line, revision => $type },
240
                   message => "Server not found or wrong data type",
241
                );
242
    return \%return;
243
  }
244
}
245

  
229 246
sub get_articles {
230 247
  my ($self, $json_data) = @_;
231 248

  
232 249
}
233 250

  
234

  
235 251
sub update_part {
236 252
  my ($self, $shop_part, $json, $todo) = @_;
237 253

  
......
253 269
  my $images = SL::DB::Manager::ShopImage->get_all( where => [ 'files.object_id' => $part->{id}, ], with_objects => 'file', sort_by => 'position' );
254 270
  my @upload_img = ();
255 271
  foreach my $img (@{ $images }) {
256
    my $file = SL::File->get(id => $img->file->id );
257
    my $file_path = $file->get_file;
272
    my $file               = SL::File->get(id => $img->file->id );
273
    my $file_path          = $file->get_file;
258 274
    my ($path, $extension) = (split /\./, $file->file_name);
259
    my $content = File::Slurp::read_file($file->get_file);
275
    my $content            = File::Slurp::read_file($file->get_file);
276

  
260 277
    my $temp ={ ( link        => 'data:' . $file->mime_type . ';base64,' . MIME::Base64::encode($content),
261 278
                  description => $img->file->title,
262 279
                  position    => $img->position,
......
271 288
    my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
272 289
# Shopware RestApi schreibt Fehleremail wenn Artikel nicht gefunden. es braucht aber irgendeine Abfrage, ob der Artikel schon im Shop ist.
273 290
# LWP->post = neuanlegen LWP->put = update
274
    $data = $self->connector->get("http://$url/api/articles/$partnumber?useNumberAsId=true");
275
    $data_json = $data->content;
276
    $import = SL::JSON::decode_json($data_json);
291
    $data       = $self->connector->get($url . "api/articles/$partnumber?useNumberAsId=true");
292
    $data_json  = $data->content;
293
    $import     = SL::JSON::decode_json($data_json);
277 294
#  }
278 295

  
279 296
  # get the right price
......
291 308
  # get the right taxrate for the article
292 309
  # TODO In extra Helper??
293 310
  my $taxrate;
294
  my $dbh = $::form->get_standard_dbh();
311
  my $dbh  = $::form->get_standard_dbh();
295 312
  my $b_id = $part->buchungsgruppen_id;
296 313
  my $t_id = $shop_part->shop->taxzone_id;
297 314

  
......
362 379
  }
363 380

  
364 381
  my $dataString = SL::JSON::to_json(\%shop_data);
365
  $dataString = encode_utf8($dataString);
382
  $dataString    = encode_utf8($dataString);
366 383
  my $upload_content;
367 384
  my $upload;
368 385
  if($import->{success}){
369 386
    #update
370
    my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
371
    $upload = $self->connector->put("http://$url/api/articles/$partnumber?useNumberAsId=true",Content => $dataString);
372
    my $data_json = $upload->content;
387
    my $partnumber  = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
388
    $upload         = $self->connector->put($url . "api/articles/$partnumber?useNumberAsId=true", Content => $dataString);
389
    my $data_json   = $upload->content;
373 390
    $upload_content = SL::JSON::decode_json($data_json);
374 391
  }else{
375 392
    #upload
376
    $upload = $self->connector->post("http://$url/api/articles/",Content => $dataString);
377
    my $data_json = $upload->content;
393
    $upload         = $self->connector->post($url . "api/articles/", Content => $dataString);
394
    my $data_json   = $upload->content;
378 395
    $upload_content = SL::JSON::decode_json($data_json);
379 396
  }
380
  # Don't know if this is needed
397
  # don't know if this is needed
381 398
  if(@upload_img) {
382 399
    my $partnumber = $::form->escape($part->{partnumber});#shopware don't accept / in articlenumber
383
    my $imgup = $self->connector->put("http://$url/api/generateArticleImages/$partnumber?useNumberAsId=true");
400
    my $imgup      = $self->connector->put($url . "api/generatearticleimages/$partnumber?usenumberasid=true");
384 401
  }
385 402

  
386 403
  return $upload_content->{success};
......
389 406
sub get_article {
390 407
  my ($self,$partnumber) = @_;
391 408

  
392
  my $url = $self->url;
393
  $partnumber = $::form->escape($partnumber);#shopware don't accept / in articlenumber
394
  my $data = $self->connector->get("http://$url/api/articles/$partnumber?useNumberAsId=true");
409
  my $url       = $self->url;
410
  $partnumber   = $::form->escape($partnumber);#shopware don't accept / in articlenumber
411
  my $data      = $self->connector->get($url . "api/articles/$partnumber?usenumberasid=true");
395 412
  my $data_json = $data->content;
396 413
  return SL::JSON::decode_json($data_json);
397 414
}
398 415

  
416

  
399 417
sub set_orderstatus {
400 418
  my ($self,$ordernumber);
401 419
}
402 420

  
403 421
sub init_url {
404 422
  my ($self) = @_;
405
  # TODO: validate url and port Mabey in shopconfig test connection
406
  $self->url($self->config->url . ":" . $self->config->port);
407
};
423
  $self->url($self->config->protocol . "://" . $self->config->server . ":" . $self->config->port . $self->config->path);
424
}
408 425

  
409 426
sub init_connector {
410 427
  my ($self) = @_;
411 428
  my $ua = LWP::UserAgent->new;
412 429
  $ua->credentials(
413
      $self->url,
414
      "Shopware REST-API", # TODO in config
430
      $self->config->server . ":" . $self->config->port,
431
      $self->config->realm,
415 432
      $self->config->login => $self->config->password
416 433
  );
434

  
417 435
  return $ua;
418
};
436
}
419 437

  
420 438
1;
421 439

  
......
425 443

  
426 444
=head1 NAME
427 445

  
428
  SL::ShopConnecter::Shopware - connector for Shopware 5
446
  SL::Shopconnecter::Shopware - connector for shopware 5
429 447

  
430 448
=head1 SYNOPSIS
431 449

  
432 450

  
433 451
=head1 DESCRIPTION
434 452

  
453
=head1 TODO
454

  
455
  Pricesrules, pricessources aren't fully implemented yet.
456
  Payments aren't implemented( need to map payments from Shopware like invoice, paypal etc. to payments in kivitendo)
435 457

  
436 458
=head1 BUGS
437 459

  
sql/Pg-upgrade2/shops_1.sql
1
-- @tag: shop_1
2
-- @description: Add tables for part information for shop
3
-- @charset: UTF-8
4
-- @depends: shops
5
-- @ignore: 0
6

  
7
ALTER TABLE shops ADD COLUMN protocol TEXT NOT NULL DEFAULT 'http';
8
ALTER TABLE shops ADD COLUMN path TEXT NOT NULL DEFAULT '/';
9
ALTER TABLE shops RENAME COLUMN url TO server;
sql/Pg-upgrade2/shops_2.sql
1
-- @tag: shop_2
2
-- @description: Add tables for part information for shop
3
-- @charset: UTF-8
4
-- @depends: shops
5
-- @ignore: 0
6

  
7
ALTER TABLE shops ADD COLUMN realm TEXT;
sql/Pg-upgrade2/trigram_indices.sql
1
-- @tag: trigram_indices
2
-- @description: Trigram Indizes für häufig durchsuchte Spalten
3
-- @depends: release_3_4_1
4
-- @encoding: utf-8
5
-- @ignore: 1
6

  
7
-- CREATE EXTENSION IF NOT EXISTS pg_trgm;
8

  
9
CREATE INDEX customer_customernumber_gin_trgm_idx    ON customer        USING gin (customernumber          gin_trgm_ops);
10
CREATE INDEX customer_name_gin_trgm_idx              ON customer        USING gin (name                    gin_trgm_ops);
11

  
12
CREATE INDEX vendor_vendornumber_gin_trgm_idx        ON vendor          USING gin (vendornumber            gin_trgm_ops);
13
CREATE INDEX vendor_name_gin_trgm_idx                ON vendor          USING gin (name                    gin_trgm_ops);
14

  
15
CREATE INDEX parts_partnumber_gin_trgm_idx           ON parts           USING gin (partnumber              gin_trgm_ops);
16
CREATE INDEX parts_description_gin_trgm_idx          ON parts           USING gin (description             gin_trgm_ops);
17

  
18
CREATE INDEX oe_ordnumber_gin_trgm_idx               ON oe              USING gin (ordnumber               gin_trgm_ops);
19
CREATE INDEX oe_quonumber_gin_trgm_idx               ON oe              USING gin (quonumber               gin_trgm_ops);
20
CREATE INDEX oe_cusordnumber_gin_trgm_idx            ON oe              USING gin (cusordnumber            gin_trgm_ops);
21
CREATE INDEX oe_transaction_description_gin_trgm_idx ON oe              USING gin (transaction_description gin_trgm_ops);
22

  
23
CREATE INDEX do_donumber_gin_trgm_idx                ON delivery_orders USING gin (donumber                gin_trgm_ops);
24
CREATE INDEX do_ordnumber_gin_trgm_idx               ON delivery_orders USING gin (ordnumber               gin_trgm_ops);
25
CREATE INDEX do_cusordnumber_gin_trgm_idx            ON delivery_orders USING gin (cusordnumber            gin_trgm_ops);
26
CREATE INDEX do_transaction_description_gin_trgm_idx ON delivery_orders USING gin (transaction_description gin_trgm_ops);
27

  
28
CREATE INDEX ar_invnumber_gin_trgm_idx               ON ar              USING gin (invnumber               gin_trgm_ops);
29
CREATE INDEX ar_ordnumber_gin_trgm_idx               ON ar              USING gin (ordnumber               gin_trgm_ops);
30
CREATE INDEX ar_quonumber_gin_trgm_idx               ON ar              USING gin (quonumber               gin_trgm_ops);
31
CREATE INDEX ar_cusordnumber_gin_trgm_idx            ON ar              USING gin (cusordnumber            gin_trgm_ops);
32
CREATE INDEX ar_transaction_description_gin_trgm_idx ON ar              USING gin (transaction_description gin_trgm_ops);
33

  
34
CREATE INDEX ap_invnumber_gin_trgm_idx               ON ap              USING gin (invnumber               gin_trgm_ops);
35
CREATE INDEX ap_ordnumber_gin_trgm_idx               ON ap              USING gin (ordnumber               gin_trgm_ops);
36
CREATE INDEX ap_quonumber_gin_trgm_idx               ON ap              USING gin (quonumber               gin_trgm_ops);
37
CREATE INDEX ap_transaction_description_gin_trgm_idx ON ap              USING gin (transaction_description gin_trgm_ops);
38

  
39
CREATE INDEX gl_description_gin_trgm_idx             ON gl              USING gin (description             gin_trgm_ops);
40
CREATE INDEX gl_reference_gin_trgm_idx               ON gl              USING gin (reference               gin_trgm_ops);
41

  
42
CREATE INDEX orderitems_description_gin_trgm_idx     ON orderitems      USING gin (description             gin_trgm_ops);
43

  
44
CREATE INDEX doi_description_gin_trgm_idx       ON delivery_order_items USING gin (description             gin_trgm_ops);
45

  
46
CREATE INDEX invoice_description_gin_trgm_idx        ON invoice         USING gin (description             gin_trgm_ops);
templates/webpages/shops/form.html
6 6

  
7 7
<h1>[% HTML.escape(title) %]</h1>
8 8
[% #Dumper.dump_html(SELF.shop) %]
9
<form action="controller.pl" method="post">
9
<form id="form" action="controller.pl" method="post">
10 10

  
11 11
[%- INCLUDE 'common/flash.html' %]
12 12

  
......
34 34
    <td>[% L.select_tag('shop.taxzone_id', SELF.taxzone_id, value_key = 'id', title_key = 'name', with_empty = 0, default = SELF.shop.taxzone_id, default_value_key='id' ) %]</td>
35 35
  </tr>
36 36
  <tr>
37
    <th align="right">[% 'URL' | $T8 %]</th>
38
    <td>[%- L.input_tag("shop.url", SELF.shop.url, size=size) %]</td>
37
    <th align="right">[% 'Protocol' | $T8 %]</th>
38
    <td>[% L.select_tag('shop.protocol', SELF.protocols value_key = 'id', title_key = 'name', with_empty = 0, default = SELF.shop.protocol, default_value_key='id' ) %]</td>
39
  </tr>
40
  <tr>
41
    <th align="right">[% 'Server' | $T8 %]</th>
42
    <td>[%- L.input_tag("shop.server", SELF.shop.server, size=size) %]</td>
39 43
  </tr>
40 44
  <tr>
41 45
    <th align="right">[% 'Port' | $T8 %]</th>
42 46
    <td>[%- L.input_tag("shop.port", SELF.shop.port, size=5) %]</td>
43
   <tr>
47
  </tr>
48
  <tr>
49
    <th align="right">[% 'Path' | $T8 %]</th>
50
    <td>[%- L.input_tag("shop.path", SELF.shop.path, size=size) %]</td>
51
  </tr>
52
  <tr>
53
    <th align="right">[% 'Realm' | $T8 %]</th>
54
    <td>[%- L.input_tag("shop.realm", SELF.shop.realm, size=size) %]</td>
55
  </tr>
56
  <tr>
44 57
    <th align="right">[% 'User' | $T8 %]</th>
45
    <td>[%- L.input_tag("shop.login", SELF.shop.login, size=12) %]</td>
58
    <td>[%- L.input_tag("shop.login", SELF.shop.login, size=size) %]</td>
46 59
  </tr>
47 60
  <tr>
48 61
    <th align="right">[% 'Password' | $T8 %]</th>
49
    <td>[%- L.input_tag("shop.password", SELF.shop.password, size=12) %]</td>
62
    <td>[%- L.input_tag("shop.password", SELF.shop.password, size=size) %]</td>
50 63
  </tr>
51 64
  <tr>
52 65
    <th align="right">[% 'Last ordernumber' | $T8 %]</th>
......
62 75
  </tr>
63 76
</table>
64 77

  
65
 <p>
66
  [% L.hidden_tag("action", "Shop/dispatch") %]
67
  [% L.submit_tag("action_" _  (SELF.shop.id ? "update" : "create"), LxERP.t8('Save'), onclick="return check_prerequisites();") %]
68
  [%- IF SELF.shop.id -%]
69
    [% L.submit_tag("action_delete", LxERP.t8('Delete')) %]
70
  [%- END %]
71
  <a href="[% SELF.url_for(action='list') %]">[%- LxERP.t8("Cancel") %]</a>
72
 </p>
73

  
74 78
 <hr>
75
 <table>
76
  <tr>
77
    <th align="right">[% 'Description' | $T8 %]</th>
78
    <th>Last update</th>
79
    <th>[% 'Available qty' | $T8 %]</th>
80
  </tr>
81
 [%- FOREACH shop_part = SELF.shop.updatable_parts %]
82
  <tr>
83
   <td>[% P.part(shop_part.part) %]</td>
84
   <td>[% shop_part.last_update.to_kivitendo %]</td>
85
   <td>[% shop_part.part.get_stock %]</td>
86
  </tr>
87
 [%- END %]
88
 </table>
89

  
90 79

  
91 80
<script type="text/javascript">
92 81
<!--
templates/webpages/shops/list.html
27 27
<hr height="3">
28 28

  
29 29
[% L.sortable_element('#shop_list tbody', url=SELF.url_for(action='reorder'), with='shop_id') %]
30

  
31
<p>
32
 <a href="[% SELF.url_for(action='new') %]">[%- 'Add' | $T8 %]</a>
33
</p>

Auch abrufbar als: Unified diff