Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 405a41ef

Von Moritz Bunkus vor mehr als 10 Jahren hinzugefügt

  • ID 405a41ef0836ac972a3ebb9e99f05de7d13d4275
  • Vorgänger c19b1e03
  • Nachfolger 48aa4607

Pflichtenhefte: Kopieren (clonen) generell und Löschen aus Kontextmenü implementiert

Unterschiede anzeigen:

SL/Controller/RequirementSpec.pm
4 4

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

  
7
use Rose::DB::Object::Helpers;
8

  
7 9
use SL::ClientJS;
8 10
use SL::Controller::Helper::GetModels;
9 11
use SL::Controller::Helper::Paginated;
......
24 26
use Rose::Object::MakeMethods::Generic
25 27
(
26 28
  scalar                  => [ qw(requirement_spec_item customers types statuses db_args flat_filter is_template visible_item visible_section) ],
27
  'scalar --get_set_init' => [ qw(requirement_spec complexities risks projects) ],
29
  'scalar --get_set_init' => [ qw(requirement_spec complexities risks projects copy_source) ],
28 30
);
29 31

  
30 32
__PACKAGE__->run_before('setup');
31 33
__PACKAGE__->run_before('load_select_options',  only => [ qw(new ajax_edit create update list) ]);
32 34

  
35

  
33 36
__PACKAGE__->get_models_url_params('flat_filter');
34 37
__PACKAGE__->make_paginated(
35 38
  MODEL         => 'RequirementSpec',
......
73 76
  my ($self) = @_;
74 77

  
75 78
  $self->requirement_spec(SL::DB::RequirementSpec->new);
79

  
80
  if ($self->copy_source) {
81
    $self->requirement_spec->$_($self->copy_source->$_) for qw(type_id status_id customer_id title hourly_rate)
82
  }
83

  
76 84
  $self->render('requirement_spec/new', title => t8('Create a new requirement spec'));
77 85
}
78 86

  
......
212 220
  $self->requirement_spec(SL::DB::RequirementSpec->new(id => $::form->{id})->load || die "No such requirement spec") if $::form->{id};
213 221
}
214 222

  
223
sub init_copy_source {
224
  my ($self) = @_;
225
  $self->copy_source(SL::DB::RequirementSpec->new(id => $::form->{copy_source_id})->load) if $::form->{copy_source_id};
226
}
227

  
215 228
sub load_select_options {
216 229
  my ($self) = @_;
217 230

  
......
245 258
    return;
246 259
  }
247 260

  
248
  $self->requirement_spec->save;
261
  my $db = $self->requirement_spec->db;
262
  if (!$db->do_transaction(sub {
263
    if ($self->copy_source) {
264
      $self->requirement_spec($self->copy_source->create_copy(%{ $params }));
265
    } else {
266
      $self->requirement_spec->save;
267
    }
268
  })) {
269
    $::lxdebug->message(LXDebug::WARN(), "Error: " . $db->error);
270
    @errors = ($::locale->text('Saving failed. Erro message from the database: #1'), $db->error);
271
    return SL::ClientJS->new->error(@errors)->render($self) if $::request->is_ajax;
272

  
273
    $self->requirement_spec->id(undef) if $is_new;
274
    flash('error', @errors);
275
    return $self->render('requirement_spec/new', title => $title);
276
  }
