Preisgruppen - Umstellung auf Controller, sortkey, obsolete
authorG. Richardson <information@kivitendo-premium.de>
Thu, 29 Sep 2016 05:19:51 +0000 (07:19 +0200)
committerG. Richardson <information@kivitendo-premium.de>
Mon, 17 Oct 2016 14:13:36 +0000 (16:13 +0200)
Neuer CRUD-Controller nur für Preisgruppen.

Die Reihenfolge der Preisgruppen kann nun eingestellt werden, und man
kann Preisgruppen auf ungültig setzen, sofern sie nicht mehr aktiv bei
Kunden in Verwendung sind, so daß sie bei Kunden oder neuen Belegen
nicht mehr ausgewählt werden können.

18 files changed:
SL/Controller/CsvImport/Part.pm
SL/Controller/CustomerVendor.pm
SL/Controller/PriceRule.pm
SL/Controller/Pricegroup.pm [new file with mode: 0644]
SL/DB/Manager/Pricegroup.pm
SL/DB/MetaSetup/Pricegroup.pm
SL/DB/Pricegroup.pm
SL/PriceSource/Pricegroup.pm
bin/mozilla/ic.pl
bin/mozilla/pe.pl
doc/changelog
locale/de/all
menus/user/00-erp.yaml
sql/Pg-upgrade2/pricegroup_sortkey_obsolete.sql [new file with mode: 0644]
templates/webpages/pe/pricegroup_form.html [deleted file]
templates/webpages/pe/pricegroup_report.html [deleted file]
templates/webpages/pricegroup/form.html [new file with mode: 0644]
templates/webpages/pricegroup/list.html [new file with mode: 0644]

