Revision 405a41ef
Von Moritz Bunkus vor fast 11 Jahren hinzugefügt
SL/Controller/RequirementSpec.pm | ||
---|---|---|
|
||
use parent qw(SL::Controller::Base);
|
||
|
||
use Rose::DB::Object::Helpers;
|
||
|
||
use SL::ClientJS;
|
||
use SL::Controller::Helper::GetModels;
|
||
use SL::Controller::Helper::Paginated;
|
||
... | ... | |
use Rose::Object::MakeMethods::Generic
|
||
(
|
||
scalar => [ qw(requirement_spec_item customers types statuses db_args flat_filter is_template visible_item visible_section) ],
|
||
'scalar --get_set_init' => [ qw(requirement_spec complexities risks projects) ],
|
||
'scalar --get_set_init' => [ qw(requirement_spec complexities risks projects copy_source) ],
|
||
);
|
||
|
||
__PACKAGE__->run_before('setup');
|
||
__PACKAGE__->run_before('load_select_options', only => [ qw(new ajax_edit create update list) ]);
|
||
|
||
|
||
__PACKAGE__->get_models_url_params('flat_filter');
|
||
__PACKAGE__->make_paginated(
|
||
MODEL => 'RequirementSpec',
|
||
... | ... | |
my ($self) = @_;
|
||
|
||
$self->requirement_spec(SL::DB::RequirementSpec->new);
|
||
|
||
if ($self->copy_source) {
|
||
$self->requirement_spec->$_($self->copy_source->$_) for qw(type_id status_id customer_id title hourly_rate)
|
||
}
|
||
|
||
$self->render('requirement_spec/new', title => t8('Create a new requirement spec'));
|
||
}
|
||
|
||
... | ... | |
$self->requirement_spec(SL::DB::RequirementSpec->new(id => $::form->{id})->load || die "No such requirement spec") if $::form->{id};
|
||
}
|
||
|
||
sub init_copy_source {
|
||
my ($self) = @_;
|
||
$self->copy_source(SL::DB::RequirementSpec->new(id => $::form->{copy_source_id})->load) if $::form->{copy_source_id};
|
||
}
|
||
|
||
sub load_select_options {
|
||
my ($self) = @_;
|
||
|
||
... | ... | |
return;
|
||
}
|
||
|
||
$self->requirement_spec->save;
|
||
my $db = $self->requirement_spec->db;
|
||
if (!$db->do_transaction(sub {
|
||
if ($self->copy_source) {
|
||
$self->requirement_spec($self->copy_source->create_copy(%{ $params }));
|
||
} else {
|
||
$self->requirement_spec->save;
|
||
}
|
||
})) {
|
||
$::lxdebug->message(LXDebug::WARN(), "Error: " . $db->error);
|
||
@errors = ($::locale->text('Saving failed. Erro message from the database: #1'), $db->error);
|
||
return SL::ClientJS->new->error(@errors)->render($self) if $::request->is_ajax;
|
||
|
||
$self->requirement_spec->id(undef) if $is_new;
|
||
flash('error', @errors);
|
||
return $self->render('requirement_spec/new', title => $title);
|
||
}
|
||
|
||
if ($::request->is_ajax) {
|
||
my $html = $self->render('requirement_spec/_header', { output => 0 });
|
SL/DB/RequirementSpec.pm | ||
---|---|---|
use strict;
|
||
|
||
use Carp;
|
||
use Rose::DB::Object::Helpers;
|
||
|
||
use SL::DB::MetaSetup::RequirementSpec;
|
||
use SL::DB::Manager::RequirementSpec;
|
||
... | ... | |
return sprintf('%s: "%s"', $self->type->description, $self->title);
|
||
}
|
||
|
||
sub create_copy {
|
||
my ($self, %params) = @_;
|
||
|
||
return $self->_create_copy(%params) if $self->db->in_transaction;
|
||
|
||
my $copy;
|
||
if (!$self->db->do_transaction(sub { $copy = $self->_create_copy(%params) })) {
|
||
$::lxdebug->message(LXDebug->WARN(), "create_copy failed: " . join("\n", (split(/\n/, $self->db->error))[0..2]));
|
||
return undef;
|
||
}
|
||
|
||
return $copy;
|
||
}
|
||
|
||
sub _create_copy {
|
||
my ($self, %params) = @_;
|
||
|
||
my $copy = Rose::DB::Object::Helpers::clone_and_reset($self);
|
||
$copy->assign_attributes(%params);
|
||
|
||
# Clone text blocks.
|
||
$copy->text_blocks(map { Rose::DB::Object::Helpers::clone_and_reset($_) } @{ $self->text_blocks });
|
||
|
||
# Save new object -- we need its ID for the items.
|
||
$copy->save;
|
||
|
||
my %id_to_clone;
|
||
|
||
# Clone items.
|
||
my $clone_item;
|
||
$clone_item = sub {
|
||
my ($item) = @_;
|
||
my $cloned = Rose::DB::Object::Helpers::clone_and_reset($item);
|
||
$cloned->requirement_spec_id($copy->id);
|
||
$cloned->children(map { $clone_item->($_) } @{ $item->children });
|
||
|
||
$id_to_clone{ $item->id } = $cloned;
|
||
|
||
return $cloned;
|
||
};
|
||
|
||
$copy->items(map { $clone_item->($_) } @{ $self->sections });
|
||
|
||
# Save the items -- need to do that before setting dependencies.
|
||
$copy->save;
|
||
|
||
# Set dependencies.
|
||
foreach my $item (@{ $self->items }) {
|
||
next unless @{ $item->dependencies };
|
||
$id_to_clone{ $item->id }->update_attributes(dependencies => [ map { $id_to_clone{$_->id} } @{ $item->dependencies } ]);
|
||
}
|
||
|
||
return $copy;
|
||
}
|
||
|
||
1;
|
js/locale/de.js | ||
---|---|---|
"Add text block":"Textblock erfassen",
|
||
"Are you sure?":"Sind Sie sicher?",
|
||
"Copy":"Kopieren",
|
||
"Copy requirement spec":"Pflichtenheft kopieren",
|
||
"Database Connection Test":"Test der Datenbankverbindung",
|
||
"Delete text block":"Textblock löschen",
|
||
"Delete":"Löschen",
|
||
"Delete requirement spec":"Pflichtenheft löschen",
|
||
"Delete text block":"Textblock löschen",
|
||
"Do you really want to cancel?":"Wollen Sie wirklich abbrechen?",
|
||
"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?",
|
||
"Edit text block":"Textblock bearbeiten",
|
||
... | ... | |
"Map":"Karte",
|
||
"Part picker":"Artikelauswahl",
|
||
"Paste":"Einfügen",
|
||
"Requirement spec actions:":"Pflichtenheftaktionen:",
|
||
"Save":"Speichern",
|
||
"The description is missing.":"Die Beschreibung fehlt.",
|
||
"The name is missing.":"Der Name fehlt.",
|
js/requirement_spec.js | ||
---|---|---|
return true;
|
||
}
|
||
|
||
// -------------------------------------------------------------------------
|
||
// ---------------------------- general actions ----------------------------
|
||
// -------------------------------------------------------------------------
|
||
|
||
function download_reqspec_pdf(key, opt) {
|
||
var data = {
|
||
action: "RequirementSpec/download_pdf",
|
||
id: $('#requirement_spec_id').val()
|
||
};
|
||
$.download("controller.pl", data);
|
||
}
|
||
|
||
function copy_reqspec(key, opt) {
|
||
window.location.href = "controller.pl?action=RequirementSpec/new©_source_id=" + encodeURIComponent($('#requirement_spec_id').val());
|
||
return true;
|
||
}
|
||
|
||
function delete_reqspec(key, opt) {
|
||
if (confirm(kivi.t8("Are you sure?")))
|
||
window.location.href = "controller.pl?action=RequirementSpec/destroy&id=" + encodeURIComponent($('#requirement_spec_id').val());
|
||
return true;
|
||
}
|
||
|
||
// -------------------------------------------------------------------------
|
||
// ----------------------------- context menus -----------------------------
|
||
// -------------------------------------------------------------------------
|
||
... | ... | |
hide: requirement_spec_text_block_popup_menu_hidden
|
||
};
|
||
|
||
var general_actions = {
|
||
sep98: "---------"
|
||
, general_actions: { name: kivi.t8('Requirement spec actions:') }
|
||
, sep99: "---------"
|
||
, copy_reqspec: { name: kivi.t8('Copy requirement spec'), icon: "copy", callback: copy_reqspec }
|
||
, delete_reqspec: { name: kivi.t8('Delete requirement spec'), icon: "delete", callback: delete_reqspec }
|
||
};
|
||
|
||
$.contextMenu({
|
||
selector: '.text-block-context-menu',
|
||
events: {
|
||
show: requirement_spec_text_block_popup_menu_shown
|
||
, hide: requirement_spec_text_block_popup_menu_hidden
|
||
},
|
||
items: {
|
||
add: { name: kivi.t8('Add text block'), icon: "add", callback: standard_text_block_ajax_call }
|
||
, edit: { name: kivi.t8('Edit text block'), icon: "edit", callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
|
||
, delete: { name: kivi.t8('Delete text block'), icon: "delete", callback: ask_delete_text_block, disabled: disable_edit_text_block_commands }
|
||
, sep1: "---------"
|
||
, flag: { name: kivi.t8('Toggle marker'), icon: "flag", callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
|
||
, sep2: "---------"
|
||
, copy: { name: kivi.t8('Copy'), icon: "copy", callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
|
||
, paste: { name: kivi.t8('Paste'), icon: "paste", callback: standard_text_block_ajax_call }
|
||
}
|
||
items: $.extend({
|
||
add: { name: kivi.t8('Add text block'), icon: "add", callback: standard_text_block_ajax_call }
|
||
, edit: { name: kivi.t8('Edit text block'), icon: "edit", callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
|
||
, delete: { name: kivi.t8('Delete text block'), icon: "delete", callback: ask_delete_text_block, disabled: disable_edit_text_block_commands }
|
||
, sep1: "---------"
|
||
, flag: { name: kivi.t8('Toggle marker'), icon: "flag", callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
|
||
, sep2: "---------"
|
||
, copy: { name: kivi.t8('Copy'), icon: "copy", callback: standard_text_block_ajax_call, disabled: disable_edit_text_block_commands }
|
||
, paste: { name: kivi.t8('Paste'), icon: "paste", callback: standard_text_block_ajax_call }
|
||
}, general_actions)
|
||
});
|
||
|
||
var events = {
|
||
... | ... | |
$.contextMenu({
|
||
selector: '.section-context-menu',
|
||
events: events,
|
||
items: {
|
||
items: $.extend({
|
||
add_section: { name: kivi.t8('Add section'), icon: "add", callback: standard_item_ajax_call }
|
||
, add_function_block: { name: kivi.t8('Add function block'), icon: "add", callback: standard_item_ajax_call, disabled: disable_add_function_block_command }
|
||
, sep1: "---------"
|
||
... | ... | |
, sep3: "---------"
|
||
, copy: { name: kivi.t8('Copy'), icon: "copy", callback: standard_item_ajax_call, disabled: disable_edit_item_commands }
|
||
, paste: { name: kivi.t8('Paste'), icon: "paste", callback: standard_item_ajax_call }
|
||
}
|
||
}, general_actions)
|
||
});
|
||
|
||
$.contextMenu({
|
||
selector: '.function-block-context-menu,.sub-function-block-context-menu',
|
||
events: events,
|
||
items: {
|
||
items: $.extend({
|
||
add_function_block: { name: kivi.t8('Add function block'), icon: "add", callback: standard_item_ajax_call }
|
||
, add_sub_function_block: { name: kivi.t8('Add sub function block'), icon: "add", callback: standard_item_ajax_call }
|
||
, sep1: "---------"
|
||
... | ... | |
, sep3: "---------"
|
||
, copy: { name: kivi.t8('Copy'), icon: "copy", callback: standard_item_ajax_call, disabled: disable_edit_item_commands }
|
||
, paste: { name: kivi.t8('Paste'), icon: "paste", callback: standard_item_ajax_call }
|
||
}
|
||
}, general_actions)
|
||
});
|
||
|
||
$.contextMenu({
|
||
selector: '.time-cost-estimate-context-menu',
|
||
events: events,
|
||
items: { edit: { name: kivi.t8('Edit'), icon: "edit", callback: standard_time_cost_estimate_ajax_call } }
|
||
items: $.extend({ edit: { name: kivi.t8('Edit'), icon: "edit", callback: standard_time_cost_estimate_ajax_call } }, general_actions)
|
||
});
|
||
|
||
$.contextMenu({
|
||
selector: '.edit-time-cost-estimate-context-menu',
|
||
events: events,
|
||
items: {
|
||
items: $.extend({
|
||
save: { name: kivi.t8('Save'), icon: "save", callback: standard_time_cost_estimate_ajax_call }
|
||
, cancel: { name: kivi.t8('Cancel'), icon: "close", callback: standard_time_cost_estimate_ajax_call }
|
||
}
|
||
}, general_actions)
|
||
});
|
||
}
|
locale/de/all | ||
---|---|---|
'Copies' => 'Kopien',
|
||
'Copy file from #1 to #2 failed: #3' => 'Kopieren der Datei von #1 nach #2 schlug fehl: #3',
|
||
'Copy' => 'Kopieren',
|
||
'Copy requirement spec' => 'Pflichtenheft kopieren',
|
||
'Correct taxkey' => 'Richtiger Steuerschlüssel',
|
||
'Cost' => 'Kosten',
|
||
'Costs' => 'Kosten',
|
||
... | ... | |
'Delete drafts' => 'Entwürfe löschen',
|
||
'Delete links' => 'Verknüpfungen löschen',
|
||
'Delete profile' => 'Profil löschen',
|
||
'Delete requirement spec' => 'Pflichtenheft löschen',
|
||
'Delete text block' => 'Textblock löschen',
|
||
'Delete transaction' => 'Buchung löschen',
|
||
'Deleted' => 'Gelöscht',
|
||
... | ... | |
'Requirement Spec Type' => 'Pflichtenhefttyp',
|
||
'Requirement Spec Types' => 'Pflichtenhefttypen',
|
||
'Requirement Specs' => 'Pflichtenhefte',
|
||
'Requirement spec actions:' => 'Pflichtenheftaktionen:',
|
||
'Requirement spec function block #1 with #2 sub function blocks; description: "#3"' => 'Pflichtenheft-Funktionsblock #1 mit #2 Unterfunktionsblöcken; Beschreibung: "#3"',
|
||
'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"',
|
||
'Requirement spec sub function block #1; description: "#2"' => 'Pflichtenheft-Unterfunktionsblock #1; Beschreibung: "#2"',
|
||
... | ... | |
'Save draft' => 'Entwurf speichern',
|
||
'Save profile' => 'Profil speichern',
|
||
'Save settings as' => 'Einstellungen speichern unter',
|
||
'Saving failed. Erro message from the database: #1' => 'Speichern schlug fehl. Fehlermeldung der Datenbank: #1',
|
||
'Saving the file \'%s\' failed. OS error message: %s' => 'Das Speichern der Datei \'%s\' schlug fehl. Fehlermeldung des Betriebssystems: %s',
|
||
'Screen' => 'Bildschirm',
|
||
'Search' => 'Suchen',
|
||
... | ... | |
'The name is missing.' => 'Der Name fehlt.',
|
||
'The name is not unique.' => 'Der Name ist nicht eindeutig.',
|
||
'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.',
|
||
'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.',
|
||
'The number of days for full payment' => 'Die Anzahl Tage, bis die Rechnung in voller Höhe bezahlt werden muss',
|
||
'The option field is empty.' => 'Das Optionsfeld ist leer.',
|
||
'The package name is invalid.' => 'Der Paketname ist ungültig.',
|
templates/webpages/requirement_spec/_form.html | ||
---|---|---|
|
||
</table>
|
||
|
||
[%- IF SELF.copy_source %]
|
||
[%- L.hidden_tag('copy_source_id', SELF.copy_source.id) %]
|
||
|
||
<p>
|
||
[%- LxERP.t8("The new requirement spec will be a copy of '#1' for customer '#2'.", SELF.copy_source.title, SELF.copy_source.customer.name) %]
|
||
</p>
|
||
[%- END %]
|
||
|
||
<p>
|
||
[% IF submit_as == 'post' %]
|
||
[% L.hidden_tag("action", "RequirementSpec/dispatch", id=id_prefix _ '_action') %]
|
Auch abrufbar als: Unified diff
Pflichtenhefte: Kopieren (clonen) generell und Löschen aus Kontextmenü implementiert