Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 916003e3

Von Moritz Bunkus vor fast 8 Jahren hinzugefügt

  • ID 916003e3c1f8edc11b79b283252aadbc59ac8757
  • Vorgänger 3b05e65a
  • Nachfolger 945bae4c

SimpleSystemSetting: Controller für die ganzen trivialen CRUD-Masken im System-Menü

Die Masken und Controller für sehr viele der Einstellungen im
System-Menü folgenden Schema F: es sind simple CRUD-Controller.

Sinnvoller wäre es, diesen ganzen Code in einem einzigen CRUD-Controller
zu vereinheitlichen und die Unterschiede nur anhand eines übergebenen
Typen-Parameters auszudrücken. Genau hierfür ist der
SimpleSystemSetting-Controller gedacht, und er macht mit Unterstützung
für Preisgruppen den Anfang. Andere Typen folgen.

Unterschiede anzeigen:

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

  
3
use strict;
4

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

  
7
use SL::Helper::Flash;
8
use SL::Locale::String;
9
use SL::DB::Default;
10
use SL::DB::Manager::Pricegroup;
11

  
12
use Rose::Object::MakeMethods::Generic (
13
  scalar                  => [ qw(pricegroup) ],
14
  'scalar --get_set_init' => [ qw(all_pricegroups) ],
15
);
16

  
17
__PACKAGE__->run_before('check_auth');
18
__PACKAGE__->run_before('load_pricegroup', only => [ qw(edit update delete) ]);
19

  
20
#
21
# actions
22
#
23

  
24
sub action_list {
25
  my ($self) = @_;
26

  
27
  $self->render('pricegroup/list',
28
                title   => t8('Pricegroups'),
29
               );
30
}
31

  
32
sub action_new {
33
  my ($self) = @_;
34

  
35
  $self->pricegroup( SL::DB::Pricegroup->new );
36
  $self->render('pricegroup/form',
37
                 title => t8('Add pricegroup'),
38
               );
39
}
40

  
41
sub action_edit {
42
  my ($self) = @_;
43

  
44
  $self->render('pricegroup/form',
45
                 title   => t8('Edit pricegroup'),
46
                );
47
}
48

  
49
sub action_create {
50
  my ($self) = @_;
51

  
52
  $self->pricegroup( SL::DB::Pricegroup->new );
53
  $self->create_or_update;
54
}
55

  
56
sub action_update {
57
  my ($self) = @_;
58
  $self->create_or_update;
59
}
60

  
61
sub action_delete {
62
  my ($self) = @_;
63

  
64
  if ( !$self->pricegroup->orphaned ) {
65
    flash_later('error', $::locale->text('The pricegroup has been used and cannot be deleted.'));
66
  } elsif ( eval { $self->pricegroup->delete; 1; } ) {
67
    flash_later('info',  $::locale->text('The pricegroup has been deleted.'));
68
  } else {
69
    flash_later('error', $::locale->text('The pricegroup has been used and cannot be deleted.'));
70
  };
71
  $self->redirect_to(action => 'list');
72
}
73

  
74
sub action_reorder {
75
  my ($self) = @_;
76

  
77
  SL::DB::Pricegroup->reorder_list(@{ $::form->{pricegroup_id} || [] });
78
  $self->render(\'', { type => 'json' });
79
}
80

  
81
#
82
# filters
83
#
84

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

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

  
92
  $self->pricegroup( SL::DB::Pricegroup->new(id => $::form->{id})->load );
