Pflichtenhefte auf Versionen zurücksetzen können
authorMoritz Bunkus <m.bunkus@linet-services.de>
Tue, 23 Apr 2013 08:30:06 +0000 (10:30 +0200)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Tue, 1 Apr 2014 11:03:20 +0000 (13:03 +0200)
SL/Controller/RequirementSpec.pm
SL/DB/RequirementSpec.pm
js/locale/de.js
js/requirement_spec.js
locale/de/all
templates/webpages/requirement_spec_version/list.html

index cac70a9..b557c03 100644 (file)
@@ -176,6 +176,23 @@ sub action_destroy {
   $self->redirect_to(action => 'list');
 }
 
+sub action_revert_to {
+  my ($self, %params) = @_;
+
+  return $self->js->error(t8('Cannot revert a versioned copy.'))->render($self) if $self->requirement_spec->working_copy_id;
+
+  my $versioned_copy = SL::DB::RequirementSpec->new(id => $::form->{versioned_copy_id})->load;
+
+  $self->requirement_spec->delete_items;
+  $self->requirement_spec->copy_from(
+    $versioned_copy,
+    version_id => $versioned_copy->version_id,
+  );
+
+  flash_later('info', t8('The requirement spec has been reverted to version #1.', $self->requirement_spec->version->version_number));
+  $self->js->redirect_to($self->url_for(action => 'show', id => $self->requirement_spec->id))->render($self);
+}
+
 #
 # filters
 #
index 69a750b..6a43a28 100644 (file)
@@ -133,9 +133,34 @@ sub copy_from {
     $id_to_clone{ $item->id }->update_attributes(dependencies => [ map { $id_to_clone{$_->id} } @{ $item->dependencies } ]);
   }
 
+  $self->update_attributes(%attributes);
+
   return $self;
 }
 