index 80fd3ce..9ccaf83 100644 (file)
@@ -118,7 +118,7 @@ sub init_parts_by {
 sub init_all_pricegroups {
   my ($self) = @_;
 
-  return SL::DB::Manager::Pricegroup->get_all(sort => 'id');
+  return SL::DB::Manager::Pricegroup->get_all_sorted;
 }
 
 sub init_settings {
index d12fc6e..2e8b2f5 100644 (file)
@@ -905,7 +905,7 @@ sub _pre_render {
 
   $self->{all_delivery_terms} = SL::DB::Manager::DeliveryTerm->get_all();
 
-  $self->{all_pricegroups} = SL::DB::Manager::Pricegroup->get_all();
+  $self->{all_pricegroups} = SL::DB::Manager::Pricegroup->get_all_sorted(query => [ or => [ id => $self->{cv}->pricegroup_id, obsolete => 0 ] ]);
 
   $query =
     'SELECT DISTINCT(cp_abteilung) AS department
index 1a42a71..d9c3978 100644 (file)
@@ -271,7 +271,7 @@ sub init_businesses {
 }
 
 sub init_pricegroups {
-  SL::DB::Manager::Pricegroup->get_all;
+  SL::DB::Manager::Pricegroup->get_all_sorted;
 }
 
 sub init_partsgroups {
diff --git a/SL/Controller/Pricegroup.pm b/SL/Controller/Pricegroup.pm
new file mode 100644 (file)
index 0000000..047ed65
--- /dev/null
@@ -0,0 +1,152 @@
+package SL::Controller::Pricegroup;
+
+use strict;
+
+use parent qw(SL::Controller::Base);
+
+use SL::Helper::Flash;
+use SL::Locale::String;
+use SL::DB::Default;
+use SL::DB::Manager::Pricegroup;
+
+use Rose::Object::MakeMethods::Generic (
+  scalar                  => [ qw(pricegroup) ],
+  'scalar --get_set_init' => [ qw(all_pricegroups) ],
+);
+
+__PACKAGE__->run_before('check_auth');
+__PACKAGE__->run_before('load_pricegroup', only => [ qw(edit update delete) ]);
+
+#
+# actions
+#
+
+sub action_list {
+  my ($self) = @_;
+
+  $self->render('pricegroup/list',
+                title   => t8('Pricegroups'),
+               );
+}
+
+sub action_new {
+  my ($self) = @_;
+
+  $self->pricegroup( SL::DB::Pricegroup->new );
+  $self->render('pricegroup/form',
+                 title => t8('Add pricegroup'),
+               );
+}
+
+sub action_edit {
+  my ($self) = @_;
+
+  $self->render('pricegroup/form',
+                 title   => t8('Edit pricegroup'),
+                );
+}
+
+sub action_create {
+  my ($self) = @_;
+
+  $self->pricegroup( SL::DB::Pricegroup->new );
+  $self->create_or_update;
+}
+
+sub action_update {
+  my ($self) = @_;
+  $self->create_or_update;
+}
+
+sub action_delete {
+  my ($self) = @_;
+
+  if ( !$self->pricegroup->orphaned ) {
+    flash_later('error', $::locale->text('The pricegroup has been used and cannot be deleted.'));
+  } elsif ( eval { $self->pricegroup->delete; 1; } ) {
+    flash_later('info',  $::locale->text('The pricegroup has been deleted.'));
+  } else {
+    flash_later('error', $::locale->text('The pricegroup has been used and cannot be deleted.'));
+  };
+  $self->redirect_to(action => 'list');
+}
+
+sub action_reorder {
+  my ($self) = @_;
+
+  SL::DB::Pricegroup->reorder_list(@{ $::form->{pricegroup_id} || [] });
+  $self->render(\'', { type => 'json' });
+}
+
+#
+# filters
+#
+
+sub check_auth {
+  $::auth->assert('config');
+}
+
+sub load_pricegroup {
+  my ($self) = @_;
+
+  $self->pricegroup( SL::DB::Pricegroup->new(id => $::form->{id})->load );
+}
+
+sub init_all_pricegroups { SL::DB::Manager::Pricegroup->get_all_sorted }
+
+#
+# helpers
+#
+
+sub create_or_update {
+  my ($self) = @_;
+  my $is_new = !$self->pricegroup->id;
+
+  my $params = delete($::form->{pricegroup}) || { };
+
+  $self->pricegroup->assign_attributes(%{ $params });
+
+  my @errors = $self->pricegroup->validate;
+
+  if (@errors) {
+    flash('error', @errors);
+    $self->render('pricegroup/form',
+                   title => $is_new ? t8('Add pricegroup') : t8('Edit pricegroup'),
+                 );
+    return;
+  }
+
+  $self->pricegroup->save;
+
+  flash_later('info', $is_new ? t8('The pricegroup has been created.') : t8('The pricegroup has been saved.'));
+  $self->redirect_to(action => 'list');
+}
+
+1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Controller::Pricegroup - CRUD controller for pricegroups
+
+=head1 SYNOPSIS
+
+A new controller to create / edit / delete pricegroups.
+
+Pricegroups can only be deleted if they haven't been used anywhere.
+
+=head1 OBSOLETE PRICEGROUPS
+
+Pricegroups can't be obsoleted while any of the customers still use that
+pricegroup as their default pricegroup. Obsoleting a pricegroup means it can't
+be selected when editing customers and it can't be selected as a price source
+for new records.
+
+=head1 AUTHOR
+
+G. Richardson E<lt>grichardson@kivitendo-premium.deE<gt>
+
+=cut
index 6da4f21..0e65609 100644 (file)
@@ -12,10 +12,8 @@ sub object_class { 'SL::DB::Pricegroup' }
 __PACKAGE__->make_manager_methods;
 
 sub _sort_spec {
-  return ( default => [ 'pricegroup', 1 ],
-           columns => { SIMPLE => 'ALL',
-                        map { ( $_ => "lower(pricegroup.${_})" ) } qw(pricegroup),
-                      });
+  return ( default => [ 'sortkey', 1 ],
+           columns => { SIMPLE => 'ALL' });
 }
 
 1;
index 60a7f20..0f35952 100644 (file)
@@ -10,7 +10,9 @@ __PACKAGE__->meta->table('pricegroup');
 
 __PACKAGE__->meta->columns(
   id         => { type => 'integer', not_null => 1, sequence => 'id' },
+  obsolete   => { type => 'boolean', default => 'false' },
   pricegroup => { type => 'text', not_null => 1 },
+  sortkey    => { type => 'integer', not_null => 1 },
 );
 
 __PACKAGE__->meta->primary_key_columns([ 'id' ]);
index b318300..76c644d 100644 (file)
@@ -4,6 +4,8 @@ use strict;
 
 use SL::DB::MetaSetup::Pricegroup;
 use SL::DB::Manager::Pricegroup;
+use SL::DB::Helper::ActsAsList;
+use SL::DB::Customer;
 
 __PACKAGE__->meta->initialize;
 
@@ -13,5 +15,50 @@ sub displayable_name {
   return join ' ', grep $_, $self->id, $self->pricegroup;
 }
 
+sub validate {
+  my ($self) = @_;
+
+  my @errors;
+
+  if ( $self->obsolete && SL::DB::Manager::Customer->get_all_count(query => [ pricegroup_id => $self->id ]) ) {
+    push @errors, $::locale->text('The pricegroup is being used by customers.');
+  }
+
+  return @errors;
+}
+
+sub orphaned {
+  my ($self) = @_;
+  die 'not an accessor' if @_ > 1;
+
+  return 1 unless $self->id;
+
+  my @relations = qw(
+    SL::DB::Customer
+    SL::DB::Price
+  );
+
+  # check if pricegroup is the default pricegroup for any customers and has any
+  # prices assigned.
+
+  for my $class (@relations) {
+    eval "require $class";
+    return 0 if $class->_get_manager_class->get_all_count(query => [ pricegroup_id => $self->id ]);
+  }
+
+  # check if pricegroup was used in any pricesource
+  my @item_relations = qw(
+    SL::DB::OrderItem
+    SL::DB::DeliveryOrderItem
+    SL::DB::InvoiceItem
+  );
+
+  for my $class (@item_relations) {
+    eval "require $class";
+    return 0 if $class->_get_manager_class->get_all_count(query => [ active_price_source => 'pricegroup/' . $self->id ]);
+  }
+
+  return 1;
+}
 
 1;
index 532b1ff..62fabf5 100644 (file)
@@ -20,10 +20,21 @@ sub available_prices {
 
   my $item = $self->record_item;
 
+  my $query = [ parts_id => $item->parts_id, price => { gt => 0 } ];
+
+  # add a pricegroup_filter for obsolete pricegroups, unless part of an
+  # existing pricegroup where that pricegroup was actually used.
+  if ( $self->record->id and $item->active_price_source =~ m/^pricegroup/ ) {
+    my ($pricegroup_id) = $item->active_price_source =~ m/^pricegroup\/(\d+)$/;
+    push(@{$query}, or => [ 'pricegroup.obsolete' => 0, 'pricegroup_id' => $pricegroup_id ]);
+  } else {
+    push(@{$query}, 'pricegroup.obsolete' => 0);
+  }
+
   my $prices = SL::DB::Manager::Price->get_all(
-    query        => [ parts_id => $item->parts_id, price => { gt => 0 } ],
+    query        => $query,
     with_objects => 'pricegroup',
-    sort_by     => 'pricegroup.id',
+    sort_by      => 'pricegroup.sortkey',
   );
 
   return () unless @$prices;
index cf94b7b..702e2b0 100644 (file)
@@ -478,7 +478,7 @@ sub generate_report {
     insertdate shop
   );
 
-  my $pricegroups = SL::DB::Manager::Pricegroup->get_all(sort => 'id');
+  my $pricegroups = SL::DB::Manager::Pricegroup->get_all_sorted;
   my @pricegroup_columns;
   my %column_defs_pricegroups;
   if ($form->{l_pricegroups}) {
index a9cee79..5dc9b89 100644 (file)
@@ -27,7 +27,7 @@
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 #======================================================================
 #
-# partsgroup, pricegroup administration
+# partsgroup administration
 #
 #======================================================================
 
@@ -62,9 +62,6 @@ sub edit {
   if ($::form->{type} eq 'partsgroup') {
     PE->get_partsgroup(\%::myconfig, $::form);
   }
-  if ($::form->{type} eq 'pricegroup') {
-    PE->get_pricegroup(\%::myconfig, $::form);
-  }
   call_sub("form_$::form->{type}");
 
   $::lxdebug->leave_sub;
@@ -92,12 +89,6 @@ sub save {
     $::form->redirect($::locale->text('Group saved!'));
   }
 
-  # choice pricegroup and save
-  if ($::form->{type} eq 'pricegroup') {
-    $::form->isblank("pricegroup", $::locale->text('Pricegroup missing!'));
-    PE->save_pricegroup(\%::myconfig, $::form);
-    $::form->redirect($::locale->text('Pricegroup saved!'));
-  }
   # saving the history
   if(!exists $::form->{addition} && $::form->{id} ne "") {
     $::form->{snumbers} = qq|projectnumber_| . $::form->{projectnumber};
@@ -118,16 +109,6 @@ sub delete {
   if ($::form->{type} eq 'partsgroup') {
     $::form->redirect($::locale->text('Group deleted!'));
   }
-  if ($::form->{type} eq 'pricegroup') {
-    $::form->redirect($::locale->text('Pricegroup deleted!'));
-  }
-  # saving the history
-  if(!exists $::form->{addition}) {
-    $::form->{snumbers} = qq|projectnumber_| . $::form->{projectnumber};
-    $::form->{addition} = "DELETED";
-    $::form->save_history;
-  }
-  # /saving the history
   $::lxdebug->leave_sub;
 }
 
@@ -177,48 +158,3 @@ sub form_partsgroup {
 
   $::lxdebug->leave_sub;
 }
-
-sub pricegroup_report {
-  $::lxdebug->enter_sub;
-  $::auth->assert('config');
-
-  $::form->{$_} = $::form->unescape($::form->{$_}) for qw(pricegroup);
-  PE->pricegroups(\%::myconfig, $::form);
-
-  my $callback = build_std_url('action=pricegroup_report', qw(type status));
-
-  my $option = '';
-  $option .= $::locale->text('All')      if $::form->{status} eq 'all';
-  $option .= $::locale->text('Orphaned') if $::form->{status} eq 'orphaned';
-
-  if ($::form->{pricegroup}) {
-    $callback .= "&pricegroup=$::form->{pricegroup}";
-    $option   .= ", " . $::locale->text('Pricegroup') . " : $::form->{pricegroup}";
-  }
-
-  # escape callback
-  $::form->{callback} = $callback;
-
-  $::form->header;
-  print $::form->parse_html_template('pe/pricegroup_report', {
-    option   => $option,
-    callback => $callback,
-    editlink => build_std_url('action=edit', qw(type status callback)),
-  });
-
-  $::lxdebug->leave_sub;
-}
-
-sub form_pricegroup {
-  $::lxdebug->enter_sub;
-  $::auth->assert('config');
-
-  # $locale->text('Add Pricegroup')
-  # $locale->text('Edit Pricegroup')
-  $::form->{title} = $::locale->text("$::form->{title} Pricegroup");
-
-  $::form->header;
-  print $::form->parse_html_template('pe/pricegroup_form');
-
-  $::lxdebug->leave_sub;
-}
index 9bf0a7c..b0e70fb 100644 (file)
@@ -38,6 +38,9 @@ kleinere neue Features und Detailverbesserungen:
   - Briefe sind jetzt auch für Lieferanten verfügbar. Die neuen Rechte dafür
     sind für Gruppen vergeben, die auch Einkaufsbelege bearbeiten dürfen.
 
+  - Neuer Controller für Preisgruppen, die nun sortiert und ungültig gesetzt
+    werden können.
+
 Administrative Änderungen
 
   - Diverse Textsuchen werden jetzt durch eine neue Klasse Indizes
index ec161b1..3dfa039 100755 (executable)
@@ -160,7 +160,6 @@ $self->{texts} = {
   'Add Letter'                  => 'Brief hinzufügen',
   'Add Part'                    => 'Ware erfassen',
   'Add Price Factor'            => 'Preisfaktor erfassen',
-  'Add Pricegroup'              => 'Preisgruppe erfassen',
   'Add Printer'                 => 'Drucker hinzufügen',
   'Add Project'                 => 'Projekt erfassen',
   'Add Purchase Delivery Order' => 'Lieferschein (Einkauf) erfassen',
@@ -202,6 +201,7 @@ $self->{texts} = {
   'Add part'                    => 'Artikel hinzufügen',
   'Add picture'                 => 'Bild hinzufügen',
   'Add picture to text block'   => 'Bild dem Textblock hinzufügen',
+  'Add pricegroup'              => 'Preisgruppe hinzufügen',
   'Add section'                 => 'Abschnitt hinzufügen',
   'Add sub function block'      => 'Unterfunktionsblock hinzufügen',
   'Add taxzone'                 => 'Steuerzone hinzufügen',
@@ -1055,7 +1055,6 @@ $self->{texts} = {
   'Edit Part'                   => 'Ware bearbeiten',
   'Edit Preferences for #1'     => 'Einstellungen von #1 bearbeiten',
   'Edit Price Factor'           => 'Preisfaktor bearbeiten',
-  'Edit Pricegroup'             => 'Preisgruppe bearbeiten',
   'Edit Printer'                => 'Drucker bearbeiten',
   'Edit Purchase Delivery Order' => 'Lieferschein (Einkauf) bearbeiten',
   'Edit Purchase Order'         => 'Lieferantenauftrag bearbeiten',
@@ -1093,6 +1092,7 @@ $self->{texts} = {
   'Edit picture'                => 'Bild bearbeiten',
   'Edit predefined text'        => 'Vordefinierten Textblock bearbeiten',
   'Edit price rule'             => 'Preisregel bearbeiten',
+  'Edit pricegroup'             => 'Preisgruppe bearbeiten',
   'Edit prices and discount (if not used, textfield is ONLY set readonly)' => 'Preise und Rabatt in Formularen frei anpassen (falls deaktiviert, wird allerdings NUR das textfield auf READONLY gesetzt / kann je nach Browserversion und technischen Fähigkeiten des Anwenders noch umgangen werden)',
   'Edit project'                => 'Projekt bearbeiten',
   'Edit project #1'             => 'Projekt #1 bearbeiten',
@@ -2139,9 +2139,6 @@ $self->{texts} = {
   'Price sources deactivated in this client' => 'Preisquellen die in diesem Mandanten deaktiviert sind',
   'Price type explanation'      => 'Preistyp Erklärung',
   'Pricegroup'                  => 'Preisgruppe',
-  'Pricegroup deleted!'         => 'Preisgruppe gelöscht!',
-  'Pricegroup missing!'         => 'Preisgruppe fehlt!',
-  'Pricegroup saved!'           => 'Preisgruppe gespeichert!',
   'Pricegroups'                 => 'Preisgruppen',
   'Prices'                      => 'Preise',
   'Print'                       => 'Drucken',
@@ -2957,6 +2954,11 @@ $self->{texts} = {
   'The price rule has been saved.' => 'Die Preisregel wurde gespeichert.',
   'The price rule is not a rule for discounts' => 'Die Preisregel ist keine Regel für Rabatte',
   'The price rule is not a rule for prices' => 'Die Preisregel ist keine Regel für Preise',
+  'The pricegroup has been created.' => 'Die Preisgruppe wurde erstellt.',
+  'The pricegroup has been deleted.' => 'Die Preisgruppe wurde gelöscht.',
+  'The pricegroup has been saved.' => 'Die Preisgruppe wurde gespeichert.',
+  'The pricegroup has been used and cannot be deleted.' => 'Die Preisgruppe wurde bereits verwendet und kann nicht gelöscht werden.',
+  'The pricegroup is being used by customers.' => 'Die Preisgruppe wird von Kunden verwendet.',
   'The printer could not be deleted.' => 'Der Drucker konnte nicht gelöscht werden.',
   'The printer has been created.' => 'Der Drucker wurde angelegt.',
   'The printer has been deleted.' => 'Der Drucker wurde entfernt.',
index 485cd82..5f2af65 100644 (file)
   id: system_pricegroups
   name: Pricegroups
   order: 1000
-  module: pe.pl
   params:
-    action: search
-    type: pricegroup
+    action: Pricegroup/list
 - parent: system
   id: system_edit_units
   name: Edit units
diff --git a/sql/Pg-upgrade2/pricegroup_sortkey_obsolete.sql b/sql/Pg-upgrade2/pricegroup_sortkey_obsolete.sql
new file mode 100644 (file)
index 0000000..dc6b331
--- /dev/null
@@ -0,0 +1,13 @@
+-- @tag: pricegroup_sortkey_obsolete
+-- @description: Sortierreihenfolge und ungültig für Preisgruppen
+-- @charset: UTF-8
+-- @depends: release_3_4_1
+-- @ignore: 0
+
+ALTER TABLE pricegroup ADD COLUMN obsolete BOOLEAN DEFAULT FALSE;
+ALTER TABLE pricegroup ADD COLUMN sortkey INTEGER;
+
+CREATE SEQUENCE tmp_counter;
+UPDATE pricegroup SET sortkey = nextval('tmp_counter');
+DROP SEQUENCE tmp_counter;
+ALTER TABLE pricegroup ALTER COLUMN sortkey SET NOT NULL;
diff --git a/templates/webpages/pe/pricegroup_form.html b/templates/webpages/pe/pricegroup_form.html
deleted file mode 100644 (file)
index 850275f..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-[%- USE L %]
-[%- USE T8 %]
-[%- USE HTML %]
-<h1>[% title %]</h1>
-[% L.javascript_tag('show_history.js') %]
-
-<form method=post action="[% script %]">
-
-<input type=hidden name=id value="[% id %]">
-<input type=hidden name=type value="[% type %]">
-
-<table width=100%>
-  <tr>
-    <td>
-      <table width=100%>
-        <tr>
-          <th align=right>[% 'Pricegroup' | $T8 %]</th>
-          <td><input name=pricegroup size=30 value="[% pricegroup | html %]"></td>
-        </tr>
-      </table>
-    </td>
-  </tr>
-  <tr>
-    <td colspan=2><hr size=3 noshade></td>
-  </tr>
-</table>
-
-<br>
-
-<input name=callback type=hidden value="[% callback | html %]">
-<input type=submit class=submit name=action value="[% 'Save' | $T8 %]">
-[%- IF id && orphaned %]
-<input type=submit class=submit name=action value="[% 'Delete' | $T8 %]">
-[%- END %]
-
-[%- IF ( id ) %]
-  <input type=button onclick="set_history_window([% id %], 'id');" name=history id=history value="[% 'history' | $T8 %]">
-[%- END %]
-
-</form>
-
diff --git a/templates/webpages/pe/pricegroup_report.html b/templates/webpages/pe/pricegroup_report.html
deleted file mode 100644 (file)
index 0b04b9d..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-[%- USE HTML %]
-[%- USE T8 %]
-<h1>[% 'Pricegroup' | $T8 %]</h1>
-
-<table width=100%>
-  <tr>
-    <td>[% option %]</td>
-  </tr>
-  <tr>
-    <td>
-      <table width=100%>
-        <tr class=listheading>
-          <th class=listheading width=90%>[% 'Pricegroup' | $T8 %]</th>
-        </tr>
-[%- FOREACH row = item_list %]
-        <tr valign=top class="listrow[% loop.count % 2 %]">
-          <td><a href="[% editlink %]&id=[% row.id %]">[% row.pricegroup %]</a></td>
-        </tr>
-[%- END %]
-      </table>
-    </td>
-  </tr>
-  <tr>
-    <td><hr size=3 noshade></td>
-  </tr>
-</table>
-
-<br>
-<form method=post action="[% script %]">
-  <input name=callback type=hidden value="[% callback | html %]">
-  <input type=hidden name=type value="[% type %]">
-  <input class=submit type=submit name=action value="[% 'Add' | $T8 %]">
-</form>
-
-
diff --git a/templates/webpages/pricegroup/form.html b/templates/webpages/pricegroup/form.html
new file mode 100644 (file)
index 0000000..7552caa
--- /dev/null
@@ -0,0 +1,50 @@
+[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%]
+
+[% SET style="width: 400px" %]
+[% SET size=15 %]
+
+<h1>[% HTML.escape(title) %]</h1>
+
+<form action="controller.pl" method="post">
+
+[%- INCLUDE 'common/flash.html' %]
+
+[%- L.hidden_tag("id", SELF.pricegroup.id) %]
+
+<table>
+  <tr>
+    <th align="right">[% 'Description' | $T8 %]</th>
+    <td>
+       [%- L.input_tag("pricegroup.pricegroup", SELF.pricegroup.pricegroup) %]
+   </td>
+  [% IF SELF.pricegroup.id %]
+  <tr>
+    <th align="right">[% 'Obsolete' | $T8 %]</th>
+    <td>[% L.checkbox_tag('pricegroup.obsolete', checked = SELF.pricegroup.obsolete, for_submit=1) %]</td>
+  </tr>
+  </tr>
+  [% END %]
+</table>
+
+ <p>
+  [% L.hidden_tag("action", "Pricegroup/dispatch") %]
+  [% L.submit_tag("action_" _  (SELF.pricegroup.id ? "update" : "create"), LxERP.t8('Save'), onclick="return check_prerequisites();") %]
+  [%- IF SELF.pricegroup.id AND SELF.pricegroup.orphaned -%]
+    [% L.submit_tag("action_delete", LxERP.t8('Delete')) %]
+  [%- END %]
+  <a href="[% SELF.url_for(action='list') %]">[%- LxERP.t8("Cancel") %]</a>
+ </p>
+
+ <hr>
+
+<script type="text/javascript">
+<!--
+function check_prerequisites() {
+  if ($('#pricegroup_pricegroup').val() === "") {
+    alert(kivi.t8('The description is missing.'));
+    return false;
+  }
+  return true;
+}
+-->
+</script>
diff --git a/templates/webpages/pricegroup/list.html b/templates/webpages/pricegroup/list.html
new file mode 100644 (file)
index 0000000..3584a5b
--- /dev/null
@@ -0,0 +1,33 @@
+[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%][%- INCLUDE 'common/flash.html' %]
+
+<h1>[% title %]</h1>
+
+<p>
+ <table width="100%" id="pricegroup_list">
+  <thead>
+   <tr class="listheading">
+    <th align="center" width="1%"><img src="image/updown.png" alt="[ LxERP.t8('reorder item') %]"></th>
+    <th>[% 'Description' | $T8 %]</th>
+    <th>[% 'Obsolete'    | $T8 %]</th>
+   </tr>
+  </thead>
+
+  <tbody>
+   [%- FOREACH pricegroup = SELF.all_pricegroups %]
+    <tr class="listrow" id="pricegroup_id_[% pricegroup.id %]">
+     <td align="center" class="dragdrop"><img src="image/updown.png" alt="[ LxERP.t8('reorder item') %]"></td>
+     <td><a href="[% SELF.url_for(action='edit', id=pricegroup.id) %]">[% HTML.escape(pricegroup.pricegroup) %]</a></td>
+     <td>[% HTML.escape(pricegroup.obsolete) %]</a></td>
+    </tr>
+   [%- END %]
+  </tbody>
+ </table>
+</p>
+
+<hr height="3">
+
+[% L.sortable_element('#pricegroup_list tbody', url=SELF.url_for(action='reorder'), with='pricegroup_id') %]
+
+<p>
+ <a href="[% SELF.url_for(action='new') %]">[%- 'Add' | $T8 %]</a>
+</p>