Revision cbb1668f
Von Bernd Bleßmann vor mehr als 3 Jahren hinzugefügt
- ID cbb1668fb815449b20be91641debf16e94fb6421
- Vorgänger 47cbf8da
SL/Controller/TimeRecording.pm | ||
---|---|---|
|
||
use DateTime;
|
||
use English qw(-no_match_vars);
|
||
use List::Util qw(sum0);
|
||
use List::Util qw(sum0 notall);
|
||
use POSIX qw(strftime);
|
||
|
||
use SL::Controller::Helper::GetModels;
|
||
... | ... | |
use SL::DB::Project;
|
||
use SL::DB::TimeRecording;
|
||
use SL::DB::TimeRecordingArticle;
|
||
use SL::Helper::Flash qw(flash);
|
||
use SL::Helper::Flash qw(flash flash_later);
|
||
use SL::Helper::Number qw(_round_number _parse_number _round_total);
|
||
use SL::Helper::UserPreferences::TimeRecording;
|
||
use SL::Locale::String qw(t8);
|
||
... | ... | |
# safety
|
||
__PACKAGE__->run_before('check_auth');
|
||
__PACKAGE__->run_before('check_auth_edit', only => [ qw(edit save delete) ]);
|
||
__PACKAGE__->run_before('check_auth_edit_all', only => [ qw(mark_as_booked) ]);
|
||
__PACKAGE__->run_before('check_auth_edit_all', only => [ qw(mark_as_booked assign_order_dialog assign_order) ]);
|
||
|
||
|
||
my %sort_columns = (
|
||
... | ... | |
$self->redirect_to(safe_callback());
|
||
}
|
||
|
||
sub action_assign_order_dialog {
|
||
my ($self) = @_;
|
||
|
||
if (!scalar @{ $::form->{ids} }) {
|
||
return $self->js->flash('warning', t8('No entries have been selected.'))->render;
|
||
}
|
||
|
||
# Sanity check: all entries must have the same customer assigned.
|
||
my $trs = SL::DB::Manager::TimeRecording->get_all(where => [id => $::form->{ids}]);
|
||
if (notall { $_->customer_id == $trs->[0]->customer_id } @$trs) {
|
||
return $self->js->flash('error', t8('All entries must have the same customer assigned.'))->render;
|
||
};
|
||
|
||
# Search assigneable orders
|
||
my $orders = SL::DB::Manager::Order->get_all(query => [or => [ closed => 0, closed => undef ],
|
||
or => [ quotation => 0, quotation => undef ],
|
||
customer_id => $trs->[0]->customer_id]);
|
||
$orders = [ map { [$_->id, sprintf("%s %s", $_->number, $_->customervendor->name) ] } sort { $a->number <=> $b->number } @{$orders||[]} ];
|
||
|
||
# Prepare dialog
|
||
my $dialog_html = $self->render('time_recording/_assign_order_dialog', { output => 0 },
|
||
orders => $orders,
|
||
time_recordings => $trs,
|
||
callback => $::form->escape($::form->{callback}),
|
||
);
|
||
|
||
my %dialog_params = (
|
||
html => $dialog_html,
|
||
id => 'assign_order_dialog',
|
||
dialog => {
|
||
title => t8('Assign an order to entries'),
|
||
width => 500,
|
||
height => 600,
|
||
},
|
||
);
|
||
|
||
$self->js
|
||
->dialog->open(\%dialog_params)
|
||
->render;
|
||
}
|
||
|
||
sub action_assign_order {
|
||
my ($self) = @_;
|
||
|
||
if (!$::form->{assign}->{order_id}) {
|
||
return $self->js->flash('warning', t8('No order has been selected.'))->render;
|
||
}
|
||
|
||
if (!scalar @{ $::form->{ids} }) {
|
||
return $self->js->flash('warning', t8('No entries have been selected.'))->render;
|
||
}
|
||
|
||
# Sanity check: all entries must have the same customer assigned.
|
||
my $trs = SL::DB::Manager::TimeRecording->get_all(where => [id => $::form->{ids}]);
|
||
if (notall { $_->customer_id == $trs->[0]->customer_id } @$trs) {
|
||
return $self->js->flash('error', t8('All entries must have the same customer assigned.'))->render;
|
||
};
|
||
|
||
my $errors_occurred;
|
||
foreach my $tr (@$trs) {
|
||
$tr->assign_attributes(order_id => $::form->{assign}->{order_id});
|
||
my @errors = $tr->validate;
|
||
if (@errors) {
|
||
$self->js->flash('error', $tr->displayable_times . ': ' . $_) for @errors;
|
||
$errors_occurred = 1;
|
||
}
|
||
}
|
||
|
||
if ($errors_occurred) {
|
||
return $self->js->flash('warning', t8('No changes were saved.'))->render;
|
||
|
||
} else {
|
||
$_->save for @$trs;
|
||
flash_later('info', t8('The changes have been saved.'));
|
||
}
|
||
|
||
$self->redirect_to($::form->unescape($::form->{assign}->{callback}));
|
||
}
|
||
|
||
sub action_edit {
|
||
my ($self) = @_;
|
||
|
||
... | ... | |
confirm => $::locale->text('Do you really want to mark the selected entries as booked?'),
|
||
only_if => $self->can_edit_all,
|
||
],
|
||
action => [
|
||
t8('Assign Order'),
|
||
call => [ 'kivi.TimeRecording.assign_order_dialog', { callback => $self->models->get_callback } ],
|
||
checks => [ [ 'kivi.check_if_entries_selected', '[name="ids[]"]' ] ],
|
||
only_if => $self->can_edit_all,
|
||
],
|
||
],
|
||
action => [
|
||
t8('Add'),
|
js/kivi.TimeRecording.js | ||
---|---|---|
});
|
||
};
|
||
|
||
ns.assign_order_dialog = function(params) {
|
||
var callback = params.callback;
|
||
|
||
var data = $('#form').serializeArray();
|
||
data = data.concat($('#filter_form').serializeArray());
|
||
data.push({name: 'action', value: 'TimeRecording/assign_order_dialog'},
|
||
{name: 'callback', value: callback});
|
||
|
||
$.post("controller.pl", data, kivi.eval_json_result);
|
||
};
|
||
|
||
ns.assign_order = function() {
|
||
var data = $('#form').serializeArray();
|
||
data = data.concat($('#assign_order_form').serializeArray());
|
||
data.push({name: 'action', value: 'TimeRecording/assign_order'});
|
||
|
||
$('#assign_order_dialog').dialog('close');
|
||
|
||
$.post("controller.pl", data, kivi.eval_json_result);
|
||
};
|
||
|
||
});
|
||
|
||
$(function() {
|
locale/de/all | ||
---|---|---|
'All changes in that file have been reverted.' => 'Alle Änderungen in dieser Datei wurden rückgängig gemacht.',
|
||
'All clients' => 'Alle Mandanten',
|
||
'All employees' => 'Alle Angestellten',
|
||
'All entries must have the same customer assigned.' => 'Alle Einträge müssen den selben Kunden zugeordnet haben.',
|
||
'All general ledger entries' => 'Alle Hauptbucheinträge',
|
||
'All groups' => 'Alle Gruppen',
|
||
'All modules' => 'Alle Module',
|
||
... | ... | |
'Asset' => 'Aktiva/Mittelverwendung',
|
||
'Assets' => 'Aktiva',
|
||
'Assign' => 'Übernehmen',
|
||
'Assign Order' => 'Auftrag zuordnen',
|
||
'Assign an order to entries' => 'Auftrag den Einträgen zuordnen',
|
||
'Assign article' => 'Artikel zuweisen',
|
||
'Assign invoice' => 'Rechnung zuweisen',
|
||
'Assign the following article to all sections' => 'Den folgenden Artikel allen Abschnitten zuweisen',
|
||
... | ... | |
'No bins have been added to this warehouse yet.' => 'Es wurden zu diesem Lager noch keine Lagerplätze angelegt.',
|
||
'No carry-over chart configured!' => 'Kein Saldenvortragskonto konfiguriert!',
|
||
'No changes since previous version.' => 'Keine Änderungen seit der letzten Version.',
|
||
'No changes were saved.' => 'Es wurden keine Änderungen gespeichert.',
|
||
'No clients have been created yet.' => 'Es wurden noch keine Mandanten angelegt.',
|
||
'No contact selected to delete' => 'Keine Ansprechperson zum Löschen ausgewählt',
|
||
'No contra account selected!' => 'Kein Gegenkonto ausgewählt!',
|
||
... | ... | |
'No groups have been created yet.' => 'Es wurden noch keine Gruppen angelegt.',
|
||
'No internal phone extensions have been configured yet.' => 'Es wurden noch keine internen Durchwahlen konfiguriert.',
|
||
'No invoices have been selected.' => 'Es wurden keine Rechnungen ausgewählt.',
|
||
'No order has been selected.' => 'Es wurde kein Auftrag ausgewählt',
|
||
'No part was selected.' => 'Es wurde kein Artikel ausgewählt',
|
||
'No payment term has been created yet.' => 'Es wurden noch keine Zahlungsbedingungen angelegt.',
|
||
'No picture has been uploaded' => 'Es wurde kein Bild hochgeladen',
|
||
... | ... | |
'Select Mulit-Item Options' => 'Multi-Treffer Auswahlliste',
|
||
'Select a Customer' => 'Endkunde auswählen',
|
||
'Select a period' => 'Bitte Zeitraum auswählen',
|
||
'Select an order to assign' => 'Wählen Sie einen Auftrag zum Zuordnen',
|
||
'Select federal state...' => 'Bundesland auswählen...',
|
||
'Select file to upload' => 'Datei zum Hochladen auswählen',
|
||
'Select from one of the items below' => 'Wählen Sie einen der untenstehenden Einträge',
|
||
... | ... | |
'Select type of transfer in' => 'Grund der Einlagerung auswählen:',
|
||
'Selected' => 'Ausgewählt',
|
||
'Selected identity fields' => 'Ausgewählte Felder',
|
||
'Selected time recordings' => 'Ausgewählte Zeiterfassungs-Einträge',
|
||
'Selection' => 'Auswahlbox',
|
||
'Selection fields: The option field must contain the available options for the selection. Options are separated by \'##\', for example \'Early##Normal##Late\'.' => 'Auswahlboxen: Das Optionenfeld muss die für die Auswahl verfügbaren Einträge enthalten. Die Einträge werden mit \'##\' voneinander getrennt. Beispiel: \'Früh##Normal##Spät\'.',
|
||
'Sell Price' => 'Verkaufspreis',
|
||
... | ... | |
'The booking group needs an inventory account.' => 'Die Buchungsgruppe braucht ein Warenbestandskonto.',
|
||
'The buchungsgruppe is missing.' => 'Die Buchungsgruppe fehlt.',
|
||
'The categories has been saved.' => 'Artikelgruppe gespeichert',
|
||
'The changes have been saved.' => 'Die Änderungen wurden gespeichert.',
|
||
'The changing of tax-o-matic account is NOT recommended, but if you do so please also (re)configure booking groups and reconfigure ALL charts which point to this tax-o-matic account. ' => 'Es wird nicht empfohlen Steuerkonten (Umsatzsteuer oder Vorsteuer) "umzuhängen", aber falls es gemacht wird, bitte auch entsprechend konsequent die Buchungsgruppen und die Konten die mit dieser Steuer verknüpft sind umkonfigurieren.',
|
||
'The chart is not valid.' => 'Das Konto ist nicht gültig.',
|
||
'The client could not be deleted.' => 'Der Mandant konnte nicht gelöscht werden.',
|
||
... | ... | |
'correction' => 'Korrektur',
|
||
'correction_br' => 'Korr.',
|
||
'cp_greeting to cp_gender migration' => 'Datenumwandlung von Titel nach Geschlecht (cp_greeting to cp_gender)',
|
||
'current order' => 'aktueller Auftrag',
|
||
'customer_list' => 'kundenliste',
|
||
'dated' => 'datiert',
|
||
'delete' => 'Löschen',
|
||
... | ... | |
'taxnumber' => 'Automatikkonto',
|
||
'terminated' => 'gekündigt',
|
||
'time and effort based position' => 'Aufwandsposition',
|
||
'time recording entry' => 'Zeiterfassungs-Eintrag',
|
||
'time_recordings' => 'zeiterfassung',
|
||
'to' => 'bis',
|
||
'to (date)' => 'bis',
|
locale/en/all | ||
---|---|---|
'All changes in that file have been reverted.' => '',
|
||
'All clients' => '',
|
||
'All employees' => '',
|
||
'All entries must have the same customer assigned.' => '',
|
||
'All general ledger entries' => '',
|
||
'All groups' => '',
|
||
'All modules' => '',
|
||
... | ... | |
'Asset' => '',
|
||
'Assets' => '',
|
||
'Assign' => '',
|
||
'Assign Order' => '',
|
||
'Assign an order to entries' => '',
|
||
'Assign article' => '',
|
||
'Assign invoice' => '',
|
||
'Assign the following article to all sections' => '',
|
||
... | ... | |
'No bins have been added to this warehouse yet.' => '',
|
||
'No carry-over chart configured!' => '',
|
||
'No changes since previous version.' => '',
|
||
'No changes were saved.' => '',
|
||
'No clients have been created yet.' => '',
|
||
'No contact selected to delete' => '',
|
||
'No contra account selected!' => '',
|
||
... | ... | |
'No groups have been created yet.' => '',
|
||
'No internal phone extensions have been configured yet.' => '',
|
||
'No invoices have been selected.' => '',
|
||
'No order has been selected.' => '',
|
||
'No part was selected.' => '',
|
||
'No payment term has been created yet.' => '',
|
||
'No picture has been uploaded' => '',
|
||
... | ... | |
'Select Mulit-Item Options' => '',
|
||
'Select a Customer' => '',
|
||
'Select a period' => '',
|
||
'Select an order to assign' => '',
|
||
'Select federal state...' => '',
|
||
'Select file to upload' => '',
|
||
'Select from one of the items below' => '',
|
||
... | ... | |
'Select type of transfer in' => '',
|
||
'Selected' => '',
|
||
'Selected identity fields' => '',
|
||
'Selected time recordings' => '',
|
||
'Selection' => '',
|
||
'Selection fields: The option field must contain the available options for the selection. Options are separated by \'##\', for example \'Early##Normal##Late\'.' => '',
|
||
'Sell Price' => '',
|
||
... | ... | |
'The booking group needs an inventory account.' => '',
|
||
'The buchungsgruppe is missing.' => '',
|
||
'The categories has been saved.' => '',
|
||
'The changes have been saved.' => '',
|
||
'The changing of tax-o-matic account is NOT recommended, but if you do so please also (re)configure booking groups and reconfigure ALL charts which point to this tax-o-matic account. ' => '',
|
||
'The chart is not valid.' => '',
|
||
'The client could not be deleted.' => '',
|
||
... | ... | |
'correction' => '',
|
||
'correction_br' => 'correction',
|
||
'cp_greeting to cp_gender migration' => '',
|
||
'current order' => '',
|
||
'customer_list' => '',
|
||
'dated' => '',
|
||
'delete' => '',
|
||
... | ... | |
'taxnumber' => '',
|
||
'terminated' => '',
|
||
'time and effort based position' => '',
|
||
'time recording entry' => '',
|
||
'time_recordings' => '',
|
||
'to' => '',
|
||
'to (date)' => '',
|
templates/webpages/time_recording/_assign_order_dialog.html | ||
---|---|---|
[%- USE T8 %][%- USE HTML %][%- USE L %][%- USE P %][%- USE LxERP %]
|
||
|
||
<form method="POST" id="assign_order_form">
|
||
[% L.hidden_tag('assign.callback', HTML.escape(callback)) %]
|
||
|
||
<p>
|
||
<h3>[% 'Selected time recordings' | $T8 %]</h3>
|
||
<table>
|
||
<tr class="listheading">
|
||
<th>[% 'time recording entry' | $T8 %]</th>
|
||
<th>[% 'current order' | $T8 %]</th>
|
||
</tr>
|
||
[% FOREACH tr = time_recordings %]
|
||
<tr class="listrow">
|
||
<td>[% tr.displayable_times %]</td>
|
||
<td align="right">[% tr.order_id ? tr.order.number : '-' %]</td>
|
||
</tr>
|
||
[% END %]
|
||
</table>
|
||
</p>
|
||
|
||
<p>
|
||
<h3>[% 'Select an order to assign' | $T8 %]</h3>
|
||
[% P.select_tag('assign.order_id', orders, with_empty=1, style='width: 300px') %]
|
||
</p>
|
||
|
||
<p>
|
||
[% L.button_tag("kivi.TimeRecording.assign_order()", LxERP.t8('Continue')) %]
|
||
</p>
|
||
</form>
|
Auch abrufbar als: Unified diff
Zeiterfassung: Im Bericht Aufträge zuordnen können