93
}
94

  
95
sub init_all_pricegroups { SL::DB::Manager::Pricegroup->get_all_sorted }
96

  
97
#
98
# helpers
99
#
100

  
101
sub create_or_update {
102
  my ($self) = @_;
103
  my $is_new = !$self->pricegroup->id;
104

  
105
  my $params = delete($::form->{pricegroup}) || { };
106

  
107
  $self->pricegroup->assign_attributes(%{ $params });
108

  
109
  my @errors = $self->pricegroup->validate;
110

  
111
  if (@errors) {
112
    flash('error', @errors);
113
    $self->render('pricegroup/form',
114
                   title => $is_new ? t8('Add pricegroup') : t8('Edit pricegroup'),
115
                 );
116
    return;
117
  }
118

  
119
  $self->pricegroup->save;
120

  
121
  flash_later('info', $is_new ? t8('The pricegroup has been created.') : t8('The pricegroup has been saved.'));
122
  $self->redirect_to(action => 'list');
123
}
124

  
125
1;
126

  
127
__END__
128

  
129
=encoding utf-8
130

  
131
=head1 NAME
132

  
133
SL::Controller::Pricegroup - CRUD controller for pricegroups
134

  
135
=head1 SYNOPSIS
136

  
137
A new controller to create / edit / delete pricegroups.
138

  
139
Pricegroups can only be deleted if they haven't been used anywhere.
140

  
141
=head1 OBSOLETE PRICEGROUPS
142

  
143
Pricegroups can't be obsoleted while any of the customers still use that
144
pricegroup as their default pricegroup. Obsoleting a pricegroup means it can't
145
be selected when editing customers and it can't be selected as a price source
146
for new records.
147

  
148
=head1 AUTHOR
149

  
150
G. Richardson E<lt>grichardson@kivitendo-premium.deE<gt>
151

  
152
=cut
SL/Controller/SimpleSystemSetting.pm
1
package SL::Controller::SimpleSystemSetting;
2

  
3
use strict;
4
use utf8;
5

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

  
8
use SL::Helper::Flash;
9
use SL::Locale::String;
10
use SL::DB::Default;
11
use SL::System::Process;
12

  
13
use Rose::Object::MakeMethods::Generic (
14
  scalar                  => [ qw(type config) ],
15
  'scalar --get_set_init' => [ qw(defaults object all_objects class manager_class list_attributes list_url supports_reordering) ],
16
);
17

  
18
__PACKAGE__->run_before('check_type_and_auth');
19
__PACKAGE__->run_before('setup_javascript', only => [ qw(add create edit update delete) ]);
20

  
21
# Make locales.pl happy: $self->render("simple_system_setting/_default_form")
22

  
23
my %supported_types = (
24
  pricegroup => {
25
    # Make locales.pl happy: $self->render("simple_system_setting/_pricegroup_form")
26
    class  => 'Pricegroup',
27
    titles => {
28
      list => t8('Pricegroups'),
29
      add  => t8('Add pricegroup'),
30
      edit => t8('Edit pricegroup'),
31
    },
32
    list_attributes => [
33
      { method => 'pricegroup', title => t8('Description') },
34
      { method => 'obsolete',   title => t8('Obsolete'), formatter => sub { $_[0]->obsolete ? t8('yes') : t8('no') } },
35
    ],
36
  },
37
);
38

  
39
my @default_list_attributes = (
40
  { method => 'description', title => t8('Description') },
41
);
42

  
43
#
44
# actions
45
#
46

  
47
sub action_list {
48
  my ($self) = @_;
49

  
50
  $self->render('simple_system_setting/list', title => $self->config->{titles}->{list});
51
}
52

  
53
sub action_new {
54
  my ($self) = @_;
55

  
56
  $self->object($self->class->new);
57
  $self->render_form(title => $self->config->{titles}->{add});
58
}
59

  
60
sub action_edit {
61
  my ($self) = @_;
62

  
63
  $self->render_form(title => $self->config->{titles}->{edit});
64
}
65

  
66
sub action_create {
67
  my ($self) = @_;
68

  
69
  $self->object($self->class->new);
70
  $self->create_or_update;
71
}
72

  
73
sub action_update {
74
  my ($self) = @_;
75

  
76
  $self->create_or_update;
77
}
78

  
79
sub action_delete {
80
  my ($self) = @_;
81

  
82
  if ($self->object->can('orphaned') && !$self->object->orphaned) {
83
    flash_later('error', t8('The object is in use and cannot be deleted.'));
84

  
85
  } elsif ( eval { $self->object->delete; 1; } ) {
86
    flash_later('info',  t8('The object has been deleted.'));
87

  
88
  } else {
89
    flash_later('error', t8('The object is in use and cannot be deleted.'));
90
  }
91

  
92
  $self->redirect_to($self->list_url);
93
}
94

  
95
sub action_reorder {
96
  my ($self) = @_;
97

  
98
  $self->class->reorder_list(@{ $::form->{object_id} || [] });
99
  $self->render(\'', { type => 'json' });
100
}
101

  
102
#
103
# filters
104
#
105

  
106
sub check_type_and_auth {
107
  my ($self) = @_;
108

  
109
  $self->type($::form->{type});
110
  $self->config($supported_types{$self->type}) || die "Unsupported type";
111

  
112
  $::auth->assert($self->config->{auth} || 'config');
113

  
114
  my $pm = (map { s{::}{/}g; "${_}.pm" } $self->class)[0];
115
  require $pm;
116

  
117
  my $setup = "setup_" . $self->type;
118
  $self->$setup if $self->can($setup);
119

  
120
  1;
121
}
122

  
123
sub setup_javascript {
124
  $::request->layout->use_javascript("${_}.js") for qw(ckeditor/ckeditor ckeditor/adapters/jquery);
125
}
126

  
127
sub init_class               { "SL::DB::"          . $_[0]->config->{class}                  }
128
sub init_manager_class       { "SL::DB::Manager::" . $_[0]->config->{class}                  }
129
sub init_object              { $_[0]->class->new(id => $::form->{id})->load                  }
130
sub init_all_objects         { $_[0]->manager_class->get_all_sorted                          }
131
sub init_list_url            { $_[0]->url_for(action => 'list', type => $_[0]->type)         }
132
sub init_supports_reordering { $_[0]->class->new->can('reorder_list')                        }
133
sub init_defaults            { SL::DB::Default->get                                          }
134

  
135
sub init_list_attributes {
136
  my ($self) = @_;
137

  
138
  my $method = "list_attributes_" . $self->type;
139

  
140
  return $self->$method if $self->can($method);
141
  return $self->config->{list_attributes} // \@default_list_attributes;
142
}
143

  
144
#
145
# helpers
146
#
147

  
148
sub create_or_update {
149
  my ($self) = @_;
150
  my $is_new = !$self->object->id;
151

  
152
  my $params = delete($::form->{object}) || { };
153

  
154
  $self->object->assign_attributes(%{ $params });
155

  
156
  my @errors;
157

  
158
  push @errors, $self->object->validate if $self->object->can('validate');
159

  
160
  if (@errors) {
161
    flash('error', @errors);
162
    return $self->render_form(title => $self->config->{titles}->{$is_new ? 'add' : 'edit'});
163
  }
164

  
165
  $self->object->save;
166

  
167
  flash_later('info', $is_new ? t8('The object has been created.') : t8('The object has been saved.'));
168

  
169
  $self->redirect_to($self->list_url);
170
}
171

  
172
sub render_form {
173
  my ($self, %params) = @_;
174

  
175
  my $sub_form_template = SL::System::Process->exe_dir . '/templates/webpages/simple_system_setting/_' . $self->type . '_form.html';
176

  
177
  $self->render(
178
    'simple_system_setting/form',
179
    %params,
180
    sub_form_template => (-f $sub_form_template ? $self->type : 'default'),
181
  );
182
}
183

  
184
#
185
# type-specific helper functions
186
#
187

  
188
1;
189

  
190
__END__
191

  
192
=encoding utf-8
193

  
194
=head1 NAME
195

  
196
SL::Controller::SimpleSystemSettings — a common CRUD controller for
197
various settings in the "System" menu
198

  
199
=head1 AUTHOR
200

  
201
Moritz Bunkus <m.bunkus@linet-services.de>
202

  
203
=cut
locale/de/all
3059 3059
  'The next partnumber in the number range already exists!' => 'Die nächste Artikelnummer im Nummernkreis existiert schon!',
