Revision d3353176
Von Kivitendo Admin vor fast 2 Jahren hinzugefügt
SL/Controller/Clearing.pm | ||
---|---|---|
package SL::Controller::Clearing;
|
||
|
||
use strict;
|
||
|
||
use parent qw(SL::Controller::Base);
|
||
|
||
use SL::Clearing;
|
||
use SL::DB::ClearedGroup;
|
||
use SL::DB::Project;
|
||
use SL::DB::Department;
|
||
use SL::DB::Chart;
|
||
use SL::Locale::String qw(t8);
|
||
use SL::DBUtils qw(selectall_hashref_query);
|
||
use List::MoreUtils qw(uniq);
|
||
|
||
use Rose::Object::MakeMethods::Generic (
|
||
'scalar' => [ qw(chart chart_transactions cleared_group_transactions fromdate todate project_id department_id susa_link) ]
|
||
);
|
||
|
||
__PACKAGE__->run_before('check_auth');
|
||
|
||
sub action_form {
|
||
my ($self) = @_;
|
||
|
||
$self->_parse_form;
|
||
|
||
if ( $self->chart && !$self->chart->clearing ) {
|
||
return $self->render('clearing/chart_missing', { layout => 1, process => 1 },
|
||
chart => $self->chart,
|
||
);
|
||
}
|
||
|
||
my @susa_url_params = (
|
||
controller => 'ca.pl',
|
||
action => 'list_transactions',
|
||
method => 'cash'
|
||
);
|
||
|
||
my %susa_params = (
|
||
accno => $self->chart ? $self->chart->accno : '',
|
||
fromdate => $self->fromdate ? $self->fromdate->to_kivitendo : undef,
|
||
todate => $self->todate ? $self->todate->to_kivitendo : undef,
|
||
description => $self->chart ? $self->chart->description : '',
|
||
);
|
||
|
||
foreach my $key ( keys %susa_params ) {
|
||
if ( $susa_params{$key} ) {
|
||
push(@susa_url_params, ( $key => $susa_params{$key} ));
|
||
}
|
||
}
|
||
|
||
$self->susa_link($self->url_for(@susa_url_params));
|
||
$self->setup_action_bar;
|
||
|
||
$self->{all_departments} = SL::DB::Manager::Department->get_all_sorted();
|
||
|
||
$::request->layout->use_javascript("${_}.js") for qw(knockout-3.5.1 knockout.kivitendo clearing);
|
||
$::request->layout->use_stylesheet("css/clearing.css");
|
||
|
||
$self->render('clearing/form', { layout => 1, process => 1 },
|
||
chart_id => $self->chart ? $self->chart->id : '',
|
||
susa_link => $self->susa_link,
|
||
);
|
||
}
|
||
|
||
sub _parse_form {
|
||
my ($self) = @_;
|
||
|
||
# chart, fromdate, todate, project_id, department_id, load_cleared
|
||
|
||
if ( $::form->{accno} ) { # only needed for link from ca list_transactions
|
||
# here we assume that there is only one chart per accno, though the old code for CA all_transactions allows for several chart.id to be summed up
|
||
$self->chart( SL::DB::Manager::Chart->find_by(accno => delete $::form->{accno}) );
|
||
} elsif ( $::form->{chart_id} ) {
|
||
$self->chart( SL::DB::Chart->new(id => delete $::form->{chart_id})->load);
|
||
};
|
||
# TODO: check that chart has clearing attribute
|
||
|
||
if ( $::form->{filter}->{fromdate} || $::form->{fromdate} ) {
|
||
my $fromdate = $::form->{filter}->{fromdate} || $::form->{fromdate};
|
||
$self->fromdate( $::locale->parse_date_to_object($fromdate) );
|
||
}
|
||
|
||
if ( $::form->{filter}->{todate} || $::form->{todate} ) {
|
||
my $todate = $::form->{filter}->{todate} || $::form->{todate};
|
||
$self->todate( $::locale->parse_date_to_object($todate) );
|
||
}
|
||
|
||
if ( $::form->{filter}->{project_id} || $::form->{project_id} ) {
|
||
$self->project_id($::form->{filter}->{project_id} || $::form->{project_id});
|
||
}
|
||
|
||
if ( $::form->{filter}->{department_id} || $::form->{department_id} ) {
|
||
$self->department_id($::form->{filter}->{department_id} || $::form->{department_id});
|
||
}
|
||
}
|
||
|
||
sub action_create_cleared_group {
|
||
my ($self) = @_;
|
||
|
||
my $cleared_group_transactions = $::request->post_data;
|
||
|
||
my @acc_trans_ids = map { $_->{acc_trans_id} } @{ $cleared_group_transactions };
|
||
|
||
my $result = SL::Clearing::create_cleared_group(\@acc_trans_ids);
|
||
if ( $result ) {
|
||
$self->js->flash('info', t8('Cleared bookings'));
|
||
} else {
|
||
$self->js->flash('error', t8('Error while clearing'));
|
||
}
|
||
return $self->js->render;
|
||
}
|
||
|
||
sub action_remove_cleared_group {
|
||
my ($self) = @_;
|
||
|
||
my $cleared_group_transactions = $::request->post_data;
|
||
|
||
my @cleared_group_ids= map { $_->{cleared_group_id} } @{ $cleared_group_transactions };
|
||
die "no unique cleared group" unless scalar uniq @cleared_group_ids == 1;
|
||
my $cleared_group_id = $cleared_group_ids[0];
|
||
|
||
my $result = SL::Clearing::remove_cleared_group($cleared_group_id);
|
||
if ( $result ) {
|
||
$self->js->flash('info', t8('Removed cleared group'));
|
||
} else {
|
||
$self->js->flash('error', t8('error while unclearing'));
|
||
}
|
||
return $self->js->render;
|
||
}
|
||
|
||
# actions returning JSON
|
||
|
||
sub action_list {
|
||
my ($self) = @_;
|
||
|
||
$self->_parse_form;
|
||
|
||
die "no valid clearing chart" unless $self->chart && $self->chart->clearing;
|
||
|
||
my $filter = delete $::form->{filter};
|
||
|
||
my %params = (
|
||
chart_id => $self->chart->id,
|
||
fromdate => $self->fromdate,
|
||
todate => $self->todate,
|
||
project_id => $self->project_id,
|
||
department_id => $self->department_id,
|
||
load_cleared => $filter->{load_cleared} ? 1 : 0,
|
||
);
|
||
|
||
my $chart_transactions = SL::Clearing::load_chart_transactions(\%params);
|
||
|
||
$self->chart_transactions($chart_transactions);
|
||
|
||
return $self->render(\ SL::JSON::to_json( $self->chart_transactions ), { layout => 0, type => 'json', process => 0 });
|
||
}
|
||
|
||
sub action_fetch_cleared_group {
|
||
my ($self) = @_;
|
||
|
||
$self->load_cleared_group_transactions($::form->{cleared_group_id});
|
||
return $self->render(\ SL::JSON::to_json( $self->cleared_group_transactions ), { layout => 0, type => 'json', process => 0 });
|
||
}
|
||
|
||
sub load_cleared_group_transactions {
|
||
my ($self, $cleared_group_id) = @_;
|
||
|
||
my $cleared_group_transactions = SL::Clearing::load_cleared_group_transactions_by_group_id($cleared_group_id);
|
||
|
||
# convert itime to locale_formatted itime
|
||
foreach my $line ( @$cleared_group_transactions ) {
|
||
my $dt = DateTime::Format::Pg->parse_datetime( $line->{itime} );
|
||
$line->{formatted_itime} = $::locale->format_date_object($dt, precision => 'seconds');
|
||
}
|
||
$self->cleared_group_transactions($cleared_group_transactions);
|
||
}
|
||
|
||
sub setup_action_bar {
|
||
my ($self, %params) = @_;
|
||
for my $bar ($::request->layout->get('actionbar')) {
|
||
$bar->add(
|
||
link => [
|
||
t8('List Transactions'),
|
||
link => $self->susa_link,
|
||
],
|
||
);
|
||
}
|
||
}
|
||
|
||
sub add_javascripts {
|
||
$::request->layout->add_javascripts(qw(knockout-3.5.1.js knockout.kivitendo.js));
|
||
}
|
||
|
||
sub check_auth {
|
||
$::auth->assert('general_ledger');
|
||
}
|
||
|
||
1;
|
css/clearing.css | ||
---|---|---|
/* the selection box */
|
||
div.selection {
|
||
background-color: lightgray;
|
||
}
|
||
|
||
.bookings tr.cleared {
|
||
background-color: lightgreen;
|
||
}
|
||
|
||
.bookings tr.selected {
|
||
background-color: lightgray;
|
||
}
|
||
|
||
.bookings tr.selected_cleared_group {
|
||
background-color: orange;
|
||
}
|
||
|
||
.bookings tr:hover {
|
||
border-color: black;
|
||
outline: thin solid;
|
||
}
|
||
|
||
div.overflow {
|
||
padding: 20px;
|
||
resize: both;
|
||
overflow-y: auto;
|
||
max-height: 500px;
|
||
}
|
||
|
||
.table { border-collapse: collapse; }
|
||
.table th, .table td { border: 1px solid silver; padding: 3px}
|
||
.sortable { cursor: pointer; }
|
||
.sorted { background-color: #B5E0FF; }
|
||
|
||
table.grid th { text-align: right; }
|
||
|
||
.flex-container {
|
||
display:flex;
|
||
align-items: flex-start;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.flexing {
|
||
position: sticky;
|
||
top: 0;
|
||
margin: 2px;
|
||
min-width: 200px;
|
||
border: 2px solid;
|
||
}
|
js/clearing.js | ||
---|---|---|
function BookingModel(data) {
|
||
var self = this;
|
||
|
||
var precision = 2;
|
||
|
||
self.selected = ko.observable(false); // user selected this element
|
||
|
||
self.acc_trans_id = data.acc_trans_id;
|
||
self.accno = data.accno;
|
||
self.description = data.description;
|
||
self.reference = data.reference;
|
||
self.itime = data.itime; // only used for loaded groups?
|
||
self.formatted_itime = data.formatted_itime; // only used for loaded groups?
|
||
|
||
// amounts
|
||
self.amount = Number(data.amount); // amount in db format
|
||
self.debit = Number(data.debit);
|
||
self.credit = Number(data.credit);
|
||
|
||
self.orig_transdate = data.transdate; // unformatted date, needed when matching transdate filter
|
||
|
||
self.transdate = ko.observable(kivi.parse_date(data.transdate)).extend( { formatted: function(date) {
|
||
return kivi.format_date(date);
|
||
} });
|
||
// maybe directly add/precompute self.transdate_gettime, as we often use getTime() when comparing dates
|
||
|
||
self.cleared_group_id = ko.observable(data.cleared_group_id); // will be null or int. needs to be updated if json create_cleared_group was successful
|
||
|
||
self.cleared = ko.computed(function() {
|
||
return self.cleared_group_id() !== null ? true : false
|
||
}).extend({ formatted: function(val) {
|
||
return val ? '✓' : '';
|
||
} });
|
||
|
||
self.gegen_chart_accnos = data.gegen_chart_accnos;
|
||
|
||
self.employee = data.employee;
|
||
|
||
self.project = data.projectnumber === null ? null : data.projectnumber + ' ' + data.projectdescription;
|
||
self.project_id = ko.observable(Number(data.project_id));
|
||
|
||
self.toggle_selected = function() {
|
||
self.selected( !self.selected() );
|
||
}
|
||
|
||
// calculate class for css
|
||
self.xclass = ko.computed(function() {
|
||
if ( self.cleared() ) {
|
||
return 'cleared';
|
||
} else {
|
||
return self.selected() ? 'selected' : undefined;
|
||
}
|
||
});
|
||
}
|
||
|
||
// the main ViewModel
|
||
var BookingListViewModel = (function() {
|
||
var self = this;
|
||
|
||
self.precision = ko.observable(2); // used by formatted_amount bindingHandler
|
||
|
||
self.bookings = ko.observableArray([])
|
||
.extend({ fibu_sums: true, trackArrayChanges: true });
|
||
// fibu_sums adds bookings.debitSum, bookings.creditSum
|
||
|
||
self.selectedChartId = ko.observable(undefined); // bound to input of chartpicker. maybe make a computed and switch between true or false depending on whether value is seted?
|
||
// doesn't really work as a two-way binding, as it doesn't set dummy chart.displayable_name
|
||
self.selectedChart = ko.observable(); // contains the chart fat item
|
||
|
||
self.calink = ko.computed(function() {
|
||
if ( self.selectedChart() !== undefined ) {
|
||
return "ca.pl?action=list_transactions&method=cash&accno=" + self.selectedChart().accno;
|
||
} else {
|
||
return undefined;
|
||
}
|
||
});
|
||
|
||
self.redirect_chartlist = function() {
|
||
if ( self.calink() !== undefined ) {
|
||
window.location.href = self.calink();
|
||
}
|
||
}
|
||
|
||
self.selectedBookings = ko.computed(function() {
|
||
return ko.utils.arrayFilter(self.bookings(), function(booking) {
|
||
return booking.selected();
|
||
});
|
||
}).extend({ fibu_sums: true });
|
||
|
||
self.show_filter = ko.observable(true);
|
||
|
||
// settings
|
||
self.hideCleared = ko.observable(false); // whether to filter out cleared booking groups
|
||
self.automaticClearing = ko.observable(false); // automatically created a cleared_group when sum(amount) == 0
|
||
|
||
// filters
|
||
self.automaticAmountFiltering = ko.observable(false); // when clicking on a line, filter all lines which have the same amount (with opposite sign)
|
||
self.automaticDateFiltering = ko.observable(false); // when clicking on a line, filter all lines with the same date
|
||
self.automaticReferenceFiltering = ko.observable(false);
|
||
self.automaticProjectFiltering = ko.observable(false);
|
||
self.automaticEmployeeFiltering = ko.observable(false);
|
||
self.automaticDepartmentFiltering = ko.observable(false);
|
||
|
||
self.hasAutomaticFiltering = ko.computed(function() {
|
||
self.automaticAmountFiltering() ||
|
||
self.automaticDateFiltering() ||
|
||
self.automaticReferenceFiltering() ||
|
||
self.automaticEmployeeFiltering() ||
|
||
self.automaticProjectFiltering() ||
|
||
self.automaticDepartmentFiltering()
|
||
});
|
||
|
||
self.clicked_booking = ko.observable(); // needed for column line filters
|
||
|
||
self.resetClickedBooking = function() {
|
||
self.clicked_booking(undefined);
|
||
}
|
||
|
||
self.selectedClearedBookings = ko.observableArray().extend({ fibu_sums: true, trackArrayChanges: true }); // tAC needed?
|
||
|
||
self.isClearedGroupSelected = ko.computed(function() {
|
||
return self.selectedClearedBookings.hasBookings();
|
||
});
|
||
|
||
self.showSelectedBookings = ko.computed(function() {
|
||
return self.selectedBookings.hasBookings() && !self.isClearedGroupSelected();
|
||
});
|
||
|
||
// <!-- fuzzy settings with default values-->
|
||
self.fuzzyDateFilter = ko.observable(false);
|
||
self.fuzzyDateDays = ko.observable(2);
|
||
self.fuzzyAmountFilter = ko.observable(false);
|
||
self.fuzzyAmount = ko.observable(10);
|
||
|
||
self.fuzzyAmountFormatted = ko.computed({
|
||
read: function() {
|
||
return kivi.format_amount(self.fuzzyAmount(), 0);
|
||
},
|
||
write: function(formattedAmount) {
|
||
var parsed_amount = kivi.parse_amount(formattedAmount) || 1; // if user enters 0, assume he wants to disable fuzzyness, silently make it 1 to prevent divbyzero
|
||
self.fuzzyAmount(parsed_amount);
|
||
},
|
||
owner: self
|
||
});
|
||
|
||
// input fields for Column filters, searching inside results
|
||
self.searchReference = ko.observable('');
|
||
self.searchTransdate = ko.observable(null);
|
||
self.searchGegenChart = ko.observable('');
|
||
self.searchEmployee = ko.observable('');
|
||
self.searchProject = ko.observable(undefined);
|
||
self.searchAmount = ko.observable('0,00').extend({ to_kivitendo_not_zero_reformat: 2, throttle: 300 }); // will not display anything if value is 0
|
||
|
||
self.hasColumnFilter= ko.computed(function() {
|
||
return (
|
||
self.searchTransdate() !== null ||
|
||
self.searchReference() !== '' ||
|
||
self.searchGegenChart() !== '' ||
|
||
self.searchEmployee() !== '' ||
|
||
( self.searchAmount() !== '' && self.searchAmount() !== undefined ) ||
|
||
( self.searchProject() !== '' && self.searchProject() !== undefined )
|
||
);
|
||
});
|
||
|
||
self.resetColumnFilters = function() {
|
||
self.searchTransdate(null);
|
||
self.searchReference('');
|
||
self.searchGegenChart('');
|
||
self.searchEmployee('');
|
||
self.searchAmount(undefined);
|
||
self.searchProject('');
|
||
}
|
||
|
||
// ACTIONS
|
||
|
||
// action that happens when clicking on a booking
|
||
self.click = function(booking) {
|
||
if ( booking.cleared() ) {
|
||
// if there are already selected elements
|
||
// * switch group if different group_id
|
||
// * toggle group if save group_id
|
||
if ( self.selectedClearedGroupId() === booking.cleared_group_id() ) {
|
||
self.selectedClearedBookings.removeAll();
|
||
} else {
|
||
self.get_cleared_group(booking.cleared_group_id());
|
||
}
|
||
} else {
|
||
if ( self.isClearedGroupSelected() ) {
|
||
self.selectedClearedBookings.removeAll();
|
||
}
|
||
booking.toggle_selected();
|
||
|
||
if ( booking.selected() ) {
|
||
self.clicked_booking(booking);
|
||
} else {
|
||
self.resetClickedBooking();
|
||
}
|
||
}
|
||
}
|
||
|
||
self.filteredBookings = ko.computed(function () {
|
||
return ko.utils.arrayFilter(self.bookings(), function (booking) {
|
||
return (
|
||
booking.selected() // always display any line that was selected, regardless of filter
|
||
|
||
||
|
||
|
||
(
|
||
!( self.hideCleared() && booking.cleared() )
|
||
&& // header filters (manual): transdate, reference, gegenchart, employee, department, project
|
||
(
|
||
// transdate
|
||
( self.searchTransdate() === null // empty date
|
||
|| booking.transdate().getTime() === self.searchTransdate().getTime()
|
||
|| (
|
||
self.fuzzyDateFilter() && self.searchTransdate() && self.fuzzyDateDays() > 0
|
||
&& ((Math.abs( (self.searchTransdate() - booking.transdate())/(86400000) )) <= self.fuzzyDateDays())
|
||
)
|
||
)
|
||
&& // reference
|
||
( self.searchReference() && self.searchReference().length == 0
|
||
|| booking.reference.toLowerCase().indexOf(self.searchReference().toLowerCase()) > -1
|
||
)
|
||
&& // amount
|
||
// value in searchAmount, 2 modes possible: fuzzy mode or exact mode
|
||
( self.searchAmount() === undefined
|
||
||
|
||
(
|
||
( self.fuzzyAmountFilter()
|
||
&&
|
||
(
|
||
( Math.abs(Number(booking.amount)) <= Math.abs(kivi.parse_amount(self.searchAmount())) * (1 + Number(self.fuzzyAmount()/100)) )
|
||
&&
|
||
( Math.abs(Number(booking.amount)) >= Math.abs(kivi.parse_amount(self.searchAmount())) * (1 - Number(self.fuzzyAmount()/100)) )
|
||
)
|
||
)
|
||
||
|
||
(
|
||
Math.abs(Number(booking.amount)) === Math.abs(Number(kivi.parse_amount(self.searchAmount())))
|
||
)
|
||
)
|
||
)
|
||
&& // employee
|
||
( self.searchEmployee().length == 0
|
||
|| booking.employee.toLowerCase().indexOf (self.searchEmployee().toLowerCase()) > -1
|
||
)
|
||
&& // project
|
||
( ( self.searchProject() === undefined || self.searchProject() === null || self.searchProject() === '' )
|
||
|| booking.project_id() === Number(self.searchProject())
|
||
)
|
||
&& // gegenchart
|
||
( self.searchGegenChart().length == 0
|
||
|| booking.gegen_chart_accnos.toLowerCase().indexOf (self.searchGegenChart().toLowerCase()) > -1
|
||
)
|
||
)
|
||
&& ( // automatic click filters (automatic)
|
||
( // skip this whole section if nothing is selected and no automatic matching filters are selected
|
||
!self.selectedBookings.hasBookings() // skip all automatic click filter checks if nothing is selected
|
||
||
|
||
// also skip all automatic click filters if all automatic click filters are inactive
|
||
!self.hasAutomaticFiltering
|
||
)
|
||
||
|
||
( // individual automatic matching filters, we have already checked that self.clicked_booking() is valid
|
||
1 === 1
|
||
&& ( // employee filtering
|
||
!self.automaticEmployeeFiltering()
|
||
||
|
||
( self.automaticEmployeeFiltering()
|
||
&& self.clicked_booking()
|
||
&& booking.employee === self.clicked_booking().employee
|
||
)
|
||
)
|
||
|
||
&& ( // reference filtering
|
||
!self.automaticReferenceFiltering()
|
||
||
|
||
( self.automaticReferenceFiltering()
|
||
&& self.clicked_booking()
|
||
&& booking.reference === self.clicked_booking().reference
|
||
)
|
||
)
|
||
|
||
&& ( // project filtering
|
||
!self.automaticProjectFiltering()
|
||
||
|
||
// booking.project_id should always be defined, but may be 0, match all bookings without project_id (also 0)
|
||
( self.automaticProjectFiltering()
|
||
&& self.clicked_booking()
|
||
&& booking.project_id() === self.clicked_booking().project_id()
|
||
)
|
||
)
|
||
|
||
&& ( // date filtering
|
||
!self.automaticDateFiltering()
|
||
||
|
||
(
|
||
( self.automaticDateFiltering()
|
||
&& self.clicked_booking()
|
||
&& ( !self.fuzzyDateFilter()
|
||
&& self.clicked_booking().transdate().getTime() === booking.transdate().getTime()
|
||
)
|
||
||
|
||
(
|
||
self.fuzzyDateFilter() && self.fuzzyDateDays() > 0
|
||
&& ((Math.abs( (self.clicked_booking().transdate() - booking.transdate())/(86400000) )) <= self.fuzzyDateDays())
|
||
)
|
||
||
|
||
(
|
||
self.fuzzyDateFilter()
|
||
&& self.fuzzyDateDays() === '0'
|
||
&& self.clicked_booking().transdate().getTime() === booking.transdate().getTime()
|
||
)
|
||
)
|
||
)
|
||
)
|
||
|
||
&& ( // amount filtering
|
||
!self.automaticAmountFiltering()
|
||
||
|
||
(
|
||
( self.automaticAmountFiltering()
|
||
&& self.clicked_booking()
|
||
&& self.selectedBookings.hasBookings()
|
||
&& (
|
||
!self.fuzzyAmountFilter()
|
||
&&
|
||
Math.abs(self.clicked_booking().amount) === Math.abs(booking.amount)
|
||
&&
|
||
Math.sign(self.clicked_booking().amount) !== Math.sign(booking.amount)
|
||
)
|
||
||
|
||
(
|
||
self.fuzzyAmountFilter()
|
||
&&
|
||
Math.sign(self.clicked_booking().amount) !== Math.sign(booking.amount)
|
||
&&
|
||
( Math.abs(self.selectedBookings.saldo()) / Math.abs(Number(booking.amount)) > (1- Number(self.fuzzyAmount()/100)) )
|
||
&&
|
||
( Math.abs(self.selectedBookings.saldo()) / Math.abs(Number(booking.amount)) < (1+ Number(self.fuzzyAmount()/100)) )
|
||
)
|
||
)
|
||
)
|
||
) // end amount filtering
|
||
) // end of individual filters
|
||
) // automatic click filter
|
||
) //
|
||
) // return
|
||
});
|
||
}).extend( { throttle: 300, fibu_sums: true } );
|
||
|
||
// <!--------------------------- HEADERS -------------------------------->
|
||
// create headers programmatically
|
||
self.headers = ko.observable([
|
||
{title: kivi.t8('Transdate') , key: 'transdate' , datatype: 'date' , cssClass: '' },
|
||
{title: kivi.t8('Reference') , key: 'reference' , datatype: 'text' , cssClass: '' },
|
||
{title: kivi.t8('Debit') , key: 'amount' , datatype: 'numeric', cssClass: 'numeric' },
|
||
{title: kivi.t8('Credit') , key: 'amount' , datatype: 'numeric', cssClass: 'numeric' },
|
||
{title: kivi.t8('Contra accounts'), key: 'gegen_chart_accnos', datatype: 'text' , cssClass: '' },
|
||
{title: kivi.t8('Employee') , key: 'employee' , datatype: 'text' , cssClass: '' },
|
||
{title: kivi.t8('Project') , key: 'project_id' , datatype: 'numeric', cssClass: '' },
|
||
{title: kivi.t8('Cleared') , key: 'cleared' , datatype: 'boolean', cssClass: '' },
|
||
]);
|
||
|
||
self.sortHeader = ko.observable(self.headers[0]);
|
||
self.sortDirection = ko.observable(1);
|
||
self.toggleSort = function (header) {
|
||
if (header === self.sortHeader()) {
|
||
self.sortDirection(self.sortDirection() * -1);
|
||
} else {
|
||
self.sortHeader(header);
|
||
self.sortDirection(1);
|
||
}
|
||
};
|
||
|
||
// use a computed to subscribe to both self.sortHeader() and self.sortDirection()
|
||
self.sortBookings = ko.computed(function () {
|
||
var sortHeader = self.sortHeader(),
|
||
dir = self.sortDirection(),
|
||
tempBookings = self.bookings(),
|
||
prop = sortHeader ? sortHeader.key : "";
|
||
|
||
if (!prop) return;
|
||
tempBookings.sort(function (a, b) {
|
||
var va = ko.unwrap(a[prop]),
|
||
vb = ko.unwrap(b[prop]);
|
||
if ( sortHeader.key === 'amount' ) {
|
||
va = Math.abs(va);
|
||
vb = Math.abs(vb);
|
||
};
|
||
return va < vb ? -dir : va > vb ? dir : 0;
|
||
});
|
||
self.bookings.notifySubscribers();
|
||
});
|
||
|
||
// where the group_id of the currently selected cleared group is stored
|
||
self.selectedClearedGroupId = ko.computed( function() {
|
||
if ( self.isClearedGroupSelected() ) {
|
||
return self.selectedClearedBookings()[0].cleared_group_id();
|
||
} else {
|
||
return undefined;
|
||
}
|
||
});
|
||
|
||
// <!-- behaviour -->
|
||
|
||
self.deselectAll = function() {
|
||
ko.utils.arrayForEach(self.selectedBookings(), function(booking) {
|
||
if ( booking.selected() ) {
|
||
booking.selected(false);
|
||
}
|
||
});
|
||
};
|
||
|
||
self.selectAll = function() {
|
||
ko.utils.arrayForEach(self.filteredBookings(), function(booking) {
|
||
if ( !booking.selected() ) {
|
||
booking.selected(true);
|
||
}
|
||
})
|
||
};
|
||
|
||
self.deselectClearedGroup = function() {
|
||
self.selectedClearedGroupId(null);
|
||
self.selectedClearedBookings([]);
|
||
self.resetClickedBooking();
|
||
};
|
||
|
||
|
||
// <!--------- ajax actions ---------------------------------------------------->
|
||
// <!-- create_cleared_group, remove_cleared_group, get_cleared_group, update -->
|
||
|
||
self.create_cleared_group = function() {
|
||
if ( self.selectedBookings().length == 0 ) {
|
||
alert("create_cleared_group called with 0 selectedBookings, do nothing and return");
|
||
return;
|
||
};
|
||
$.ajax({
|
||
url: 'controller.pl?action=Clearing/create_cleared_group.json',
|
||
type: 'POST',
|
||
data: ko.toJSON(self.selectedBookings()),
|
||
contentType: 'application/json; charset=utf-8',
|
||
dataType: 'json',
|
||
async: false,
|
||
success: function(data) {
|
||
kivi.eval_json_result(data);
|
||
self.resetClickedBooking();
|
||
self.update();
|
||
},
|
||
error: function(data) {
|
||
alert(data);
|
||
}
|
||
});
|
||
};
|
||
|
||
self.remove_cleared_group = function() {
|
||
var current_cleared_group_id = self.selectedClearedGroupId();
|
||
$.ajax({
|
||
url: 'controller.pl?action=Clearing/remove_cleared_group.json',
|
||
type: 'POST',
|
||
data: ko.toJSON(self.selectedClearedBookings()),
|
||
contentType: 'application/json; charset=utf-8',
|
||
dataType: 'json',
|
||
async: false,
|
||
success: function(data) {
|
||
self.selectedClearedBookings([]);
|
||
kivi.eval_json_result(data); // flash
|
||
|
||
ko.utils.arrayForEach(self.bookings(), function(booking) {
|
||
if (booking.cleared_group_id() === current_cleared_group_id) {
|
||
booking.cleared_group_id(null);
|
||
}
|
||
}); //notify
|
||
self.resetClickedBooking();
|
||
},
|
||
error: function(data) {
|
||
alert('something went wrong');
|
||
}
|
||
});
|
||
}; // end of removed_cleared_group
|
||
|
||
self.get_cleared_group = function(cleared_group_id) {
|
||
var controller = 'controller.pl?action=Clearing/fetch_cleared_group';
|
||
$.getJSON(controller + '&cleared_group_id=' + cleared_group_id, function(data) {
|
||
self.selectedClearedBookings( ko.utils.arrayMap(data, function(item) { return new BookingModel(item) }) )
|
||
})
|
||
};
|
||
|
||
self.update = function() {
|
||
// kivi.clear_flash('error', 5000);
|
||
if ( !self.selectedChartId() ) {
|
||
self.bookings([]);
|
||
kivi.display_flash('error', kivi.t8('No chart selected'),0);
|
||
$("#chart_id_name").focus();
|
||
return 0;
|
||
}
|
||
var controller = 'controller.pl?action=Clearing/list';
|
||
var chart_id = $("#chart_id").val();
|
||
|
||
var filterdata = $('#clearing_filter').serialize()
|
||
|
||
var url = controller + '&' + 'chart_id=' + chart_id + '&' + filterdata;
|
||
$.getJSON(url, function(data) {
|
||
self.bookings( ko.utils.arrayMap(data, function(item) { return new BookingModel(item) }) )
|
||
})
|
||
};
|
||
|
||
self.init = function () {
|
||
ko.applyBindings(BookingListViewModel);
|
||
};
|
||
$(init);
|
||
|
||
// the returns are exposed to wm namespace!
|
||
return {
|
||
update: update,
|
||
click: click,
|
||
|
||
create_cleared_group: create_cleared_group,
|
||
remove_cleared_group: remove_cleared_group,
|
||
deselectClearedGroup: deselectClearedGroup,
|
||
|
||
selectedBookings: selectedBookings,
|
||
filteredBookings: filteredBookings,
|
||
selectedChartId: selectedChartId,
|
||
selectedChart: selectedChart,
|
||
selectedClearedGroupId: selectedClearedGroupId,
|
||
|
||
deselectAll: deselectAll,
|
||
|
||
searchProject: searchProject,
|
||
|
||
headers: headers,
|
||
sortHeader: sortHeader,
|
||
|
||
hideCleared: hideCleared,
|
||
|
||
toggleSort: toggleSort,
|
||
|
||
automaticAmountFiltering: automaticAmountFiltering,
|
||
automaticDateFiltering: automaticDateFiltering,
|
||
automaticReferenceFiltering: automaticReferenceFiltering,
|
||
automaticProjectFiltering: automaticProjectFiltering,
|
||
automaticEmployeeFiltering: automaticEmployeeFiltering,
|
||
automaticDepartmentFiltering: automaticDepartmentFiltering,
|
||
|
||
automaticClearing: automaticClearing
|
||
};
|
||
})();
|
||
|
||
|
||
$( document ).ready(function() {
|
||
|
||
$('#chart_id').on('change', function(event) {
|
||
BookingListViewModel.update();
|
||
});
|
||
|
||
$('#chart_id').on('set_item:ChartPicker', function (e, item) {
|
||
self.selectedChartId(item.id)
|
||
self.selectedChart(item)
|
||
});
|
||
|
||
$('#clearing_filter').on('change', 'input', function() {
|
||
$('form#clearing_filter').submit();
|
||
});
|
||
|
||
$('#project_id').change( function() {
|
||
BookingListViewModel.searchProject( $('#project_id').val() );
|
||
});
|
||
|
||
$('#automaticClearing').hover( function() { $('#automatic_clearing_info').toggle() });
|
||
|
||
$(document).keyup(function(event){
|
||
var keycode = (event.keyCode ? event.keyCode : event.which);
|
||
if(keycode == '13') { <!-- enter -->
|
||
if ( BookingListViewModel.selectedBookings.hasBookings() && BookingListViewModel.selectedBookings.saldo() == 0 ) {
|
||
BookingListViewModel.create_cleared_group();
|
||
}
|
||
}
|
||
if(keycode == '27') { <!-- ESC -->
|
||
if ( BookingListViewModel.selectedBookings.hasBookings() ) {
|
||
BookingListViewModel.deselectAll();
|
||
}
|
||
}
|
||
});
|
||
|
||
$('#reset_form_filter').click(function() {
|
||
document.getElementById("clearing_filter").reset();
|
||
});
|
||
|
||
// automatically call create_cleared_group when certain conditions are met:
|
||
BookingListViewModel.selectedBookings.saldo.subscribe(function(new_sum) {
|
||
if ( BookingListViewModel.automaticClearing()
|
||
&& BookingListViewModel.selectedBookings.hasBookings()
|
||
&& new_sum == 0
|
||
) {
|
||
BookingListViewModel.create_cleared_group();
|
||
}
|
||
});
|
||
});
|
js/locale/de.js | ||
---|---|---|
"Carry over shipping address":"Lieferadresse übernehmen",
|
||
"Chart picker":"Kontenauswahl",
|
||
"Clear":"Löschen",
|
||
"Cleared":"Ausgeziffert",
|
||
"Contra accounts":"Gegenkonten",
|
||
"Copy":"Kopieren",
|
||
"Copy requirement spec":"Pflichtenheft kopieren",
|
||
"Copy template":"Vorlage kopieren",
|
||
... | ... | |
"Create new quotation/order":"Neues Angebot/neuen Auftrag anlegen",
|
||
"Create new qutoation/order":"Neues Angebot/neuen Auftrag anlegen",
|
||
"Create new version":"Neue Version anlegen",
|
||
"Credit":"Haben",
|
||
"Customer details":"Kundendetails",
|
||
"Customer missing!":"Kundenname fehlt!",
|
||
"Database Connection Test":"Test der Datenbankverbindung",
|
||
"Debit":"Soll",
|
||
"Dec":"Dez",
|
||
"December":"Dezember",
|
||
"Delete":"Löschen",
|
||
... | ... | |
"Edit project link":"Projektverknüpfung bearbeiten",
|
||
"Edit text block":"Textblock bearbeiten",
|
||
"Edit the configuration for periodic invoices":"Konfiguration für wiederkehrende Rechnungen bearbeiten",
|
||
"Employee":"Bearbeiter",
|
||
"Enter longdescription":"Langtext eingeben",
|
||
"Error: #1":"Fehler: #1",
|
||
"Error: Name missing":"Fehler: Name fehlt",
|
||
... | ... | |
"Next month":"nächster Monat",
|
||
"No":"Nein",
|
||
"No article has been selected yet.":"Es wurde noch kein Artikel ausgewählt.",
|
||
"No chart selected":"Kein Konto ausgewählt",
|
||
"No delivery orders have been selected.":"Es wurden keine Lieferscheine ausgewählt.",
|
||
"No entries have been selected.":"Es wurden keine Einträge ausgewählt.",
|
||
"No file selected, please set one checkbox!":"Kein Element selektiert,bitte eine Box anklicken",
|
||
... | ... | |
"Price Types":"Preistypen",
|
||
"Print options":"Druckoptionen",
|
||
"Print record":"Beleg drucken",
|
||
"Project":"Projekt",
|
||
"Project link actions":"Projektverknüpfungs-Aktionen",
|
||
"Project picker":"Projektauswahl",
|
||
"Quotations/Orders actions":"Aktionen für Angebote/Aufträge",
|
||
"Re-numbering all sections and function blocks in the order they are currently shown cannot be undone.":"Das Neu-Nummerieren aller Abschnitte und Funktionsblöcke kann nicht rückgängig gemacht werden.",
|
||
"Reference":"Referenz",
|
||
"Remove article":"Artikel entfernen",
|
||
"Rename attachment":"Dateianhang umbenennen",
|
||
"Renumber sections and function blocks":"Abschnitte/Funktionsblöcke neu nummerieren",
|
||
... | ... | |
"Today":"heute",
|
||
"Toggle marker":"Markierung umschalten",
|
||
"Transaction description":"Vorgangsbezeichnung",
|
||
"Transdate":"Buchungsdatum",
|
||
"Transfer stock":"Lagerbewegungen",
|
||
"Tue":"Di",
|
||
"Tuesday":"Dienstag",
|
js/locale/en.js | ||
---|---|---|
"Carry over shipping address":"",
|
||
"Chart picker":"",
|
||
"Clear":"",
|
||
"Cleared":"",
|
||
"Contra accounts":"",
|
||
"Copy":"",
|
||
"Copy requirement spec":"",
|
||
"Copy template":"",
|
||
... | ... | |
"Create new quotation/order":"",
|
||
"Create new qutoation/order":"",
|
||
"Create new version":"",
|
||
"Credit":"",
|
||
"Customer details":"",
|
||
"Customer missing!":"",
|
||
"Database Connection Test":"",
|
||
"Debit":"",
|
||
"Dec":"",
|
||
"December":"",
|
||
"Delete":"",
|
||
... | ... | |
"Edit project link":"",
|
||
"Edit text block":"",
|
||
"Edit the configuration for periodic invoices":"",
|
||
"Employee":"",
|
||
"Enter longdescription":"",
|
||
"Error: #1":"",
|
||
"Error: Name missing":"",
|
||
... | ... | |
"Next month":"",
|
||
"No":"",
|
||
"No article has been selected yet.":"",
|
||
"No chart selected":"",
|
||
"No delivery orders have been selected.":"",
|
||
"No entries have been selected.":"",
|
||
"No file selected, please set one checkbox!":"",
|
||
... | ... | |
"Price Types":"",
|
||
"Print options":"",
|
||
"Print record":"",
|
||
"Project":"",
|
||
"Project link actions":"",
|
||
"Project picker":"",
|
||
"Quotations/Orders actions":"",
|
||
"Re-numbering all sections and function blocks in the order they are currently shown cannot be undone.":"",
|
||
"Reference":"",
|
||
"Remove article":"",
|
||
"Rename attachment":"",
|
||
"Renumber sections and function blocks":"",
|
||
... | ... | |
"Today":"",
|
||
"Toggle marker":"",
|
||
"Transaction description":"",
|
||
"Transdate":"Booking Date",
|
||
"Transfer stock":"",
|
||
"Tue":"",
|
||
"Tuesday":"",
|
locale/de/all | ||
---|---|---|
'Author' => 'Verfasser/in',
|
||
'Auto Send?' => 'Auto. Versand?',
|
||
'Automatic Foreign Exchange Bank Fees' => 'Automatische Bankgebühren für Auslandsüberweisungen',
|
||
'Automatic clearing' => 'Automatisch ausziffern',
|
||
'Automatic date calculation' => 'Automatische Datumsberechnung',
|
||
'Automatic deletion of leading, trailing and excessive (repetitive) spaces in customer or vendor names' => 'Automatisches Löschen von voran-/nachgestellten und aufeinanderfolgenden Leerzeichen im Kunden- oder Lieferantennamen',
|
||
'Automatic deletion of leading, trailing and excessive (repetitive) spaces in part description and part notes. Affects the CSV import as well.' => 'Automatisches Löschen von voran-/nachgestellten und aufeinanderfolgenden Leerzeichen in Artikelbeschreibungen und -bemerkungen. Betrifft auch den CSV-Import.',
|
||
... | ... | |
'Automatic skonto chart sales' => 'Skontoautomatik Verkauf',
|
||
'Automatically create new bins' => 'Automatisches Zuweisen der Lagerplätze',
|
||
'Automatically created invoice for fee and interest for dunning %s' => 'Automatisch erzeugte Rechnung für Gebühren und Zinsen zu Mahnung %s',
|
||
'Automatically filter when matching' => 'Automatisch filtern bei Gleichheit von',
|
||
'Available' => 'Verfügbar',
|
||
'Available Prices' => 'Mögliche Preise',
|
||
'Available qty' => 'Lagerbestand',
|
||
... | ... | |
'Cancel' => 'Abbrechen',
|
||
'Cancel Accounts Payables Transaction' => 'Kreditorenbuchung stornieren',
|
||
'Cancel Accounts Receivables Transaction' => 'Debitorenbuchung stornieren',
|
||
'Cancel clearing' => 'Ausziffern aufheben',
|
||
'Cancelling is disallowed. Either undo or balance the current payments until the open amount matches the invoice amount' => 'Storno verboten, da Zahlungen zum Beleg vorhanden sind. Entweder die Zahlungen löschen oder mit umgekehrten Vorzeichen ausbuchen, sodass der offene Betrag dem Rechnungsbetrag entspricht.',
|
||
'Cannot Post AP transaction with tax included!' => 'Kann diesen kreditorischen Beleg nicht mit "Steuer im Preis inbegriffen" verbuchen!',
|
||
'Cannot add Booking, reason: #1 DB: #2 ' => 'Kann die Buchung nicht hinzufügen, Grund: #1 DB: #2',
|
||
... | ... | |
'Chargenumbers' => 'Chargennummern',
|
||
'Charset' => 'Zeichensatz',
|
||
'Chart' => 'Buchungskonto',
|
||
'Chart #1 isn\'t configured for clearing' => 'Das Konto #1 ist nicht für das Ausziffern konfiguriert',
|
||
'Chart Test' => 'Konten-Test',
|
||
'Chart Type' => 'Kontentyp',
|
||
'Chart assignments' => 'Chart-Zuordnungen',
|
||
... | ... | |
'City' => 'Stadt',
|
||
'Classification' => 'Klassifizierung',
|
||
'Clear' => 'Löschen',
|
||
'Clear bookings' => 'Buchungen ausziffern',
|
||
'Clear chart' => 'Ausziffern',
|
||
'Clear fields' => 'Felder leeren',
|
||
'Cleared' => 'Ausgeziffert',
|
||
'Cleared Balance' => 'abgeschlossen',
|
||
'Cleared at' => 'Ausgeziffert am',
|
||
'Cleared bookings' => 'Buchungen ausgeziffert',
|
||
'Cleared group' => 'Ausziffergruppe',
|
||
'Cleared/uncleared only' => 'Status abgeglichen',
|
||
'Clearing Tax Received (No 71)' => 'Verrechnung des Erstattungsbetrages erwünscht (Zeile 71)',
|
||
'Clearing account for advance payments' => 'Verrechnungskonto für Anzahlungen',
|
||
... | ... | |
'Continue' => 'Weiter',
|
||
'Contra' => 'gegen',
|
||
'Contra Account' => 'Gegenkonto',
|
||
'Contra Amount' => 'Gegenbetrag',
|
||
'Contra accounts' => 'Gegenkonten',
|
||
'Contrary to Reduced Master Data this will be shown as discount in records.' => 'Im Gegensatz zu Abschlag wird der Rabatt in Belegen ausgewiesen',
|
||
'Conversion of "birthday" contact person attribute' => 'Umstellung des Kontaktpersonenfeldes "Geburtstag"',
|
||
'Conversion to PDF failed: #1' => 'Konvertierung zu PDF schlug fehl: #1',
|
||
... | ... | |
'Datev export encoding' => 'DATEV-Export Kodierung',
|
||
'Datevautomatik' => 'Datev-Automatik',
|
||
'Datum von' => 'Datum von',
|
||
'Days' => 'Tage',
|
||
'Deactivate by default' => 'Deaktiviert als Voreinstellung',
|
||
'Deadline' => 'Fristsetzung',
|
||
'Dear Sir or Madam,' => 'Sehr geehrte Damen und Herren,',
|
||
... | ... | |
'Edit bank account' => 'Bankkonto bearbeiten',
|
||
'Edit booking group' => 'Buchungsgruppe bearbeiten',
|
||
'Edit business' => 'Kunden-/Lieferantentyp bearbeiten',
|
||
'Edit chart' => 'Konto bearbeiten',
|
||
'Edit complexity' => 'Komplexitätsgrad bearbeiten',
|
||
'Edit custom report query' => 'Benutzerdefinierte Berichts-Abfrage bearbeiten',
|
||
'Edit custom shipto' => 'Individuelle Lieferadresse bearbeiten',
|
||
... | ... | |
'Error message from the webshop api:' => 'Fehlermeldung der Webshop Api',
|
||
'Error when saving: #1' => 'Fehler beim Speichern: #1',
|
||
'Error while applying year-end bookings!' => 'Fehler beim Durchführen der Abschlußbuchungen!',
|
||
'Error while clearing' => '',
|
||
'Error while creating project with project number of new order number, project number #1 already exists!' => 'Fehler beim Erstellen eines Projekts mit der Projektnummer der neuen Auftragsnummer, Projektnummer #1 existiert bereits!',
|
||
'Error while saving shop order #1. DB Error #2. Generic exception #3.' => 'Fehler beim Speichern der Shop-Bestellung #1. DB Fehler #2. Genereller Fehler #3.',
|
||
'Error with default taxzone' => 'Ungültige Standardsteuerzone',
|
||
... | ... | |
'Filter for item variables' => 'Filter für benutzerdefinierte Artikelvariablen',
|
||
'Filter parts' => 'Artikel filtern',
|
||
'Filter record template' => 'Filter für Buchungsvorlagen',
|
||
'Filtered' => 'Gefiltert',
|
||
'Final Invoice' => 'Schlussrechnung',
|
||
'Final Invoice (one letter abbreviation)' => 'F',
|
||
'Final Invoice, please use mark as paid manually' => 'Rechnungstyp Schlussrechnung, bitte den Beleg manuell als bezahlt markieren',
|
||
... | ... | |
'Function block number format' => 'Format der Funktionsblocknummerierung',
|
||
'Function/position' => 'Funktion/Position',
|
||
'Further Invoice for Advance Payment' => 'Weitere Anzahlungsrechnung',
|
||
'Fuzzy filter' => 'Unscharfer Filter',
|
||
'GL Transaction' => 'Dialogbuchung',
|
||
'GL Transaction (abbreviation)' => 'DB',
|
||
'GL Transactions' => 'Dialogbuchungen',
|
||
... | ... | |
'Hide chart details' => 'Konteninformation verstecken',
|
||
'Hide chart list' => 'Kontenliste verstecken',
|
||
'Hide charts' => 'Konten verstecken',
|
||
'Hide cleared' => 'Ausgeziffert verstecken',
|
||
'Hide details' => 'Details verbergen',
|
||
'Hide help text' => 'Hilfetext verbergen',
|
||
'Hide mappings (csv_import)' => 'Spaltenzuordnungen verbergen',
|
||
... | ... | |
'Listprice' => 'Listenpreis',
|
||
'Load' => 'Laden',
|
||
'Load an existing draft' => 'Einen bestehenden Entwurf laden',
|
||
'Load cleared bookings' => 'Ausgezifferte Buchungen laden',
|
||
'Load letter draft' => 'Briefentwurf laden',
|
||
'Load profile' => 'Profil laden',
|
||
'Loading...' => 'Wird geladen...',
|
||
... | ... | |
'No business selected or found!' => 'Kein Kunden-/Lieferantentyp ausgewählt oder gefunden!',
|
||
'No carry-over chart configured!' => 'Kein Saldenvortragskonto konfiguriert!',
|
||
'No changes since previous version.' => 'Keine Änderungen seit der letzten Version.',
|
||
'No chart selected' => 'Kein Konto ausgewählt',
|
||
'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!',
|
||
... | ... | |
'Number missing in Row' => 'Nummer fehlt in Zeile',
|
||
'Number of Data: ' => 'Anzahl Datensätze',
|
||
'Number of bins' => 'Anzahl Lagerplätze',
|
||
'Number of bookings' => 'Anzahl Buchungen',
|
||
'Number of columns of custom variables in form details (second row)' => 'Anzahl der Spalten für benutzerdef. Variablen in den Formulardetails (zweite Positionszeile)',
|
||
'Number of copies' => 'Anzahl Kopien',
|
||
'Number of data sets' => 'Anzahl Datensätze',
|
||
... | ... | |
'Please ask your administrator to create warehouses and bins.' => 'Bitten Sie Ihren Administrator, dass er Lager und Lagerplätze anlegt.',
|
||
'Please change the partnumber of the following parts and run the update again:' => 'Bitte ändern Sie daher die Artikelnummer folgender Artikel:',
|
||
'Please choose a part.' => 'Bitte wählen Sie einen Artikel aus.',
|
||
'Please choose an account for clearing:' => 'Bitte wählen Sie ein Konto zum Ausziffern aus:',
|
||
'Please choose for which categories the taxes should be displayed (otherwise remove the ticks):' => 'Bitte wählen Sie für welche Kontoart die Steuer angezeigt werden soll (ansonsten einfach die Häkchen entfernen)',
|
||
'Please choose the action to be processed for your target quantity:' => 'Bitte wählen Sie eine Aktion, die mit Ihrer gezählten Zielmenge durchgeführt werden soll:',
|
||
'Please configure the carry over and profit and loss accounts for year-end closing in the client configuration!' => 'Bitte konfigurieren Sie in der Mandantenkonfiguration das Saldenvortragskonto, das Gewinnvortragskonto und das Verlustvortragskonto!',
|
||
... | ... | |
'Reconciliation with bank' => 'Kontenabgleich mit Bank',
|
||
'Record Type' => 'Belegtyp',
|
||
'Record Vendor Invoice' => 'Einkaufsrechnung erfassen',
|
||
'Record filters' => 'Belegfilter',
|
||
'Record in' => 'Buchen auf',
|
||
'Record number' => 'Belegnummer',
|
||
'Record numbers and dates' => 'Belegnummern & Datum',
|
||
... | ... | |
'Remove' => 'Entfernen',
|
||
'Remove Draft' => 'Entwurf löschen',
|
||
'Remove article' => 'Artikel entfernen',
|
||
'Removed cleared group' => 'Ausziffergruppe erfolgreich aufgelöst',
|
||
'Removed sections and function blocks: #1' => 'Entfernte Abschnitte und Funktionsblöcke: #1',
|
||
'Removed spoolfiles!' => 'Druckdateien entfernt!',
|
||
'Removed text blocks: #1' => 'Entfernte Textblöcke: #1',
|
||
... | ... | |
'Requirement specs' => 'Pflichtenhefte',
|
||
'Reset' => 'Zurücksetzen',
|
||
'Reset Filter' => 'Filter zurücksetzen',
|
||
'Reset column filters' => 'Spaltenfilter zurücksetzen',
|
||
'Reset selected bookings' => 'Ausgewählte Buchungen zurücksetzen',
|
||
'Result' => 'Ergebnis',
|
||
'Result of SQL query' => 'Ergebnis einer SQL-Abfrage',
|
||
'Results per page' => 'Treffer pro Seite',
|
||
... | ... | |
'Select Shipping Address' => 'Lieferadresse auswählen',
|
||
'Select a Customer' => 'Endkunde auswählen',
|
||
'Select a period' => 'Bitte Zeitraum auswählen',
|
||
'Select all' => 'Alle auswählen',
|
||
'Select article' => 'Artikel auswählen',
|
||
'Select federal state...' => 'Bundesland auswählen...',
|
||
'Select file to upload' => 'Datei zum Hochladen auswählen',
|
||
... | ... | |
'entries imported' => 'Einträge importiert',
|
||
'error while disassembling for trans_ids #1 : #2' => 'Fehler beim Zerlegen von Erzeugnis für Transaktions-Id #1: #2',
|
||
'error while paying invoice #1 : ' => 'Fehler beim Bezahlen von Rechnung #1 : ',
|
||
'error while unclearing' => '',
|
||
'error while unlinking payment #1 : ' => 'Fehler beim Zurücksetzen von Zahlung #1:',
|
||
'every third month' => 'vierteljährlich',
|
||
'every time' => 'immer',
|
||
... | ... | |
'warehouse_journal_list' => 'lagerbuchungsliste',
|
||
'warehouse_report_list' => 'lagerbestandsliste',
|
||
'warehouse_usage_list' => 'Lagerentnahmeliste',
|
||
'when sum 0 is reached / bookings are balanced' => 'Wenn Summe 0 erreicht ist / Buchungen ausgeglichen sind',
|
||
'will be set upon posting' => 'wird beim Buchen vergeben',
|
||
'will be set upon saving' => 'wird beim Speichern vergeben',
|
||
'with skonto acc. to pt' => 'mit Skonto nach ZB',
|
locale/en/all | ||
---|---|---|
'Author' => '',
|
||
'Auto Send?' => '',
|
||
'Automatic Foreign Exchange Bank Fees' => '',
|
||
'Automatic clearing' => '',
|
||
'Automatic date calculation' => '',
|
||
'Automatic deletion of leading, trailing and excessive (repetitive) spaces in customer or vendor names' => '',
|
||
'Automatic deletion of leading, trailing and excessive (repetitive) spaces in part description and part notes. Affects the CSV import as well.' => '',
|
||
... | ... | |
'Automatic skonto chart sales' => '',
|
||
'Automatically create new bins' => '',
|
||
'Automatically created invoice for fee and interest for dunning %s' => '',
|
||
'Automatically filter when matching' => '',
|
||
'Available' => '',
|
||
'Available Prices' => '',
|
||
'Available qty' => '',
|
||
... | ... | |
'Cancel' => '',
|
||
'Cancel Accounts Payables Transaction' => '',
|
||
'Cancel Accounts Receivables Transaction' => '',
|
||
'Cancel clearing' => '',
|
||
'Cancelling is disallowed. Either undo or balance the current payments until the open amount matches the invoice amount' => '',
|
||
'Cannot Post AP transaction with tax included!' => '',
|
||
'Cannot add Booking, reason: #1 DB: #2 ' => '',
|
||
... | ... | |
'Chargenumbers' => '',
|
||
'Charset' => '',
|
||
'Chart' => '',
|
||
'Chart #1 isn\'t configured for clearing' => '',
|
||
'Chart Test' => '',
|
||
'Chart Type' => '',
|
||
'Chart assignments' => '',
|
||
... | ... | |
'City' => '',
|
||
'Classification' => '',
|
||
'Clear' => '',
|
||
'Clear bookings' => '',
|
||
'Clear chart' => '',
|
||
'Clear fields' => '',
|
||
'Cleared' => '',
|
||
'Cleared Balance' => '',
|
||
'Cleared at' => '',
|
||
'Cleared bookings' => '',
|
||
'Cleared group' => '',
|
||
'Cleared/uncleared only' => '',
|
||
'Clearing Tax Received (No 71)' => '',
|
||
'Clearing account for advance payments' => '',
|
||
... | ... | |
'Continue' => '',
|
||
'Contra' => '',
|
||
'Contra Account' => '',
|
||
'Contra Amount' => '',
|
||
'Contra accounts' => '',
|
||
'Contrary to Reduced Master Data this will be shown as discount in records.' => '',
|
||
'Conversion of "birthday" contact person attribute' => '',
|
||
'Conversion to PDF failed: #1' => '',
|
||
... | ... | |
'Datev export encoding' => '',
|
||
'Datevautomatik' => '',
|
||
'Datum von' => '',
|
||
'Days' => '',
|
||
'Deactivate by default' => '',
|
||
'Deadline' => '',
|
||
'Dear Sir or Madam,' => '',
|
||
... | ... | |
'Edit bank account' => '',
|
||
'Edit booking group' => '',
|
||
'Edit business' => '',
|
||
'Edit chart' => '',
|
||
'Edit complexity' => '',
|
||
'Edit custom report query' => '',
|
||
'Edit custom shipto' => '',
|
||
... | ... | |
'Error message from the webshop api:' => '',
|
||
'Error when saving: #1' => '',
|
||
'Error while applying year-end bookings!' => '',
|
||
'Error while clearing' => '',
|
||
'Error while creating project with project number of new order number, project number #1 already exists!' => '',
|
||
'Error while saving shop order #1. DB Error #2. Generic exception #3.' => '',
|
||
'Error with default taxzone' => '',
|
||
... | ... | |
'Filter for item variables' => '',
|
||
'Filter parts' => '',
|
||
'Filter record template' => '',
|
||
'Filtered' => '',
|
||
'Final Invoice' => '',
|
||
'Final Invoice (one letter abbreviation)' => '',
|
||
'Final Invoice, please use mark as paid manually' => '',
|
||
... | ... | |
'Function block number format' => '',
|
||
'Function/position' => '',
|
||
'Further Invoice for Advance Payment' => '',
|
||
'Fuzzy filter' => '',
|
||
'GL Transaction' => '',
|
||
'GL Transaction (abbreviation)' => '',
|
||
'GL Transactions' => '',
|
||
... | ... | |
'Hide chart details' => '',
|
||
'Hide chart list' => '',
|
||
'Hide charts' => '',
|
||
'Hide cleared' => '',
|
||
'Hide details' => '',
|
||
'Hide help text' => '',
|
||
'Hide mappings (csv_import)' => '',
|
||
... | ... | |
'Listprice' => '',
|
||
'Load' => '',
|
||
'Load an existing draft' => '',
|
||
'Load cleared bookings' => '',
|
||
'Load letter draft' => '',
|
||
'Load profile' => '',
|
||
'Loading...' => '',
|
||
... | ... | |
'No business selected or found!' => '',
|
||
'No carry-over chart configured!' => '',
|
||
'No changes since previous version.' => '',
|
||
'No chart selected' => '',
|
||
'No clients have been created yet.' => '',
|
||
'No contact selected to delete' => '',
|
||
'No contra account selected!' => '',
|
||
... | ... | |
'Number missing in Row' => '',
|
||
'Number of Data: ' => '',
|
||
'Number of bins' => '',
|
||
'Number of bookings' => '',
|
||
'Number of columns of custom variables in form details (second row)' => '',
|
||
'Number of copies' => '',
|
||
'Number of data sets' => '',
|
||
... | ... | |
'Please ask your administrator to create warehouses and bins.' => '',
|
||
'Please change the partnumber of the following parts and run the update again:' => '',
|
||
'Please choose a part.' => '',
|
||
'Please choose an account for clearing:' => '',
|
||
'Please choose for which categories the taxes should be displayed (otherwise remove the ticks):' => '',
|
||
'Please choose the action to be processed for your target quantity:' => '',
|
||
'Please configure the carry over and profit and loss accounts for year-end closing in the client configuration!' => '',
|
||
... | ... | |
'Reconciliation with bank' => '',
|
||
'Record Type' => '',
|
||
'Record Vendor Invoice' => '',
|
||
'Record filters' => '',
|
||
'Record in' => '',
|
||
'Record number' => '',
|
||
'Record numbers and dates' => '',
|
||
... | ... | |
'Remove' => '',
|
||
'Remove Draft' => '',
|
||
'Remove article' => '',
|
||
'Removed cleared group' => '',
|
||
'Removed sections and function blocks: #1' => '',
|
||
'Removed spoolfiles!' => '',
|
||
'Removed text blocks: #1' => '',
|
||
... | ... | |
'Requirement specs' => '',
|
||
'Reset' => '',
|
||
'Reset Filter' => '',
|
||
'Reset column filters' => '',
|
||
'Reset selected bookings' => '',
|
||
'Result' => '',
|
||
'Result of SQL query' => '',
|
||
'Results per page' => '',
|
||
... | ... | |
'Select Shipping Address' => '',
|
||
'Select a Customer' => '',
|
||
'Select a period' => '',
|
||
'Select all' => '',
|
||
'Select article' => '',
|
||
'Select federal state...' => '',
|
||
'Select file to upload' => '',
|
||
... | ... | |
'entries imported' => '',
|
||
'error while disassembling for trans_ids #1 : #2' => '',
|
||
'error while paying invoice #1 : ' => '',
|
||
'error while unclearing' => '',
|
||
'error while unlinking payment #1 : ' => '',
|
||
'every third month' => '',
|
||
'every time' => '',
|
||
... | ... | |
'warehouse_journal_list' => '',
|
||
'warehouse_report_list' => '',
|
||
'warehouse_usage_list' => '',
|
||
'when sum 0 is reached / bookings are balanced' => '',
|
||
'will be set upon posting' => '',
|
||
'will be set upon saving' => '',
|
||
'with skonto acc. to pt' => '',
|
templates/webpages/clearing/form.html | ||
---|---|---|
[%- USE HTML -%]
|
||
[%- USE LxERP -%]
|
||
[%- USE T8 -%]
|
||
[%- USE L -%]
|
||
[%- USE P -%]
|
||
|
||
[% INCLUDE 'common/flash.html' %]
|
||
|
||
[% SET style="width: 300px" %]
|
||
[% SET style2="width: 200px" %]
|
||
|
||
<h1>[% 'Clear bookings' | $T8 %]: <!-- ko if: selectedChart --><span data-bind="text: selectedChart().displayable_name"></span><!-- /ko --></h1>
|
||
|
||
<div id="chart">
|
||
<div data-bind="hidden: selectedChartId">
|
||
[% 'Please choose an account for clearing:' | $T8 %]
|
||
</div>
|
||
<div>
|
||
[% 'Chart' | $T8 %]: [% P.chart.picker('chart_id', chart_id,
|
||
fat_set_item=1,
|
||
style=style,
|
||
type='clearing'
|
||
) %]
|
||
<button type="button" data-bind="visible: selectedChartId && calink() !== undefined, click: redirect_chartlist">[% 'List Transactions' | $T8 %]</button>
|
||
</div>
|
||
</div> <!-- chart -->
|
||
|
||
<div id="top" data-bind="visible: selectedChartId">
|
||
<div id="filter">
|
||
<div data-bind="visible: false">
|
||
[% 'Precision' %]: <input data-bind="value: precision"></input>
|
||
</div>
|
||
<form id="clearing_filter" name="clearing_filter" data-bind="submit: BookingListViewModel.update">
|
||
<fieldset>
|
||
<legend>[% 'Record filters' | $T8 %] <button data-bind="toggle: show_filter"><span data-bind="text: show_filter() ? '⌃' : '⌄'"></span></button></legend>
|
||
<div data-bind="visible: show_filter">
|
||
<table class="grid">
|
||
<tbody>
|
||
<tr>
|
||
<th>[% 'Invoice Date' | $T8 %]</th>
|
||
<td>[% 'From' | $T8 %] [% L.date_tag("filter.fromdate", SELF.fromdate || FORM.filter.fromdate, class="filter") %]
|
||
[% 'Until' | $T8 %] [% L.date_tag('filter.todate', SELF.todate || FORM.filter.todate, class="filter") %]
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th>[% 'Project' | $T8 %]</th>
|
||
<td>[% P.project.picker('filter.project_id', SELF.project_id, description_style='both', style=style, class="filter") %]</td>
|
||
|
||
</tr>
|
||
[% IF SELF.all_departments.size %]
|
||
<tr>
|
||
<th>[% 'Department' | $T8 %]</th><td>[% L.select_tag('filter.department_id', SELF.all_departments, default=SELF.department_id, title_key='description', with_empty=1, style='width:300px') %]</td>
|
||
</tr>
|
||
[% END %]
|
||
<tr>
|
||
<th>[% 'Load cleared bookings' | $T8 %]</th>
|
||
<td>[% P.checkbox_tag("filter.load_cleared", value=1, checked=FORM.load_cleared, class="filter") %]</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<button type="submit" data-bind="enable: selectedChartId">[% 'Update' | $T8 %]</button>
|
||
<button type="button" id="reset_form_filter">[% 'Reset' | $T8 %]</button>
|
||
</div>
|
||
</fieldset>
|
||
</form>
|
||
</div> <!-- filter -->
|
||
</div> <!-- top -->
|
||
|
||
<div id="flexsettings" class="flex-container" data-bind="visible: selectedChartId">
|
||
<div id="settings" class="flexing">
|
||
<h2>[% 'Settings' | $T8 %]</h2>
|
||
<table>
|
||
<tr>
|
||
<td>[% 'Hide cleared' | $T8 %]:</td>
|
||
<td><input type="checkbox" data-bind="checked: hideCleared"></input>
|
||
</tr>
|
||
<tr>
|
||
<td>[% 'Automatic clearing' | $T8 %]:</td>
|
||
<td><input id="automaticClearing" type="checkbox" data-bind="checked: automaticClearing"></input>
|
||
<span style="display: none" id="automatic_clearing_info">([% 'when sum 0 is reached / bookings are balanced' | $T8 %])</span>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</div> <!-- settings flex -->
|
||
|
||
<div id="autofilters" class="flexing">
|
||
<h2>[% 'Automatically filter when matching' | $T8 %]:</h2>
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td>[% 'Contra Amount' | $T8 %]:</td><td><input type="checkbox" data-bind="checked: automaticAmountFiltering"></input></td>
|
||
<td></td>
|
||
<td>[% 'Employee' | $T8 %]:</td><td><input type="checkbox" data-bind="checked: automaticEmployeeFiltering"></input></td>
|
||
</tr>
|
||
<tr>
|
||
<td>[% 'Reference' | $T8 %]</td><td><input type="checkbox" data-bind="checked: automaticReferenceFiltering"></input></td>
|
||
<td></td>
|
||
<td>[% 'Project' | $T8 %]</td><td><input type="checkbox" data-bind="checked: automaticProjectFiltering"</input></td>
|
||
</tr>
|
||
<tr>
|
||
<td>[% 'Date' | $T8%]</td>
|
||
<td><input type="checkbox" data-bind="checked: automaticDateFiltering"></input></td>
|
||
<td></td>
|
||
<td></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div> <!-- autofilters flex -->
|
||
|
||
<div id="fuzzyfilters" class="flexing">
|
||
<h2>[% 'Fuzzy filter' | $T8 %]</h2>
|
||
<table>
|
||
<tr>
|
||
<td>[% 'Amount' | $T8 %]</td>
|
||
<td><input type="checkbox" data-bind="checked: fuzzyAmountFilter"></input>
|
||
±<input size="2" class="numeric" data-bind="value: fuzzyAmountFormatted, enable: fuzzyAmountFilter"></input>%
|
||
</tr>
|
||
<tr>
|
||
<td>[% 'Date' | $T8 %]</td>
|
||
<td><input type="checkbox" data-bind="checked: fuzzyDateFilter"></input>
|
Auch abrufbar als: Unified diff
Konten ausziffern - Controller
mit Templates, Javascript und CSS