Telefonnotizen Angebot/Auftrag
authorBernd Bleßmann <bernd@kivitendo-premium.de>
Mon, 11 Apr 2022 07:47:38 +0000 (09:47 +0200)
committerBernd Bleßmann <bernd@kivitendo-premium.de>
Fri, 13 May 2022 09:44:18 +0000 (11:44 +0200)
In einem neuen Reiter können Notizen zum Beleg erfasst werden.

SL/Controller/Order.pm
SL/DB/Order.pm
js/kivi.Order.js
js/locale/de.js
js/locale/en.js
locale/de/all
locale/en/all
templates/webpages/order/form.html
templates/webpages/order/tabs/phone_notes.html [new file with mode: 0644]

index 89d2af0..a37df9e 100644 (file)
@@ -24,6 +24,7 @@ use SL::DB::Part;
 use SL::DB::PartClassification;
 use SL::DB::PartsGroup;
 use SL::DB::Printer;
+use SL::DB::Note;
 use SL::DB::Language;
 use SL::DB::RecordLink;
 use SL::DB::RequirementSpec;
@@ -1239,6 +1240,58 @@ sub action_update_row_from_master_data {
   $self->js->render();
 }
 
+sub action_save_phone_note {
+  my ($self) = @_;
+
+  if (!$::form->{phone_note}->{subject} || !$::form->{phone_note}->{body}) {
+    return $self->js->flash('error', t8('Phone note needs a subject and a body.'))->render;
+  }
+
+  my $phone_note;
+  if ($::form->{phone_note}->{id}) {
+    $phone_note = first { $_->id == $::form->{phone_note}->{id} } @{$self->order->phone_notes};
+    return $self->js->flash('error', t8('Phone note not found for this order.'))->render if !$phone_note;
+  }
+
+  $phone_note = SL::DB::Note->new() if !$phone_note;
+  my $is_new  = !$phone_note->id;
+
+  $phone_note->assign_attributes(%{ $::form->{phone_note} },
+                                 trans_id     => $self->order->id,
+                                 trans_module => 'oe',
+                                 employee     => SL::DB::Manager::Employee->current);
+
+  $phone_note->save;
+  $self->order(SL::DB::Order->new(id => $self->order->id)->load);
+
+  my $tab_as_html = $self->p->render('order/tabs/phone_notes', SELF => $self);
+
+  return $self->js
+    ->replaceWith('#phone-notes', $tab_as_html)
+    ->html('#num_phone_notes', (scalar @{$self->order->phone_notes}) ? ' (' . scalar @{$self->order->phone_notes} . ')' : '')
+    ->flash('info', $is_new ? t8('Phone note has been created.') : t8('Phone note has been updated.'))
+    ->render;
+}
+
+sub action_delete_phone_note {
+  my ($self) = @_;
+
+  my $phone_note = first { $_->id == $::form->{phone_note}->{id} } @{$self->order->phone_notes};
+
+  return $self->js->flash('error', t8('Phone note not found for this order.'))->render if !$phone_note;
+
+  $phone_note->delete;
+  $self->order(SL::DB::Order->new(id => $self->order->id)->load);
+
+  my $tab_as_html = $self->p->render('order/tabs/phone_notes', SELF => $self);
+
+  return $self->js
+    ->replaceWith('#phone-notes', $tab_as_html)
+    ->html('#num_phone_notes', (scalar @{$self->order->phone_notes}) ? ' (' . scalar @{$self->order->phone_notes} . ')' : '')
+    ->flash('info', t8('Phone note has been deleted.'))
+    ->render;
+}
+
 sub js_load_second_row {
   my ($self, $item, $item_id, $do_parse) = @_;
 
@@ -1802,6 +1855,30 @@ sub save {
   my $errors = [];
   my $db     = $self->order->db;
 
+  # check for new or updated phone note
+  if ($::form->{phone_note}->{subject} || $::form->{phone_note}->{body}) {
+    if (!$::form->{phone_note}->{subject} || !$::form->{phone_note}->{body}) {
+      return [t8('Phone note needs a subject and a body.')];
+      die;
+    }
+
+    my $phone_note;
+    if ($::form->{phone_note}->{id}) {
+      $phone_note = first { $_->id == $::form->{phone_note}->{id} } @{$self->order->phone_notes};
+      return [t8('Phone note not found for this order.')] if !$phone_note;
+    }
+
+    $phone_note = SL::DB::Note->new() if !$phone_note;
+    my $is_new  = !$phone_note->id;
+
+    $phone_note->assign_attributes(%{ $::form->{phone_note} },
+                                   trans_id     => $self->order->id,
+                                   trans_module => 'oe',
+                                   employee     => SL::DB::Manager::Employee->current);
+
+    $self->order->add_phone_notes($phone_note) if $is_new;
+  }
+
   $db->with_transaction(sub {
     # delete custom shipto if it is to be deleted or if it is empty
     if ($self->order->custom_shipto && ($self->is_custom_shipto_to_delete || $self->order->custom_shipto->is_empty)) {
@@ -2026,6 +2103,8 @@ sub pre_render {
 
   $self->get_item_cvpartnumber($_) for @{$self->order->items_sorted};
 
+  $self->{template_args}->{num_phone_notes} = scalar @{ $self->order->phone_notes || [] };
+
   $::request->{layout}->use_javascript("${_}.js") for qw(kivi.Validator kivi.SalesPurchase kivi.Order kivi.File ckeditor/ckeditor ckeditor/adapters/jquery
                                                          edit_periodic_invoices_config calculate_qty follow_up show_history);
   $self->setup_edit_action_bar;
index 397b7fa..fdaa1e8 100644 (file)
@@ -47,6 +47,16 @@ __PACKAGE__->meta->add_relationship(
     class                  => 'SL::DB::Exchangerate',
     column_map             => { currency_id => 'currency_id', transdate => 'transdate' },
   },
+  phone_notes => {
+    type         => 'one to many',
+    class        => 'SL::DB::Note',
+    column_map   => { id => 'trans_id' },
+    query_args   => [ trans_module => 'oe' ],
+    manager_args => {
+      with_objects => [ 'employee' ],
+      sort_by      => 'notes.itime',
+    }
+  },
 );
 
 SL::DB::Helper::Attr::make(__PACKAGE__, daily_exchangerate => 'numeric');
index b0960e7..9ef6ef5 100644 (file)
@@ -878,7 +878,6 @@ namespace('kivi.Order', function(ns) {
   ns.create_part = function() {
     var data = $('#order_form').serializeArray();
     data.push({ name: 'action', value: 'Order/create_part' });
-
     $.post("controller.pl", data, kivi.eval_json_result);
   };
 
@@ -906,6 +905,38 @@ namespace('kivi.Order', function(ns) {
     return true;
   };
 
+  ns.load_phone_note = function(id, subject, body) {
+    $('#phone_note_edit_text').html(kivi.t8('Edit note'));
+    $('#phone_note_id').val(id);
+    $('#phone_note_subject').val(subject);
+    $('#phone_note_body').val(body);
+    $('#phone_note_delete_button').show();
+  };
+
+  ns.cancel_phone_note = function() {
+    $('#phone_note_edit_text').html(kivi.t8('Add note'));
+    $('#phone_note_id').val('');
+    $('#phone_note_subject').val('');
+    $('#phone_note_body').val('');
+    $('#phone_note_delete_button').hide();
+  };
+
+  ns.save_phone_note = function() {
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'Order/save_phone_note' });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
+  ns.delete_phone_note = function() {
+    if ($('#phone_note_id').val() === '') return;
+
+    var data = $('#order_form').serializeArray();
+    data.push({ name: 'action', value: 'Order/delete_phone_note' });
+
+    $.post("controller.pl", data, kivi.eval_json_result);
+  };
+
 });
 
 $(function() {
index 859fe0e..c17b213 100644 (file)
@@ -4,6 +4,7 @@ namespace("kivi").setupLocale({
 "Add function block":"Funktionsblock hinzufügen",
 "Add linked record":"Verknüpften Beleg hinzufügen",
 "Add multiple items":"Mehrere Artikel hinzufügen",
+"Add note":"Notiz erfassen",
 "Add picture":"Bild hinzufügen",
 "Add picture to text block":"Bild dem Textblock hinzufügen",
 "Add section":"Abschnitt hinzufügen",
@@ -61,6 +62,7 @@ namespace("kivi").setupLocale({
 "Edit":"Bearbeiten",
 "Edit article/section assignments":"Zuweisung Artikel/Abschnitte bearbeiten",
 "Edit custom shipto":"Individuelle Lieferadresse bearbeiten",
+"Edit note":"Notiz bearbeiten",
 "Edit picture":"Bild bearbeiten",
 "Edit project link":"Projektverknüpfung bearbeiten",
 "Edit text block":"Textblock bearbeiten",
index 6683837..4306694 100644 (file)
@@ -4,6 +4,7 @@ namespace("kivi").setupLocale({
 "Add function block":"",
 "Add linked record":"",
 "Add multiple items":"",
+"Add note":"",
 "Add picture":"",
 "Add picture to text block":"",
 "Add section":"",
@@ -61,6 +62,7 @@ namespace("kivi").setupLocale({
 "Edit":"",
 "Edit article/section assignments":"",
 "Edit custom shipto":"",
+"Edit note":"",
 "Edit picture":"",
 "Edit project link":"",
 "Edit text block":"",
index 038091b..ecb9551 100755 (executable)
@@ -2530,8 +2530,14 @@ $self->{texts} = {
   'Perpetual inventory'         => 'Bestandsmethode',
   'Personal settings'           => 'Persönliche Einstellungen',
   'Phone'                       => 'Telefon',
+  'Phone Notes'                 => 'Telefonnotizen',
   'Phone extension'             => 'Durchwahl',
   'Phone extension missing in user configuration' => 'Durchwahl fehlt in der Benutzerkonfiguration',
+  'Phone note has been created.' => 'Die Telefonnotiz wurde angelegt.',
+  'Phone note has been deleted.' => 'Die Telefonnotiz wurde gelöscht.',
+  'Phone note has been updated.' => 'Die Telefonnotiz wurde aktualisiert.',
+  'Phone note needs a subject and a body.' => 'Eine Telefonnotiz muss einen Betreff und einen Text haben.',
+  'Phone note not found for this order.' => 'Diese Telefonnotiz wurde für dieses Dokument nicht gefunden.',
   'Phone password'              => 'Telefonpasswort',
   'Phone password missing in user configuration' => 'Telefonpasswort fehlt in der Benutzerkonfiguration',
   'Phone1'                      => 'Telefon 1 ',
index 5be0917..035c447 100644 (file)
@@ -2530,8 +2530,14 @@ $self->{texts} = {
   'Perpetual inventory'         => '',
   'Personal settings'           => '',
   'Phone'                       => '',
+  'Phone Notes'                 => '',
   'Phone extension'             => '',
   'Phone extension missing in user configuration' => '',
+  'Phone note has been created.' => '',
+  'Phone note has been deleted.' => '',
+  'Phone note has been updated.' => '',
+  'Phone note needs a subject and a body.' => '',
+  'Phone note not found for this order.' => '',
   'Phone password'              => '',
   'Phone password missing in user configuration' => '',
   'Phone1'                      => '',
index 17534de..82bc2f1 100644 (file)
@@ -38,6 +38,9 @@
 [%- IF SELF.order.id %]
       <li><a href="controller.pl?action=RecordLinks/ajax_list&object_model=Order&object_id=[% HTML.url(SELF.order.id) %]">[% 'Linked Records' | $T8 %]</a></li>
 [%- END %]
+[% IF SELF.order.id %]
+      <li><a href="#ui-tabs-phone-notes">[% 'Phone Notes' | $T8 %]<span id="num_phone_notes">[%- num_phone_notes ? ' (' _ num_phone_notes _ ')' : '' -%]</span></a></li>
+[% END %]
     </ul>
 
     [% PROCESS "order/tabs/basic_data.html" %]
     <div id="ui-tabs-1">
       [%- LxERP.t8("Loading...") %]
     </div>
-
+[% IF SELF.order.id %]
+    <div id="ui-tabs-phone-notes">
+      [% PROCESS "order/tabs/phone_notes.html" %]
+    </div>
+[% END %]
     <div id="shipto_inputs" class="hidden">
       [%- PROCESS 'common/_ship_to_dialog.html'
         vc_obj=SELF.order.customervendor
diff --git a/templates/webpages/order/tabs/phone_notes.html b/templates/webpages/order/tabs/phone_notes.html
new file mode 100644 (file)
index 0000000..b1d2117
--- /dev/null
@@ -0,0 +1,47 @@
+[%- USE T8 %]
+[%- USE HTML %]
+[%- USE L %]
+[%- USE LxERP %]
+[%- USE P %]
+
+<div id="phone-notes">
+ [% IF ( SELF.order.phone_notes && SELF.order.phone_notes.size ) %]
+  <table>
+    <tr>
+      <th class="listheading">[% 'Subject' | $T8 %]</th>
+      <th class="listheading">[% 'Created on' | $T8 %]</th>
+      <th class="listheading">[% 'Created by' | $T8 %]</th>
+    </tr>
+
+    [%- FOREACH row = SELF.order.phone_notes %]
+     <tr class="listrow">
+       <td>[% P.link_tag('#', row.subject, onclick="kivi.Order.load_phone_note(" _ HTML.url(row.id) _ ", '" _ HTML.escape(row.subject) _ "', '" _ HTML.escape(row.body) _ "')") %]</td>
+       <td>[% row.itime.to_kivitendo | html %]</td>
+       <td>[% row.employee.safe_name | html %]</td>
+     </tr>
+    [% END %]
+  </table>
+ [% END %]
+
+  <h2 id='phone_note_edit_text'>[% 'Add note' | $T8 %]</h2>
+
+  [% L.hidden_tag('phone_note.id') %]
+
+  <table>
+    <tr>
+      <td valign="right">[% 'Subject' | $T8 %]</td>
+      <td>[% L.input_tag('phone_note.subject', '', size = 50) %]</td>
+    </tr>
+    <tr>
+      <td valign="right" align="top">[% 'Body' | $T8 %]</td>
+      <td align="top">[% L.textarea_tag('phone_note.body', '', cols = 50 rows = 10) %]</td>
+    </tr>
+  </table>
+
+ <p>
+   [% P.button_tag("kivi.Order.save_phone_note()",   LxERP.t8('Save')) %]
+   [% P.button_tag("kivi.Order.delete_phone_note()", LxERP.t8('Delete'), id = 'phone_note_delete_button', style='display:none') %]
+   [% P.button_tag("kivi.Order.cancel_phone_note()", LxERP.t8('Cancel')) %]
+ </p>
+
+</div>