3060 3060
  'The number of days for full payment' => 'Die Anzahl Tage, bis die Rechnung in voller Höhe bezahlt werden muss',
3061 3061
  'The numbering will start at 1 with each requirement spec.' => 'Die Nummerierung beginnt bei jedem Pflichtenheft bei 1.',
3062
  'The object has been created.' => 'Das Objekt wurde angelegt.',
3063
  'The object has been deleted.' => 'Das Objekt wurde gelöscht..',
3064
  'The object has been saved.'  => 'Das Objekt wurde gespeichert.',
3065
  'The object is in use and cannot be deleted.' => 'Das Objekt ist in Benutzung und kann nicht gelöscht werden.',
3062 3066
  'The option field is empty.'  => 'Das Optionsfeld ist leer.',
3063 3067
  'The order has been deleted'  => 'Der Auftrag wurde gelöscht.',
3064 3068
  'The order has been saved'    => 'Der Auftrag wurde gespeichert.',
......
3098 3102
  'The price rule has been saved.' => 'Die Preisregel wurde gespeichert.',
3099 3103
  'The price rule is not a rule for discounts' => 'Die Preisregel ist keine Regel für Rabatte',
3100 3104
  'The price rule is not a rule for prices' => 'Die Preisregel ist keine Regel für Preise',
3101
  'The pricegroup has been created.' => 'Die Preisgruppe wurde erstellt.',
3102
  'The pricegroup has been deleted.' => 'Die Preisgruppe wurde gelöscht.',
3103
  'The pricegroup has been saved.' => 'Die Preisgruppe wurde gespeichert.',
3104
  'The pricegroup has been used and cannot be deleted.' => 'Die Preisgruppe wurde bereits verwendet und kann nicht gelöscht werden.',