+sub delete_items {
+  my ($self) = @_;
+
+  my $worker = sub {
+    # First convert all items to sections so that deleting won't
+    # violate foreign key constraints on parent_id.
+    SL::DB::Manager::RequirementSpecItem->update_all(
+      set   => { parent_id => undef, item_type => 'section' },
+      where => [
+        requirement_spec_id => $self->id,
+        '!parent_id'        => undef,
+      ]);
+
+    # Now delete all items in one go.
+    SL::DB::Manager::RequirementSpecItem->delete_all(where => [ requirement_spec_id => $self->id ]);
+
+    # Last clear values in ourself.
+    $self->items([]);
+  };
+
+  return $self->db->in_transaction ? $worker->() : $self->db->do_transaction($worker);
+}
+
 sub previous_version {
   my ($self) = @_;
 
index 704abd7..5bba34d 100644 (file)
@@ -7,13 +7,16 @@ namespace("kivi").setupLocale({
 "Are you sure?":"Sind Sie sicher?",
 "Copy":"Kopieren",
 "Copy requirement spec":"Pflichtenheft kopieren",
+"Create PDF":"PDF erzeugen",
 "Create new version":"Neue Version anlegen",
 "Database Connection Test":"Test der Datenbankverbindung",
 "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 really want to revert to this version?":"Wollen Sie wirklich auf diese Version zurücksetzen?",
 "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":"Bearbeiten",
 "Edit text block":"Textblock bearbeiten",
 "Edit":"Bearbeiten",
 "Enter longdescription":"Langtext eingeben",
@@ -21,6 +24,7 @@ namespace("kivi").setupLocale({
 "Part picker":"Artikelauswahl",
 "Paste":"Einfügen",
 "Requirement spec actions:":"Pflichtenheftaktionen:",
+"Revert to version":"Auf Version zurücksetzen",
 "Save":"Speichern",
 "The description is missing.":"Die Beschreibung fehlt.",
 "The name is missing.":"Der Name fehlt.",
index 4ae545e..a03eb90 100644 (file)
@@ -252,7 +252,6 @@ function requirement_spec_text_block_popup_menu_hidden(opt) {
   return handle_text_block_popup_menu_markings(opt, false);
 }
 
-
 function handle_item_popup_menu_markings(opt, add) {
   var id = find_item_id(opt.$trigger);
   if (id)
@@ -323,6 +322,17 @@ function disable_requirement_spec_commands(key, opt) {
 // -------------------------------- versions -------------------------------
 // -------------------------------------------------------------------------
 
+function find_versioned_copy_id(clicked_elt) {
+  var id = $(clicked_elt).find("[name=versioned_copy_id]");
+  return id ? id.val() : undefined;
+}
+
+function disable_versioned_copy_item_commands(key, opt) {
+  if (key === "revert_to_version")
+    return !find_versioned_copy_id(opt.$trigger);
+  return false;
+}
+
 function create_requirement_spec_version() {
   open_jqm_window({ url:  'controller.pl',
                     data: { action:              'RequirementSpecVersion/new',
@@ -331,6 +341,27 @@ function create_requirement_spec_version() {
   return true;
 }
 
+function create_pdf_for_versioned_copy_ajax_call(key, opt) {
+  // TODO: create_pdf_for_versioned_copy_ajax_call
+
+  return true;
+}
+
+function revert_to_versioned_copy_ajax_call(key, opt) {
+  if (!confirm(kivi.t8('Do you really want to revert to this version?')))
+    return true;
+
+  var data = {
+    action:            'RequirementSpec/revert_to',
+    versioned_copy_id: find_versioned_copy_id(opt.$trigger),
+    id:                $('#requirement_spec_id').val()
+  };
+
+  $.post("controller.pl", data, eval_json_result);
+
+  return true;
+}
+
 // -------------------------------------------------------------------------
 // ----------------------------- context menus -----------------------------
 // -------------------------------------------------------------------------
@@ -414,16 +445,22 @@ function create_requirement_spec_context_menus() {
 
   $.contextMenu({
     selector: '.time-cost-estimate-context-menu',
-    events:   events,
     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:    $.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)
   });
+
+  $.contextMenu({
+    selector: '.versioned-copy-context-menu',
+    items:    $.extend({
+        // create_pdf:        { name: kivi.t8('Create PDF'),        icon: "pdf",    callback: create_pdf_for_versioned_copy_ajax_call                                                }
+      revert_to_version: { name: kivi.t8('Revert to version'), icon: "revert", callback: revert_to_versioned_copy_ajax_call,     disabled: disable_versioned_copy_item_commands }
+    }, general_actions)
+  });
 }
index 61c3d8e..be833f0 100755 (executable)
@@ -420,6 +420,7 @@ $self->{texts} = {
   'Cannot post transaction!'    => 'Rechnung kann nicht gebucht werden!',
   'Cannot process payment for a closed period!' => 'Es kann keine Zahlung in einem abgeschlossenen Zeitraum verbucht werden!',
   'Cannot remove files!'        => 'Dateien können nicht gelöscht werden!',
+  'Cannot revert a versioned copy.' => 'Eine versionierte Kopie selber kann nicht zurückgesetzt werden.',
   'Cannot save account!'        => 'Konto kann nicht gespeichert werden!',
   'Cannot save order!'          => 'Auftrag kann nicht gespeichert werden!',
   'Cannot save preferences!'    => 'Einstellungen können nicht gespeichert werden!',
@@ -534,6 +535,7 @@ $self->{texts} = {
   'Create Chart of Accounts'    => 'Zu verwendender Kontenplan',
   'Create Dataset'              => 'Neue Datenbank anlegen',
   'Create Date'                 => 'Erstelldatum',
+  'Create PDF'                  => 'PDF erzeugen',
   'Create a new acceptance status' => 'Einen neuen Abnahmestatus anlegen',
   'Create a new background job' => 'Einen neuen Hintergrund-Job anlegen',
   'Create a new business'       => 'Einen neuen Kunden-/Lieferantentyp erfassen',
@@ -785,6 +787,7 @@ $self->{texts} = {
   'Do you really want to delete the selected links?' => 'Wollen Sie wirklich die ausgewählten Verknüpfungen löschen?',
   'Do you really want to delete this object?' => 'Wollen Sie dieses Objekt wirklich löschen?',
   'Do you really want to delete this warehouse?' => 'Wollen Sie dieses Lager wirklich l&ouml;schen?',
+  'Do you really want to revert to this version?' => 'Wollen Sie wirklich auf diese Version zurücksetzen?',
   'Do you want to <b>limit</b> your search?' => 'Wollen Sie Ihre Suche <b>spezialisieren</b>?',
   'Do you want to carry this shipping address over to the new purchase order so that the vendor can deliver the goods directly to your customer?' => 'Wollen Sie diese Lieferadresse in den neuen Lieferantenauftrag &uuml;bernehmen, damit der H&auml;ndler die Waren direkt an Ihren Kunden liefern kann?',
   'Do you want to overwrite your current title?' => 'Wollen Sie den aktuellen Titel überschreiben?',
@@ -1876,6 +1879,7 @@ $self->{texts} = {
   'Revenue Account'             => 'Erlöskonto',
   'Revenues EU with UStId'      => 'Erl&ouml;se EU m. UStId',
   'Revenues EU without UStId'   => 'Erl&ouml;se EU o. UStId',
+  'Revert to version'           => 'Auf Version zurücksetzen',
   'Review of Aging list'        => 'Altersstrukturliste',
   'Right'                       => 'Rechts',
   'Risk'                        => 'Risiko',
@@ -2363,6 +2367,7 @@ $self->{texts} = {
   'The required information consists of the IBAN, the BIC, the mandator ID and the mandate\'s date of signature.' => 'Die benötigten Informationen bestehen aus IBAN, BIC, Mandanten-ID und dem Unterschriftsdatum des Mandates.',
   'The requirement spec has been created.' => 'Das Pflichtenheft wurde angelegt.',
   'The requirement spec has been deleted.' => 'Das Pflichtenheft wurde gelöscht.',
+  'The requirement spec has been reverted to version #1.' => 'Das Pflichtenheft wurde auf Version #1 zurückgesetzt.',
   'The requirement spec has been saved.' => 'Das Pflichtenheft wurde gespeichert.',
   'The requirement spec is in use and cannot be deleted.' => 'Das Pflichtenheft wird verwendet und kann nicht gelöscht werden.',
   'The requirement spec status has been created.' => 'Der Pflichtenheftstatus wurde angelegt.',
index 7c4f4d5..7f6ab52 100644 (file)
@@ -1,9 +1,9 @@
 [% USE HTML %][% USE L %][% USE LxERP %][%- USE P -%]
 
-<table>
+<table id="versioned_copies_list">
  <thead>
   <tr class="listheading">
-   <th>[%- LxERP.t8("Version number") %]</th>
+   <th><div class="thingy" style="width: 10px; height: 100%; background-color: red; position: relative; left: -10px;"></div>[%- LxERP.t8("Version number") %]</th>
    <th>[%- LxERP.t8("Description") %]</th>
    <th>[%- LxERP.t8("Internal comment") %]</th>
    <th>[%- LxERP.t8("Last modification") %]</th>
  </thead>
 
  <tbody>
-  <tr class="listrow">
-   <td>
-    [%- IF SELF.requirement_spec.version_id %]
-     [%- LxERP.t8("Working copy identical to version number #1", SELF.requirement_spec.version.version_number) %]
-    [%- ELSE %]
-     [%- LxERP.t8("Working copy without version") %]
-    [%- END -%]
-   </td>
+  <tr class="listrow versioned-copy-context-menu">
+   [%- IF SELF.requirement_spec.version_id %]
+    [% L.hidden_tag('versioned_copy_id', SELF.requirement_spec.version_id, no_id=1) %]
+    <td>[%- LxERP.t8("Working copy identical to version number #1", SELF.requirement_spec.version.version_number) %]</td>
+   [%- ELSE %]
+    <td>[%- LxERP.t8("Working copy without version") %]</td>
+   [%- END -%]
    <td>[%- LxERP.t8("Working copy; no description yet") %]</td>
    <td>&nbsp;</td>
    <td>[% SELF.requirement_spec.mtime.to_kivitendo(precision='minute') %]</td>
   </tr>
 
   [%- FOREACH versioned = SELF.versioned_copies %]
-   <tr class="listrow versioned_copy_context_menu">
+   <tr class="listrow versioned-copy-context-menu">
+    [% L.hidden_tag('versioned_copy_id', versioned.id, no_id=1) %]
     <td>[% HTML.escape(versioned.version.version_number) %]</td>
     <td>[% HTML.escape(P.truncate(versioned.description)) %]</td>
     <td>[% HTML.escape(P.truncate(versioned.comment)) %]</td>