249 277

  
250 278
  if ($::request->is_ajax) {
251 279
    my $html = $self->render('requirement_spec/_header', { output => 0 });
SL/DB/RequirementSpec.pm
3 3
use strict;
4 4

  
5 5
use Carp;
6
use Rose::DB::Object::Helpers;
6 7

  
7 8
use SL::DB::MetaSetup::RequirementSpec;
8 9
use SL::DB::Manager::RequirementSpec;
......
63 64
  return sprintf('%s: "%s"', $self->type->description, $self->title);
64 65
}
65 66

  
67
sub create_copy {
68
  my ($self, %params) = @_;
69

  
70
  return $self->_create_copy(%params) if $self->db->in_transaction;
71

  
72
  my $copy;
73
  if (!$self->db->do_transaction(sub { $copy = $self->_create_copy(%params) })) {
74
    $::lxdebug->message(LXDebug->WARN(), "create_copy failed: " . join("\n", (split(/\n/, $self->db->error))[0..2]));
75
    return undef;
76
  }
77

  
78
  return $copy;
79
}
80

  
81
sub _create_copy {
82
  my ($self, %params) = @_;
83

  
84
  my $copy = Rose::DB::Object::Helpers::clone_and_reset($self);
85
  $copy->assign_attributes(%params);
86

  
87
  # Clone text blocks.
88
  $copy->text_blocks(map { Rose::DB::Object::Helpers::clone_and_reset($_) } @{ $self->text_blocks });
89

  
90
  # Save new object -- we need its ID for the items.
91
  $copy->save;
92

  
93
  my %id_to_clone;
94

  
95
  # Clone items.
96
  my $clone_item;
97
  $clone_item = sub {
98
    my ($item) = @_;
99
    my $cloned = Rose::DB::Object::Helpers::clone_and_reset($item);
100
    $cloned->requirement_spec_id($copy->id);
101
    $cloned->children(map { $clone_item->($_) } @{ $item->children });
102

  
103
    $id_to_clone{ $item->id } = $cloned;
104

  
105
    return $cloned;
106
  };
107

  
108
  $copy->items(map { $clone_item->($_) } @{ $self->sections });
109

  
110
  # Save the items -- need to do that before setting dependencies.
111
  $copy->save;
112

  
113
  # Set dependencies.
114
  foreach my $item (@{ $self->items }) {
115
    next unless @{ $item->dependencies };
116
    $id_to_clone{ $item->id }->update_attributes(dependencies => [ map { $id_to_clone{$_->id} } @{ $item->dependencies } ]);
117
  }
118

  
119
  return $copy;
120
}
121

  
66 122
1;
js/locale/de.js
6 6
"Add text block":"Textblock erfassen",
7 7
"Are you sure?":"Sind Sie sicher?",
8 8
"Copy":"Kopieren",
9
"Copy requirement spec":"Pflichtenheft kopieren",
9 10
"Database Connection Test":"Test der Datenbankverbindung",
10
"Delete text block":"Textblock löschen",
11 11
"Delete":"Löschen",
12
"Delete requirement spec":"Pflichtenheft löschen",
13
"Delete text block":"Textblock löschen",
12 14
"Do you really want to cancel?":"Wollen Sie wirklich abbrechen?",
13 15
"Do you want to set the account number \"#1\" to \"#2\" and the name \"#3\" to \"#4\"?":"Soll die Kontonummer \"#1\" zu \"#2\" und den Name \"#3\" zu \"#4\" geändert werden?",
14 16
"Edit text block":"Textblock bearbeiten",
......
17 19
"Map":"Karte",
18 20
"Part picker":"Artikelauswahl",
19 21
"Paste":"Einfügen",
22
"Requirement spec actions:":"Pflichtenheftaktionen:",
20 23
"Save":"Speichern",
21 24
"The description is missing.":"Die Beschreibung fehlt.",
22 25
"The name is missing.":"Der Name fehlt.",
js/requirement_spec.js
290 290
  return true;
291 291
}
292 292

  
293
// -------------------------------------------------------------------------
294
// ---------------------------- general actions ----------------------------
295
// -------------------------------------------------------------------------
296

  
297
function download_reqspec_pdf(key, opt) {
298
  var data = {
299
    action: "RequirementSpec/download_pdf",
300
    id:     $('#requirement_spec_id').val()
301
  };
302
  $.download("controller.pl", data);
303
}
304

  
305
function copy_reqspec(key, opt) {
306
  window.location.href = "controller.pl?action=RequirementSpec/new&copy_source_id=" + encodeURIComponent($('#requirement_spec_id').val());
307
  return true;
308
}
309

  
310
function delete_reqspec(key, opt) {
311
  if (confirm(kivi.t8("Are you sure?")))
312
    window.location.href = "controller.pl?action=RequirementSpec/destroy&id=" + encodeURIComponent($('#requirement_spec_id').val());
313
  return true;
314
}
315

  
293 316
// -------------------------------------------------------------------------
294 317
// ----------------------------- context menus -----------------------------
295 318
// -------------------------------------------------------------------------
......
300 323
    hide: requirement_spec_text_block_popup_menu_hidden
301 324
  };
302 325

  
326
  var general_actions = {
327
      sep98:           "---------"
328
    , general_actions: { name: kivi.t8('Requirement spec actions:') }
329
    , sep99:           "---------"
330
    , copy_reqspec:    { name: kivi.t8('Copy requirement spec'),   icon: "copy",   callback: copy_reqspec   }
331
    , delete_reqspec:  { name: kivi.t8('Delete requirement spec'), icon: "delete", callback: delete_reqspec }
332
  };