3105 3105
  'The pricegroup is being used by customers.' => 'Die Preisgruppe wird von Kunden verwendet.',
3106 3106
  'The printer could not be deleted.' => 'Der Drucker konnte nicht gelöscht werden.',
3107 3107
  'The printer has been created.' => 'Der Drucker wurde angelegt.',
menus/user/00-erp.yaml
1084 1084
  name: Pricegroups
1085 1085
  order: 1120
1086 1086
  params:
1087
    action: Pricegroup/list
1087
    action: SimpleSystemSetting/list
1088
    type: pricegroup
1088 1089
- parent: system
1089 1090
  id: system_edit_units
1090 1091
  name: Edit units
templates/webpages/pricegroup/form.html
1
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%]
2

  
3
[% SET style="width: 400px" %]
4
[% SET size=15 %]
5

  
6
<h1>[% HTML.escape(title) %]</h1>
7

  
8
<form action="controller.pl" method="post">
9

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

  
12
[%- L.hidden_tag("id", SELF.pricegroup.id) %]
13

  
14
<table>
15
  <tr>
16
    <th align="right">[% 'Description' | $T8 %]</th>
17
    <td>
18
       [%- L.input_tag("pricegroup.pricegroup", SELF.pricegroup.pricegroup) %]
19
   </td>
20
  [% IF SELF.pricegroup.id %]
21
  <tr>
22
    <th align="right">[% 'Obsolete' | $T8 %]</th>
23
    <td>[% L.checkbox_tag('pricegroup.obsolete', checked = SELF.pricegroup.obsolete, for_submit=1) %]</td>
24
  </tr>
25
  </tr>
26
  [% END %]
27
</table>
28

  
29
 <p>
30
  [% L.hidden_tag("action", "Pricegroup/dispatch") %]
31
  [% L.submit_tag("action_" _  (SELF.pricegroup.id ? "update" : "create"), LxERP.t8('Save'), onclick="return check_prerequisites();") %]
32
  [%- IF SELF.pricegroup.id AND SELF.pricegroup.orphaned -%]
33
    [% L.submit_tag("action_delete", LxERP.t8('Delete')) %]
34
  [%- END %]
35
  <a href="[% SELF.url_for(action='list') %]">[%- LxERP.t8("Cancel") %]</a>
36
 </p>
37

  
38
 <hr>
39

  
40
<script type="text/javascript">
41
<!--
42
function check_prerequisites() {
43
  if ($('#pricegroup_pricegroup').val() === "") {
44
    alert(kivi.t8('The description is missing.'));
45
    return false;
46
  }
47
  return true;
48
}
49
-->
50
</script>
templates/webpages/pricegroup/list.html
1
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%][%- INCLUDE 'common/flash.html' %]
2

  
3
<h1>[% title %]</h1>
4

  
5
<p>
6
 <table width="100%" id="pricegroup_list">
7
  <thead>
8
   <tr class="listheading">
9
    <th align="center" width="1%"><img src="image/updown.png" alt="[ LxERP.t8('reorder item') %]"></th>
10
    <th>[% 'Description' | $T8 %]</th>
11
    <th>[% 'Obsolete'    | $T8 %]</th>
12
   </tr>
13
  </thead>
14

  
15
  <tbody>
16
   [%- FOREACH pricegroup = SELF.all_pricegroups %]
17
    <tr class="listrow" id="pricegroup_id_[% pricegroup.id %]">
18
     <td align="center" class="dragdrop"><img src="image/updown.png" alt="[ LxERP.t8('reorder item') %]"></td>
19
     <td><a href="[% SELF.url_for(action='edit', id=pricegroup.id) %]">[% HTML.escape(pricegroup.pricegroup) %]</a></td>
20
     <td>[% HTML.escape(pricegroup.obsolete) %]</a></td>
21
    </tr>
22
   [%- END %]
23
  </tbody>
24
 </table>
25
</p>
26

  
27
<hr height="3">
28

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

  
31
<p>
32
 <a href="[% SELF.url_for(action='new') %]">[%- 'Add' | $T8 %]</a>
33
</p>
templates/webpages/simple_system_setting/_default_form.html
1
[%- USE LxERP -%][%- USE L -%]
2
<table>
3
 <tr>
4
  <th align="right">[% LxERP.t8("Description") %]</th>
5
  <td>[% L.input_tag("object.description", LxERP.t8(SELF.object.description), "data-validate"="required", "data-title"=LxERP.t8("Description")) %]</td>
6
 </tr>
7
</table>
templates/webpages/simple_system_setting/_pricegroup_form.html
1
[%- USE LxERP -%][%- USE L -%]
2
<table>
3
 <tr>
4
  <th align="right">[% LxERP.t8("Description") %]</th>
5
  <td>
6
   [%- L.input_tag("object.pricegroup", SELF.object.pricegroup, "data-validate"="required", "data-title"=LxERP.t8("Description")) %]
7
  </td>
8
 </tr>
9
 <tr>
10
  <th align="right">[% LxERP.t8("Obsolete") %]</th>
11
  <td>[% L.checkbox_tag("object.obsolete", checked=SELF.object.obsolete, for_submit=1) %]</td>
12
 </tr>
13
</table>
templates/webpages/simple_system_setting/form.html
1
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%]
2

  
3
[% SET style="width: 400px" %]
4
[% SET size=15 %]
5

  
6
<h1>[% HTML.escape(title) %]</h1>
7

  
8
[%- INCLUDE "common/flash.html" %]
9

  
10
<form action="controller.pl" method="post" id="form">
11

  
12
 [%- L.hidden_tag("type", SELF.type) %]
13
 [%- L.hidden_tag("id", SELF.object.id) %]
14

  
15
 [%- SET sub_file = "simple_system_setting/_" _ sub_form_template _ "_form.html";
16
     INCLUDE $sub_file %]
17

  
18
 <p>
19
  [% L.hidden_tag("action", "SimpleSystemSetting/dispatch") %]
20
  [% L.submit_tag("action_" _  (SELF.object.id ? "update" : "create"), LxERP.t8("Save"), onclick="return kivi.validate_form('#form');") %]
21
  [%- IF SELF.object.id && (!SELF.object.can("orphaned") || SELF.object.orphaned) -%]
22
    [% L.submit_tag("action_delete", LxERP.t8("Delete"), confirm=LxERP.t8("Do you really want to delete this object?")) %]
23
  [%- END %]
24
  <a href="[% SELF.list_url %]">[%- LxERP.t8("Cancel") %]</a>
25
 </p>
26
</form>
templates/webpages/simple_system_setting/list.html
1
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%]
2

  
3
<h1>[% HTML.escape(title) %]</h1>
4

  
5
[%- INCLUDE 'common/flash.html' %]
6

  
7
<table width="100%" id="object_list">
8
 <thead>
9
  <tr class="listheading">
10
   [% IF SELF.supports_reordering %]
11
    <th align="center" width="1%"><img src="image/updown.png" alt="[ LxERP.t8('reorder item') %]"></th>
12
   [% END %]
13
   [% FOREACH attribute = SELF.list_attributes %]
14
    <th[% IF attribute.align %] align="[% attribute.align %]"[% END %]>[% HTML.escape(attribute.title) %]</th>
15
   [% END %]
16
  </tr>
17
 </thead>
18

  
19
 <tbody>
20
  [%- FOREACH object = SELF.all_objects %]
21
   <tr class="listrow" id="object_id_[% object.id %]">
22
   [% IF SELF.supports_reordering %]
23
    <td align="center" class="dragdrop">[% L.img_tag(src="image/updown.png", alt=LxERP.t8("reorder item")) %]</td>
24
   [% END %][%# IF SELF.supports_reordering %]
25
   [% FOREACH attribute = SELF.list_attributes %]
26
    <td[% IF attribute.align %] align="[% attribute.align %]"[% END %]>
27
     [% IF loop.count == 1 %]
28
      <a href="[% SELF.url_for(action='edit', type=SELF.type, id=object.id) %]">
29
     [% END %][%# IF loop.count == 0 %]
30
     [% SET method = attribute.method
31
            value  = attribute.exists('formatter') ? attribute.formatter(object) : object.$method ;
32
        HTML.escape(value) %]
33
     [% IF loop.count == 1 %]
34
      </a>
35
     [% END %][%# IF loop.count == 0 %]
36
    </td>
37
   [% END %][%# FOREACH attribute… %]
38
   </tr>
39
  [%- END %][%# FOREACH object… %]
40
 </tbody>
41
</table>
42

  
43
<hr height="3">
44

  
45
<p>
46
 <a href="[% SELF.url_for(action="new", type=SELF.type) %]">[%- "Add" | $T8 %]</a>
47
</p>
48

  
49
[% IF SELF.supports_reordering %]
50
[% L.sortable_element("#object_list tbody", url=SELF.url_for(action="reorder", type=SELF.type), with="object_id") %]
51
[% END %]

Auch abrufbar als: Unified diff