333

  
303 334
  $.contextMenu({
304 335
    selector: '.text-block-context-menu',
305 336
    events:   {
306 337
        show: requirement_spec_text_block_popup_menu_shown
307 338
      , hide: requirement_spec_text_block_popup_menu_hidden
308 339
    },
309
    items:    {
310
        add:    { name: kivi.t8('Add text block'),    icon: "add",    callback: standard_text_block_ajax_call }
311
      , edit:   { name: kivi.t8('Edit text block'),   icon: "edit",   callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
312
      , delete: { name: kivi.t8('Delete text block'), icon: "delete", callback: ask_delete_text_block,         disabled: disable_edit_text_block_commands }
313
      , sep1:   "---------"
314
      , flag:   { name: kivi.t8('Toggle marker'),     icon: "flag",   callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
315
      , sep2:   "---------"
316
      , copy:   { name: kivi.t8('Copy'),              icon: "copy",   callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
317
      , paste:  { name: kivi.t8('Paste'),             icon: "paste",  callback: standard_text_block_ajax_call  }
318
    }
340
    items:    $.extend({
341
        add:     { name: kivi.t8('Add text block'),        icon: "add",    callback: standard_text_block_ajax_call }
342
      , edit:    { name: kivi.t8('Edit text block'),       icon: "edit",   callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
343
      , delete:  { name: kivi.t8('Delete text block'),     icon: "delete", callback: ask_delete_text_block,         disabled: disable_edit_text_block_commands }
344
      , sep1:    "---------"
345
      , flag:    { name: kivi.t8('Toggle marker'),         icon: "flag",   callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
346
      , sep2:    "---------"
347
      , copy:    { name: kivi.t8('Copy'),                  icon: "copy",   callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
348
      , paste:   { name: kivi.t8('Paste'),                 icon: "paste",  callback: standard_text_block_ajax_call  }
349
    }, general_actions)
319 350
  });
320 351

  
321 352
  var events = {
......
326 357
  $.contextMenu({
327 358
    selector: '.section-context-menu',
328 359
    events:   events,
329
    items:    {
360
    items:    $.extend({
330 361
        add_section:        { name: kivi.t8('Add section'),        icon: "add",    callback: standard_item_ajax_call }
331 362
      , add_function_block: { name: kivi.t8('Add function block'), icon: "add",    callback: standard_item_ajax_call, disabled: disable_add_function_block_command }
332 363
      , sep1:               "---------"
......
337 368
      , sep3:               "---------"
338 369
      , copy:               { name: kivi.t8('Copy'),               icon: "copy",   callback: standard_item_ajax_call, disabled: disable_edit_item_commands }
339 370
      , paste:              { name: kivi.t8('Paste'),              icon: "paste",  callback: standard_item_ajax_call }
340
    }
371
    }, general_actions)
341 372
  });
342 373

  
343 374
  $.contextMenu({
344 375
    selector: '.function-block-context-menu,.sub-function-block-context-menu',
345 376
    events:   events,
346
    items:    {
377
    items:    $.extend({
347 378
        add_function_block:     { name: kivi.t8('Add function block'),     icon: "add",    callback: standard_item_ajax_call }
348 379
      , add_sub_function_block: { name: kivi.t8('Add sub function block'), icon: "add",    callback: standard_item_ajax_call }
349 380
      , sep1:                   "---------"
......
354 385
      , sep3:                   "---------"
355 386
      , copy:                   { name: kivi.t8('Copy'),                   icon: "copy",   callback: standard_item_ajax_call, disabled: disable_edit_item_commands }
356 387
      , paste:                  { name: kivi.t8('Paste'),                  icon: "paste",  callback: standard_item_ajax_call }
357
    }
388
    }, general_actions)
358 389
  });
359 390

  
360 391
  $.contextMenu({
361 392
    selector: '.time-cost-estimate-context-menu',
362 393
    events:   events,
363
    items:    { edit: { name: kivi.t8('Edit'), icon: "edit", callback: standard_time_cost_estimate_ajax_call } }
394
    items:    $.extend({ edit: { name: kivi.t8('Edit'), icon: "edit", callback: standard_time_cost_estimate_ajax_call } }, general_actions)
364 395
  });
365 396

  
366 397
  $.contextMenu({
367 398
    selector: '.edit-time-cost-estimate-context-menu',
368 399
    events:   events,
369
    items:    {
400
    items:    $.extend({
370 401
        save:   { name: kivi.t8('Save'),   icon: "save",  callback: standard_time_cost_estimate_ajax_call }
371 402
      , cancel: { name: kivi.t8('Cancel'), icon: "close", callback: standard_time_cost_estimate_ajax_call }
372
    }
403
    }, general_actions)
373 404
  });
374 405
}
locale/de/all
513 513
  'Copies'                      => 'Kopien',
514 514
  'Copy file from #1 to #2 failed: #3' => 'Kopieren der Datei von #1 nach #2 schlug fehl: #3',
515 515
  'Copy'                        => 'Kopieren',
516
  'Copy requirement spec'       => 'Pflichtenheft kopieren',
516 517
  'Correct taxkey'              => 'Richtiger Steuerschlüssel',
517 518
  'Cost'                        => 'Kosten',
518 519
  'Costs'                       => 'Kosten',
......
714 715
  'Delete drafts'               => 'Entwürfe löschen',
715 716
  'Delete links'                => 'Verknüpfungen löschen',
716 717
  'Delete profile'              => 'Profil löschen',
718
  'Delete requirement spec'     => 'Pflichtenheft löschen',
717 719
  'Delete text block'           => 'Textblock löschen',
718 720
  'Delete transaction'          => 'Buchung löschen',
719 721
  'Deleted'                     => 'Gelöscht',
......
1847 1849
  'Requirement Spec Type'       => 'Pflichtenhefttyp',
1848 1850
  'Requirement Spec Types'      => 'Pflichtenhefttypen',
1849 1851
  'Requirement Specs'           => 'Pflichtenhefte',
1852
  'Requirement spec actions:'   => 'Pflichtenheftaktionen:',
1850 1853
  'Requirement spec function block #1 with #2 sub function blocks; description: "#3"' => 'Pflichtenheft-Funktionsblock #1 mit #2 Unterfunktionsblöcken; Beschreibung: "#3"',
1851 1854
  'Requirement spec section #1 "#2" with #3 function blocks and a total of #4 sub function blocks; preamble: "#5"' => 'Pflichtenheftabschnitt #1 "#2" mit #3 Funktionsblöcken und insgesamt #4 Unterfunktionsblöcken; Einleitung: "#5"',
1852 1855
  'Requirement spec sub function block #1; description: "#2"' => 'Pflichtenheft-Unterfunktionsblock #1; Beschreibung: "#2"',
......
1925 1928
  'Save draft'                  => 'Entwurf speichern',
1926 1929
  'Save profile'                => 'Profil speichern',
1927 1930
  'Save settings as'            => 'Einstellungen speichern unter',
1931
  'Saving failed. Erro message from the database: #1' => 'Speichern schlug fehl. Fehlermeldung der Datenbank: #1',
1928 1932
  'Saving the file \'%s\' failed. OS error message: %s' => 'Das Speichern der Datei \'%s\' schlug fehl. Fehlermeldung des Betriebssystems: %s',
1929 1933
  'Screen'                      => 'Bildschirm',
1930 1934
  'Search'                      => 'Suchen',
......
2302 2306
  'The name is missing.'        => 'Der Name fehlt.',
2303 2307
  'The name is not unique.'     => 'Der Name ist nicht eindeutig.',
2304 2308
  'The name must only consist of letters, numbers and underscores and start with a letter.' => 'Der Name darf nur aus Buchstaben (keine Umlaute), Ziffern und Unterstrichen bestehen und muss mit einem Buchstaben beginnen.',
2309
  'The new requirement spec will be a copy of \'#1\' for customer \'#2\'.' => 'Das neue Pflichtenheft wird eine Kopie von \'#1\' für Kunde \'#2\' sein.',
2305 2310
  'The number of days for full payment' => 'Die Anzahl Tage, bis die Rechnung in voller Höhe bezahlt werden muss',
2306 2311
  'The option field is empty.'  => 'Das Optionsfeld ist leer.',
2307 2312
  'The package name is invalid.' => 'Der Paketname ist ungültig.',
templates/webpages/requirement_spec/_form.html
34 34

  
35 35
 </table>
36 36

  
37
[%- IF SELF.copy_source %]
38
 [%- L.hidden_tag('copy_source_id', SELF.copy_source.id) %]
39

  
40
 <p>
41
  [%- LxERP.t8("The new requirement spec will be a copy of '#1' for customer '#2'.", SELF.copy_source.title, SELF.copy_source.customer.name) %]
42
 </p>
43
[%- END %]
44

  
37 45
 <p>
38 46
[% IF submit_as == 'post' %]
39 47
  [% L.hidden_tag("action", "RequirementSpec/dispatch", id=id_prefix _ '_action') %]

Auch abrufbar als: Unified diff