24 |
24 |
# Datev export module
|
25 |
25 |
#======================================================================
|
26 |
26 |
|
27 |
|
package DATEV;
|
|
27 |
package SL::DATEV;
|
28 |
28 |
|
29 |
29 |
use utf8;
|
30 |
30 |
use strict;
|
... | ... | |
34 |
34 |
use SL::Taxkeys;
|
35 |
35 |
|
36 |
36 |
use Data::Dumper;
|
|
37 |
use DateTime;
|
|
38 |
use Exporter qw(import);
|
37 |
39 |
use File::Path;
|
38 |
|
use List::Util qw(max);
|
|
40 |
use List::Util qw(max sum);
|
39 |
41 |
use Time::HiRes qw(gettimeofday);
|
40 |
42 |
|
|
43 |
{
|
|
44 |
my $i = 0;
|
|
45 |
use constant {
|
|
46 |
DATEV_ET_BUCHUNGEN => $i++,
|
|
47 |
DATEV_ET_STAMM => $i++,
|
|
48 |
|
|
49 |
DATEV_FORMAT_KNE => $i++,
|
|
50 |
DATEV_FORMAT_OBE => $i++,
|
|
51 |
};
|
|
52 |
}
|
|
53 |
|
|
54 |
my @export_constants = qw(DATEV_ET_BUCHUNGEN DATEV_ET_STAMM DATEV_FORMAT_KNE DATEV_FORMAT_OBE);
|
|
55 |
our @EXPORT_OK = (@export_constants);
|
|
56 |
our %EXPORT_TAGS = (CONSTANTS => [ @export_constants ]);
|
|
57 |
|
|
58 |
|
|
59 |
sub new {
|
|
60 |
my $class = shift;
|
|
61 |
my %data = @_;
|
|
62 |
|
|
63 |
my $obj = bless {}, $class;
|
|
64 |
|
|
65 |
$obj->$_($data{$_}) for keys %data;
|
|
66 |
|
|
67 |
$obj;
|
|
68 |
}
|
|
69 |
|
|
70 |
sub exporttype {
|
|
71 |
my $self = shift;
|
|
72 |
$self->{exporttype} = $_[0] if @_;
|
|
73 |
return $self->{exporttype};
|
|
74 |
}
|
|
75 |
|
|
76 |
sub has_exporttype {
|
|
77 |
defined $_[0]->{exporttype};
|
|
78 |
}
|
|
79 |
|
|
80 |
sub format {
|
|
81 |
my $self = shift;
|
|
82 |
$self->{format} = $_[0] if @_;
|
|
83 |
return $self->{format};
|
|
84 |
}
|
|
85 |
|
|
86 |
sub has_format {
|
|
87 |
defined $_[0]->{format};
|
|
88 |
}
|
|
89 |
|
41 |
90 |
sub _get_export_path {
|
42 |
91 |
$main::lxdebug->enter_sub();
|
43 |
92 |
|
44 |
93 |
my ($a, $b) = gettimeofday();
|
45 |
|
my $path = get_path_for_download_token("${a}-${b}-${$}");
|
|
94 |
my $path = _get_path_for_download_token("${a}-${b}-${$}");
|
46 |
95 |
|
47 |
96 |
mkpath($path) unless (-d $path);
|
48 |
97 |
|
... | ... | |
51 |
100 |
return $path;
|
52 |
101 |
}
|
53 |
102 |
|
54 |
|
sub get_path_for_download_token {
|
|
103 |
sub _get_path_for_download_token {
|
55 |
104 |
$main::lxdebug->enter_sub();
|
56 |
105 |
|
57 |
|
my $token = shift;
|
|
106 |
my $token = shift || '';
|
58 |
107 |
my $path;
|
59 |
108 |
|
60 |
109 |
if ($token =~ m|^(\d+)-(\d+)-(\d+)$|) {
|
61 |
|
$path = $::lx_office_conf{paths}->{userspath} . "/datev-export-${1}-${2}-${3}";
|
|
110 |
$path = $::lx_office_conf{paths}->{userspath} . "/datev-export-${1}-${2}-${3}/";
|
62 |
111 |
}
|
63 |
112 |
|
64 |
113 |
$main::lxdebug->leave_sub();
|
... | ... | |
66 |
115 |
return $path;
|
67 |
116 |
}
|
68 |
117 |
|
69 |
|
sub get_download_token_for_path {
|
|
118 |
sub _get_download_token_for_path {
|
70 |
119 |
$main::lxdebug->enter_sub();
|
71 |
120 |
|
72 |
121 |
my $path = shift;
|
... | ... | |
81 |
130 |
return $token;
|
82 |
131 |
}
|
83 |
132 |
|
|
133 |
sub download_token {
|
|
134 |
my $self = shift;
|
|
135 |
$self->{download_token} = $_[0] if @_;
|
|
136 |
return $self->{download_token} ||= _get_download_token_for_path($self->export_path);
|
|
137 |
}
|
|
138 |
|
|
139 |
sub export_path {
|
|
140 |
my ($self) = @_;
|
|
141 |
|
|
142 |
return $self->{export_path} ||= _get_path_for_download_token($self->{download_token}) || _get_export_path();
|
|
143 |
}
|
|
144 |
|
|
145 |
sub add_filenames {
|
|
146 |
my $self = shift;
|
|
147 |
push @{ $self->{filenames} ||= [] }, @_;
|
|
148 |
}
|
|
149 |
|
|
150 |
sub filenames {
|
|
151 |
return @{ $_[0]{filenames} || [] };
|
|
152 |
}
|
|
153 |
|
|
154 |
sub add_error {
|
|
155 |
my $self = shift;
|
|
156 |
push @{ $self->{errors} ||= [] }, @_;
|
|
157 |
}
|
|
158 |
|
|
159 |
sub errors {
|
|
160 |
return @{ $_[0]{errors} || [] };
|
|
161 |
}
|
|
162 |
|
|
163 |
sub add_net_gross_differences {
|
|
164 |
my $self = shift;
|
|
165 |
push @{ $self->{net_gross_differences} ||= [] }, @_;
|
|
166 |
}
|
|
167 |
|
|
168 |
sub net_gross_differences {
|
|
169 |
return @{ $_[0]{net_gross_differences} || [] };
|
|
170 |
}
|
|
171 |
|
|
172 |
sub sum_net_gross_differences {
|
|
173 |
return sum $_[0]->net_gross_differences;
|
|
174 |
}
|
|
175 |
|
|
176 |
sub from {
|
|
177 |
my $self = shift;
|
|
178 |
|
|
179 |
if (@_) {
|
|
180 |
$self->{from} = $_[0];
|
|
181 |
}
|
|
182 |
|
|
183 |
return $self->{from};
|
|
184 |
}
|
|
185 |
|
|
186 |
sub to {
|
|
187 |
my $self = shift;
|
|
188 |
|
|
189 |
if (@_) {
|
|
190 |
$self->{to} = $_[0];
|
|
191 |
}
|
|
192 |
|
|
193 |
return $self->{to};
|
|
194 |
}
|
|
195 |
|
|
196 |
sub accnofrom {
|
|
197 |
my $self = shift;
|
|
198 |
|
|
199 |
if (@_) {
|
|
200 |
$self->{accnofrom} = $_[0];
|
|
201 |
}
|
|
202 |
|
|
203 |
return $self->{accnofrom};
|
|
204 |
}
|
|
205 |
|
|
206 |
sub accnoto {
|
|
207 |
my $self = shift;
|
|
208 |
|
|
209 |
if (@_) {
|
|
210 |
$self->{accnoto} = $_[0];
|
|
211 |
}
|
|
212 |
|
|
213 |
return $self->{accnoto};
|
|
214 |
}
|
|
215 |
|
|
216 |
|
|
217 |
sub dbh {
|
|
218 |
my $self = shift;
|
|
219 |
|
|
220 |
if (@_) {
|
|
221 |
$self->{dbh} = $_[0];
|
|
222 |
$self->{provided_dbh} = 1;
|
|
223 |
}
|
|
224 |
|
|
225 |
$self->{dbh} ||= $::form->get_standard_dbh;
|
|
226 |
}
|
|
227 |
|
|
228 |
sub provided_dbh {
|
|
229 |
$_[0]{provided_dbh};
|
|
230 |
}
|
|
231 |
|
84 |
232 |
sub clean_temporary_directories {
|
85 |
|
$main::lxdebug->enter_sub();
|
|
233 |
$::lxdebug->enter_sub;
|
86 |
234 |
|
87 |
235 |
foreach my $path (glob($::lx_office_conf{paths}->{userspath} . "/datev-export-*")) {
|
88 |
|
next unless (-d $path);
|
|
236 |
next unless -d $path;
|
89 |
237 |
|
90 |
238 |
my $mtime = (stat($path))[9];
|
91 |
239 |
next if ((time() - $mtime) < 8 * 60 * 60);
|
... | ... | |
93 |
241 |
rmtree $path;
|
94 |
242 |
}
|
95 |
243 |
|
96 |
|
$main::lxdebug->leave_sub();
|
|
244 |
$::lxdebug->leave_sub;
|
97 |
245 |
}
|
98 |
246 |
|
99 |
247 |
sub _fill {
|
... | ... | |
120 |
268 |
}
|
121 |
269 |
|
122 |
270 |
sub get_datev_stamm {
|
123 |
|
$main::lxdebug->enter_sub();
|
124 |
|
|
125 |
|
my ($self, $myconfig, $form) = @_;
|
|
271 |
return $_[0]{stamm} ||= selectfirst_hashref_query($::form, $_[0]->dbh, 'SELECT * FROM datev');
|
|
272 |
}
|
126 |
273 |
|
127 |
|
# connect to database
|
128 |
|
my $dbh = $form->dbconnect($myconfig);
|
|
274 |
sub save_datev_stamm {
|
|
275 |
my ($self, $data) = @_;
|
129 |
276 |
|
130 |
|
my $query = qq|SELECT * FROM datev|;
|
131 |
|
my $sth = $dbh->prepare($query);
|
132 |
|
$sth->execute || $form->dberror($query);
|
|
277 |
do_query($::form, $self->dbh, 'DELETE FROM datev');
|
133 |
278 |
|
134 |
|
my $ref = $sth->fetchrow_hashref("NAME_lc");
|
|
279 |
my @columns = qw(beraternr beratername dfvkz mandantennr datentraegernr abrechnungsnr);
|
135 |
280 |
|
136 |
|
map { $form->{$_} = $ref->{$_} } keys %$ref;
|
|
281 |
my $query = "INSERT INTO datev (" . join(', ', @columns) . ") VALUES (" . join(', ', ('?') x @columns) . ")";
|
|
282 |
do_query($::form, $self->dbh, $query, map { $data->{$_} } @columns);
|
137 |
283 |
|
138 |
|
$sth->finish;
|
139 |
|
$dbh->disconnect;
|
140 |
|
$main::lxdebug->leave_sub();
|
|
284 |
$self->dbh->commit unless $self->provided_dbh;
|
141 |
285 |
}
|
142 |
286 |
|
143 |
|
sub save_datev_stamm {
|
144 |
|
$main::lxdebug->enter_sub();
|
|
287 |
sub export {
|
|
288 |
my ($self) = @_;
|
|
289 |
my $result;
|
145 |
290 |
|
146 |
|
my ($self, $myconfig, $form) = @_;
|
147 |
|
|
148 |
|
# connect to database
|
149 |
|
my $dbh = $form->dbconnect_noauto($myconfig);
|
150 |
|
|
151 |
|
my $query = qq|DELETE FROM datev|;
|
152 |
|
$dbh->do($query) || $form->dberror($query);
|
153 |
|
|
154 |
|
$query = qq|INSERT INTO datev
|
155 |
|
(beraternr, beratername, dfvkz, mandantennr, datentraegernr, abrechnungsnr) VALUES
|
156 |
|
(|
|
157 |
|
. $dbh->quote($form->{beraternr}) . qq|,|
|
158 |
|
. $dbh->quote($form->{beratername}) . qq|,|
|
159 |
|
. $dbh->quote($form->{dfvkz}) . qq|,
|
160 |
|
|
|
161 |
|
. $dbh->quote($form->{mandantennr}) . qq|,|
|
162 |
|
. $dbh->quote($form->{datentraegernr}) . qq|,|
|
163 |
|
. $dbh->quote($form->{abrechnungsnr}) . qq|)|;
|
164 |
|
my $sth = $dbh->prepare($query);
|
165 |
|
$sth->execute || $form->dberror($query);
|
166 |
|
$sth->finish;
|
|
291 |
die 'no format set!' unless $self->has_format;
|
167 |
292 |
|
168 |
|
$dbh->commit;
|
169 |
|
$dbh->disconnect;
|
170 |
|
$main::lxdebug->leave_sub();
|
|
293 |
if ($self->format == DATEV_FORMAT_KNE) {
|
|
294 |
$result = $self->kne_export;
|
|
295 |
} elsif ($self->format == DATEV_FORMAT_OBE) {
|
|
296 |
$result = $self->obe_export;
|
|
297 |
} else {
|
|
298 |
die 'unrecognized export format';
|
|
299 |
}
|
|
300 |
|
|
301 |
return $result;
|
171 |
302 |
}
|
172 |
303 |
|
173 |
304 |
sub kne_export {
|
174 |
|
$main::lxdebug->enter_sub();
|
175 |
|
|
176 |
|
my ($self, $myconfig, $form) = @_;
|
|
305 |
my ($self) = @_;
|
177 |
306 |
my $result;
|
178 |
307 |
|
179 |
|
if ($form->{exporttype} == 0) {
|
180 |
|
$result = kne_buchungsexport($myconfig, $form);
|
|
308 |
die 'no exporttype set!' unless $self->has_exporttype;
|
|
309 |
|
|
310 |
if ($self->exporttype == DATEV_ET_BUCHUNGEN) {
|
|
311 |
$result = $self->kne_buchungsexport;
|
|
312 |
} elsif ($self->exporttype == DATEV_ET_STAMM) {
|
|
313 |
$result = $self->kne_stammdatenexport;
|
181 |
314 |
} else {
|
182 |
|
$result = kne_stammdatenexport($myconfig, $form);
|
|
315 |
die 'unrecognized exporttype';
|
183 |
316 |
}
|
184 |
317 |
|
185 |
|
$main::lxdebug->leave_sub();
|
186 |
|
|
187 |
318 |
return $result;
|
188 |
319 |
}
|
189 |
320 |
|
190 |
321 |
sub obe_export {
|
191 |
|
$main::lxdebug->enter_sub();
|
192 |
|
|
193 |
|
my ($self, $myconfig, $form) = @_;
|
194 |
|
|
195 |
|
# connect to database
|
196 |
|
my $dbh = $form->dbconnect_noauto($myconfig);
|
197 |
|
$dbh->commit;
|
198 |
|
$dbh->disconnect;
|
199 |
|
$main::lxdebug->leave_sub();
|
|
322 |
die 'not yet implemented';
|
200 |
323 |
}
|
201 |
324 |
|
202 |
|
sub get_dates {
|
203 |
|
$main::lxdebug->enter_sub();
|
204 |
|
|
205 |
|
my ($zeitraum, $monat, $quartal, $transdatefrom, $transdateto) = @_;
|
206 |
|
my ($fromto, $jahr, $leap);
|
207 |
|
|
208 |
|
my $form = $main::form;
|
209 |
|
|
210 |
|
$fromto = "transdate >= ";
|
211 |
|
|
212 |
|
my @a = localtime;
|
213 |
|
$a[5] += 1900;
|
214 |
|
$jahr = $a[5];
|
215 |
|
if ($zeitraum eq "monat") {
|
216 |
|
SWITCH: {
|
217 |
|
$monat eq "1" && do {
|
218 |
|
$form->{fromdate} = "1.1.$jahr";
|
219 |
|
$form->{todate} = "31.1.$jahr";
|
220 |
|
last SWITCH;
|
221 |
|
};
|
222 |
|
$monat eq "2" && do {
|
223 |
|
$form->{fromdate} = "1.2.$jahr";
|
224 |
|
|
225 |
|
#this works from 1901 to 2099, 1900 and 2100 fail.
|
226 |
|
$leap = ($jahr % 4 == 0) ? "29" : "28";
|
227 |
|
$form->{todate} = "$leap.2.$jahr";
|
228 |
|
last SWITCH;
|
229 |
|
};
|
230 |
|
$monat eq "3" && do {
|
231 |
|
$form->{fromdate} = "1.3.$jahr";
|
232 |
|
$form->{todate} = "31.3.$jahr";
|
233 |
|
last SWITCH;
|
234 |
|
};
|
235 |
|
$monat eq "4" && do {
|
236 |
|
$form->{fromdate} = "1.4.$jahr";
|
237 |
|
$form->{todate} = "30.4.$jahr";
|
238 |
|
last SWITCH;
|
239 |
|
};
|
240 |
|
$monat eq "5" && do {
|
241 |
|
$form->{fromdate} = "1.5.$jahr";
|
242 |
|
$form->{todate} = "31.5.$jahr";
|
243 |
|
last SWITCH;
|
244 |
|
};
|
245 |
|
$monat eq "6" && do {
|
246 |
|
$form->{fromdate} = "1.6.$jahr";
|
247 |
|
$form->{todate} = "30.6.$jahr";
|
248 |
|
last SWITCH;
|
249 |
|
};
|
250 |
|
$monat eq "7" && do {
|
251 |
|
$form->{fromdate} = "1.7.$jahr";
|
252 |
|
$form->{todate} = "31.7.$jahr";
|
253 |
|
last SWITCH;
|
254 |
|
};
|
255 |
|
$monat eq "8" && do {
|
256 |
|
$form->{fromdate} = "1.8.$jahr";
|
257 |
|
$form->{todate} = "31.8.$jahr";
|
258 |
|
last SWITCH;
|
259 |
|
};
|
260 |
|
$monat eq "9" && do {
|
261 |
|
$form->{fromdate} = "1.9.$jahr";
|
262 |
|
$form->{todate} = "30.9.$jahr";
|
263 |
|
last SWITCH;
|
264 |
|
};
|
265 |
|
$monat eq "10" && do {
|
266 |
|
$form->{fromdate} = "1.10.$jahr";
|
267 |
|
$form->{todate} = "31.10.$jahr";
|
268 |
|
last SWITCH;
|
269 |
|
};
|
270 |
|
$monat eq "11" && do {
|
271 |
|
$form->{fromdate} = "1.11.$jahr";
|
272 |
|
$form->{todate} = "30.11.$jahr";
|
273 |
|
last SWITCH;
|
274 |
|
};
|
275 |
|
$monat eq "12" && do {
|
276 |
|
$form->{fromdate} = "1.12.$jahr";
|
277 |
|
$form->{todate} = "31.12.$jahr";
|
278 |
|
last SWITCH;
|
279 |
|
};
|
280 |
|
}
|
281 |
|
$fromto .=
|
282 |
|
"'" . $form->{fromdate} . "' and transdate <= '" . $form->{todate} . "'";
|
283 |
|
}
|
284 |
|
|
285 |
|
elsif ($zeitraum eq "quartal") {
|
286 |
|
if ($quartal == 1) {
|
287 |
|
$fromto .=
|
288 |
|
"'01.01." . $jahr . "' and transdate <= '31.03." . $jahr . "'";
|
289 |
|
} elsif ($quartal == 2) {
|
290 |
|
$fromto .=
|
291 |
|
"'01.04." . $jahr . "' and transdate <= '30.06." . $jahr . "'";
|
292 |
|
} elsif ($quartal == 3) {
|
293 |
|
$fromto .=
|
294 |
|
"'01.07." . $jahr . "' and transdate <= '30.09." . $jahr . "'";
|
295 |
|
} elsif ($quartal == 4) {
|
296 |
|
$fromto .=
|
297 |
|
"'01.10." . $jahr . "' and transdate <= '31.12." . $jahr . "'";
|
298 |
|
}
|
299 |
|
}
|
300 |
|
|
301 |
|
elsif ($zeitraum eq "zeit") {
|
302 |
|
$fromto .= "'" . $transdatefrom . "' and transdate <= '" . $transdateto . "'";
|
303 |
|
my ($yy, $mm, $dd) = $main::locale->parse_date(\%main::myconfig, $transdatefrom);
|
304 |
|
$jahr = $yy;
|
305 |
|
}
|
|
325 |
sub fromto {
|
|
326 |
my ($self) = @_;
|
306 |
327 |
|
307 |
|
$main::lxdebug->leave_sub();
|
|
328 |
return unless $self->from && $self->to;
|
308 |
329 |
|
309 |
|
return ($fromto, $jahr);
|
|
330 |
return "transdate >= '" . $self->from->to_lxoffice . "' and transdate <= '" . $self->to->to_lxoffice . "'";
|
310 |
331 |
}
|
311 |
332 |
|
312 |
333 |
sub _sign {
|
313 |
|
my $value = shift;
|
314 |
|
|
315 |
|
return $value < 0 ? -1
|
316 |
|
: $value > 0 ? 1
|
317 |
|
: 0;
|
|
334 |
$_[0] <=> 0;
|
318 |
335 |
}
|
319 |
336 |
|
320 |
337 |
sub _get_transactions {
|
321 |
338 |
$main::lxdebug->enter_sub();
|
322 |
|
|
|
339 |
my $self = shift;
|
323 |
340 |
my $fromto = shift;
|
|
341 |
my $progress_callback = shift || sub {};
|
324 |
342 |
|
325 |
|
my $myconfig = \%main::myconfig;
|
326 |
343 |
my $form = $main::form;
|
327 |
344 |
|
328 |
|
my $dbh = $form->get_standard_dbh($myconfig);
|
329 |
|
|
330 |
345 |
my ($notsplitindex);
|
331 |
|
my @errors = ();
|
332 |
|
|
333 |
|
$form->{net_gross_differences} = [];
|
334 |
|
$form->{sum_net_gross_differences} = 0;
|
335 |
346 |
|
336 |
347 |
$fromto =~ s/transdate/ac\.transdate/g;
|
337 |
348 |
|
338 |
349 |
my $taxkeys = Taxkeys->new();
|
339 |
350 |
my $filter = ''; # Useful for debugging purposes
|
340 |
351 |
|
341 |
|
my %all_taxchart_ids = selectall_as_map($form, $dbh, qq|SELECT DISTINCT chart_id, TRUE AS is_set FROM tax|, 'chart_id', 'is_set');
|
|
352 |
my %all_taxchart_ids = selectall_as_map($form, $self->dbh, qq|SELECT DISTINCT chart_id, TRUE AS is_set FROM tax|, 'chart_id', 'is_set');
|
342 |
353 |
|
343 |
354 |
my $query =
|
344 |
355 |
qq|SELECT ac.acc_trans_id, ac.transdate, ac.trans_id,ar.id, ac.amount, ac.taxkey,
|
... | ... | |
385 |
396 |
|
386 |
397 |
ORDER BY trans_id, acc_trans_id|;
|
387 |
398 |
|
388 |
|
my $sth = prepare_execute_query($form, $dbh, $query);
|
389 |
|
$form->{DATEV} = [];
|
|
399 |
my $sth = prepare_execute_query($form, $self->dbh, $query);
|
|
400 |
$self->{DATEV} = [];
|
390 |
401 |
|
391 |
402 |
my $counter = 0;
|
392 |
403 |
while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
|
393 |
404 |
$counter++;
|
394 |
405 |
if (($counter % 500) == 0) {
|
395 |
|
print("$counter ");
|
|
406 |
$progress_callback->($counter);
|
396 |
407 |
}
|
397 |
408 |
|
398 |
409 |
my $trans = [ $ref ];
|
... | ... | |
406 |
417 |
last unless ($ref2);
|
407 |
418 |
|
408 |
419 |
if ($ref2->{trans_id} != $trans->[0]->{trans_id}) {
|
409 |
|
$form->error("Unbalanced ledger! old trans_id " . $trans->[0]->{trans_id} . " new trans_id " . $ref2->{trans_id} . " count $count");
|
410 |
|
::end_of_request();
|
|
420 |
$self->add_error("Unbalanced ledger! old trans_id " . $trans->[0]->{trans_id} . " new trans_id " . $ref2->{trans_id} . " count $count");
|
|
421 |
return;
|
411 |
422 |
}
|
412 |
423 |
|
413 |
424 |
push @{ $trans }, $ref2;
|
... | ... | |
437 |
448 |
my %taxid_taxkeys = ();
|
438 |
449 |
my $absumsatz = 0;
|
439 |
450 |
if (scalar(@{$trans}) <= 2) {
|
440 |
|
push @{ $form->{DATEV} }, $trans;
|
|
451 |
push @{ $self->{DATEV} }, $trans;
|
441 |
452 |
next;
|
442 |
453 |
}
|
443 |
454 |
|
... | ... | |
471 |
482 |
$new_trans{'umsatz'} = abs($trans->[$j]->{'amount'}) * $ml;
|
472 |
483 |
$trans->[$j]->{'umsatz'} = abs($trans->[$j]->{'amount'}) * $ml;
|
473 |
484 |
|
474 |
|
push @{ $form->{DATEV} }, [ \%new_trans, $trans->[$j] ];
|
|
485 |
push @{ $self->{DATEV} }, [ \%new_trans, $trans->[$j] ];
|
475 |
486 |
|
476 |
487 |
} elsif (($j != $notsplitindex) && !$trans->[$j]->{is_tax}) {
|
477 |
488 |
my %tax_info = $taxkeys->get_full_tax_info('transdate' => $trans->[$j]->{transdate});
|
... | ... | |
500 |
511 |
$absumsatz -= $rounded;
|
501 |
512 |
}
|
502 |
513 |
|
503 |
|
push @{ $form->{DATEV} }, [ \%new_trans, $trans->[$j] ];
|
504 |
|
push @taxed, $form->{DATEV}->[-1];
|
|
514 |
push @{ $self->{DATEV} }, [ \%new_trans, $trans->[$j] ];
|
|
515 |
push @taxed, $self->{DATEV}->[-1];
|
505 |
516 |
}
|
506 |
517 |
}
|
507 |
518 |
|
... | ... | |
545 |
556 |
|
546 |
557 |
$absumsatz = $form->round_amount($absumsatz, 2);
|
547 |
558 |
if (abs($absumsatz) >= (0.01 * (1 + scalar @taxed))) {
|
548 |
|
push @errors, "Datev-Export fehlgeschlagen! Bei Transaktion $trans->[0]->{trans_id} ($absumsatz)\n";
|
|
559 |
$self->add_error("Datev-Export fehlgeschlagen! Bei Transaktion $trans->[0]->{trans_id} ($absumsatz)");
|
549 |
560 |
|
550 |
561 |
} elsif (abs($absumsatz) >= 0.01) {
|
551 |
|
push @{ $form->{net_gross_differences} }, $absumsatz;
|
552 |
|
$form->{sum_net_gross_differences} += $absumsatz;
|
|
562 |
$self->add_net_gross_differences($absumsatz);
|
553 |
563 |
}
|
554 |
564 |
}
|
555 |
565 |
|
556 |
566 |
$sth->finish();
|
557 |
567 |
|
558 |
|
$form->error(join("<br>\n", @errors)) if (@errors);
|
559 |
|
|
560 |
|
$main::lxdebug->leave_sub();
|
|
568 |
$::lxdebug->leave_sub;
|
561 |
569 |
}
|
562 |
570 |
|
563 |
571 |
sub make_kne_data_header {
|
564 |
572 |
$main::lxdebug->enter_sub();
|
565 |
573 |
|
566 |
|
my ($myconfig, $form, $fromto, $start_jahr) = @_;
|
|
574 |
my ($self, $form) = @_;
|
567 |
575 |
my ($primanota);
|
568 |
576 |
|
569 |
|
my $jahr = $start_jahr;
|
570 |
|
if (!$jahr) {
|
571 |
|
my @a = localtime;
|
572 |
|
$jahr = $a[5];
|
573 |
|
}
|
|
577 |
my $stamm = $self->get_datev_stamm;
|
|
578 |
|
|
579 |
my $jahr = $self->from ? $self->from->year : DateTime->today->year;
|
574 |
580 |
|
575 |
581 |
#Header
|
576 |
582 |
my $header = "\x1D\x181";
|
577 |
|
$header .= _fill($form->{datentraegernr}, 3, ' ', 'left');
|
578 |
|
$header .= ($fromto) ? "11" : "13"; # Anwendungsnummer
|
579 |
|
$header .= _fill($form->{dfvkz}, 2, '0');
|
580 |
|
$header .= _fill($form->{beraternr}, 7, '0');
|
581 |
|
$header .= _fill($form->{mandantennr}, 5, '0');
|
582 |
|
$header .= _fill($form->{abrechnungsnr} . $jahr, 6, '0');
|
583 |
|
|
584 |
|
$fromto =~ s/transdate|>=|and|\'|<=//g;
|
585 |
|
my ($from, $to) = split / /, $fromto;
|
586 |
|
$from =~ s/ //g;
|
587 |
|
$to =~ s/ //g;
|
588 |
|
|
589 |
|
if ($from ne "") {
|
590 |
|
my ($fday, $fmonth, $fyear) = split(/\./, $from);
|
591 |
|
if (length($fmonth) < 2) {
|
592 |
|
$fmonth = "0" . $fmonth;
|
593 |
|
}
|
594 |
|
if (length($fday) < 2) {
|
595 |
|
$fday = "0" . $fday;
|
596 |
|
}
|
597 |
|
$from = $fday . $fmonth . substr($fyear, -2, 2);
|
598 |
|
} else {
|
599 |
|
$from = "";
|
600 |
|
}
|
|
583 |
$header .= _fill($stamm->{datentraegernr}, 3, ' ', 'left');
|
|
584 |
$header .= ($self->fromto) ? "11" : "13"; # Anwendungsnummer
|
|
585 |
$header .= _fill($stamm->{dfvkz}, 2, '0');
|
|
586 |
$header .= _fill($stamm->{beraternr}, 7, '0');
|
|
587 |
$header .= _fill($stamm->{mandantennr}, 5, '0');
|
|
588 |
$header .= _fill($stamm->{abrechnungsnr} . $jahr, 6, '0');
|
601 |
589 |
|
602 |
|
$header .= $from;
|
|
590 |
$header .= $self->from ? $self->from->strftime('%d%m%y') : '';
|
|
591 |
$header .= $self->to ? $self->to->strftime('%d%m%y') : '';
|
603 |
592 |
|
604 |
|
if ($to ne "") {
|
605 |
|
my ($tday, $tmonth, $tyear) = split(/\./, $to);
|
606 |
|
if (length($tmonth) < 2) {
|
607 |
|
$tmonth = "0" . $tmonth;
|
608 |
|
}
|
609 |
|
if (length($tday) < 2) {
|
610 |
|
$tday = "0" . $tday;
|
611 |
|
}
|
612 |
|
$to = $tday . $tmonth . substr($tyear, -2, 2);
|
613 |
|
} else {
|
614 |
|
$to = "";
|
615 |
|
}
|
616 |
|
$header .= $to;
|
617 |
|
|
618 |
|
if ($fromto ne "") {
|
|
593 |
if ($self->fromto) {
|
619 |
594 |
$primanota = "001";
|
620 |
595 |
$header .= $primanota;
|
621 |
596 |
}
|
622 |
597 |
|
623 |
|
$header .= _fill($form->{passwort}, 4, '0');
|
|
598 |
$header .= _fill($stamm->{passwort}, 4, '0');
|
624 |
599 |
$header .= " " x 16; # Anwendungsinfo
|
625 |
600 |
$header .= " " x 16; # Inputinfo
|
626 |
601 |
$header .= "\x79";
|
627 |
602 |
|
628 |
603 |
#Versionssatz
|
629 |
|
my $versionssatz = $form->{exporttype} == 0 ? "\xB5" . "1," : "\xB6" . "1,";
|
|
604 |
my $versionssatz = $self->exporttype == DATEV_ET_BUCHUNGEN ? "\xB5" . "1," : "\xB6" . "1,";
|
630 |
605 |
|
631 |
|
my $dbh = $form->get_standard_dbh($myconfig);
|
632 |
606 |
my $query = qq|SELECT accno FROM chart LIMIT 1|;
|
633 |
|
my $ref = selectfirst_hashref_query($form, $dbh, $query);
|
|
607 |
my $ref = selectfirst_hashref_query($form, $self->dbh, $query);
|
634 |
608 |
|
635 |
609 |
$versionssatz .= length $ref->{accno};
|
636 |
610 |
$versionssatz .= ",";
|
... | ... | |
683 |
657 |
sub make_ed_versionset {
|
684 |
658 |
$main::lxdebug->enter_sub();
|
685 |
659 |
|
686 |
|
my ($header, $filename, $blockcount, $fromto) = @_;
|
|
660 |
my ($self, $header, $filename, $blockcount) = @_;
|
687 |
661 |
|
688 |
662 |
my $versionset = "V" . substr($filename, 2, 5);
|
689 |
663 |
$versionset .= substr($header, 6, 22);
|
690 |
664 |
|
691 |
|
if ($fromto ne "") {
|
|
665 |
if ($self->fromto) {
|
692 |
666 |
$versionset .= "0000" . substr($header, 28, 19);
|
693 |
667 |
} else {
|
694 |
668 |
my $datum = " " x 16;
|
... | ... | |
709 |
683 |
sub make_ev_header {
|
710 |
684 |
$main::lxdebug->enter_sub();
|
711 |
685 |
|
712 |
|
my ($form, $fileno) = @_;
|
|
686 |
my ($self, $form, $fileno) = @_;
|
|
687 |
|
|
688 |
my $stamm = $self->get_datev_stamm;
|
713 |
689 |
|
714 |
|
my $ev_header = _fill($form->{datentraegernr}, 3, ' ', 'left');
|
|
690 |
my $ev_header = _fill($stamm->{datentraegernr}, 3, ' ', 'left');
|
715 |
691 |
$ev_header .= " ";
|
716 |
|
$ev_header .= _fill($form->{beraternr}, 7, ' ', 'left');
|
717 |
|
$ev_header .= _fill($form->{beratername}, 9, ' ', 'left');
|
|
692 |
$ev_header .= _fill($stamm->{beraternr}, 7, ' ', 'left');
|
|
693 |
$ev_header .= _fill($stamm->{beratername}, 9, ' ', 'left');
|
718 |
694 |
$ev_header .= " ";
|
719 |
695 |
$ev_header .= (_fill($fileno, 5, '0')) x 2;
|
720 |
696 |
$ev_header .= " " x 95;
|
... | ... | |
727 |
703 |
sub kne_buchungsexport {
|
728 |
704 |
$main::lxdebug->enter_sub();
|
729 |
705 |
|
730 |
|
my ($myconfig, $form) = @_;
|
|
706 |
my ($self) = @_;
|
|
707 |
|
|
708 |
my $form = $::form;
|
731 |
709 |
|
732 |
710 |
my @filenames;
|
733 |
711 |
|
734 |
|
my $export_path = _get_export_path() . "/";
|
735 |
712 |
my $filename = "ED00000";
|
736 |
713 |
my $evfile = "EV01";
|
737 |
714 |
my @ed_versionset;
|
738 |
715 |
my $fileno = 0;
|
739 |
716 |
|
740 |
|
$form->header;
|
741 |
|
print qq|
|
742 |
|
<html>
|
743 |
|
<body>Export in Bearbeitung<br>
|
744 |
|
Buchungssätze verarbeitet:
|
745 |
|
|;
|
746 |
|
|
747 |
|
my ($fromto, $start_jahr) =
|
748 |
|
&get_dates($form->{zeitraum}, $form->{monat},
|
749 |
|
$form->{quartal}, $form->{transdatefrom},
|
750 |
|
$form->{transdateto});
|
751 |
|
_get_transactions($fromto);
|
|
717 |
my $fromto = $self->fromto;
|
|
718 |
|
|
719 |
$self->_get_transactions($fromto);
|
|
720 |
|
|
721 |
return if $self->errors;
|
|
722 |
|
752 |
723 |
my $counter = 0;
|
753 |
|
print qq|<br>2. Durchlauf:|;
|
754 |
|
while (scalar(@{ $form->{DATEV} })) {
|
|
724 |
|
|
725 |
while (scalar(@{ $self->{DATEV} || [] })) {
|
755 |
726 |
my $umsatzsumme = 0;
|
756 |
727 |
$filename++;
|
757 |
|
my $ed_filename = $export_path . $filename;
|
|
728 |
my $ed_filename = $self->export_path . $filename;
|
758 |
729 |
push(@filenames, $filename);
|
759 |
|
my $header = &make_kne_data_header($myconfig, $form, $fromto, $start_jahr);
|
|
730 |
my $header = $self->make_kne_data_header($form);
|
760 |
731 |
|
761 |
732 |
my $kne_file = SL::DATEV::KNEFile->new();
|
762 |
733 |
$kne_file->add_block($header);
|
763 |
734 |
|
764 |
|
while (scalar(@{ $form->{DATEV} }) > 0) {
|
765 |
|
my $transaction = shift @{ $form->{DATEV} };
|
|
735 |
while (scalar(@{ $self->{DATEV} }) > 0) {
|
|
736 |
my $transaction = shift @{ $self->{DATEV} };
|
766 |
737 |
my $trans_lines = scalar(@{$transaction});
|
767 |
738 |
$counter++;
|
768 |
|
if (($counter % 500) == 0) {
|
769 |
|
print("$counter ");
|
770 |
|
}
|
771 |
739 |
|
772 |
740 |
my $umsatz = 0;
|
773 |
741 |
my $gegenkonto = "";
|
... | ... | |
885 |
853 |
print(ED $kne_file->get_data());
|
886 |
854 |
close(ED);
|
887 |
855 |
|
888 |
|
$ed_versionset[$fileno] = &make_ed_versionset($header, $filename, $kne_file->get_block_count(), $fromto);
|
|
856 |
$ed_versionset[$fileno] = $self->make_ed_versionset($header, $filename, $kne_file->get_block_count());
|
889 |
857 |
$fileno++;
|
890 |
858 |
}
|
891 |
859 |
|
892 |
860 |
#Make EV Verwaltungsdatei
|
893 |
|
my $ev_header = &make_ev_header($form, $fileno);
|
894 |
|
my $ev_filename = $export_path . $evfile;
|
|
861 |
my $ev_header = $self->make_ev_header($form, $fileno);
|
|
862 |
my $ev_filename = $self->export_path . $evfile;
|
895 |
863 |
push(@filenames, $evfile);
|
896 |
864 |
open(EV, ">", $ev_filename) or die "can't open outputfile: EV01\n";
|
897 |
865 |
print(EV $ev_header);
|
... | ... | |
900 |
868 |
print(EV $ed_versionset[$file]);
|
901 |
869 |
}
|
902 |
870 |
close(EV);
|
903 |
|
print qq|<br>Done. <br>
|
904 |
|
|;
|
905 |
871 |
###
|
|
872 |
|
|
873 |
$self->add_filenames(@filenames);
|
|
874 |
|
906 |
875 |
$main::lxdebug->leave_sub();
|
907 |
876 |
|
908 |
|
return { 'download_token' => get_download_token_for_path($export_path), 'filenames' => \@filenames };
|
|
877 |
return { 'download_token' => $self->download_token, 'filenames' => \@filenames };
|
909 |
878 |
}
|
910 |
879 |
|
911 |
880 |
sub kne_stammdatenexport {
|
912 |
881 |
$main::lxdebug->enter_sub();
|
913 |
882 |
|
914 |
|
my ($myconfig, $form) = @_;
|
915 |
|
$form->{abrechnungsnr} = "99";
|
|
883 |
my ($self) = @_;
|
|
884 |
my $form = $::form;
|
916 |
885 |
|
917 |
|
$form->header;
|
918 |
|
print qq|
|
919 |
|
<html>
|
920 |
|
<body>Export in Bearbeitung<br>
|
921 |
|
|;
|
|
886 |
$self->get_datev_stamm->{abrechnungsnr} = "99";
|
922 |
887 |
|
923 |
888 |
my @filenames;
|
924 |
889 |
|
925 |
|
my $export_path = _get_export_path() . "/";
|
926 |
890 |
my $filename = "ED00000";
|
927 |
891 |
my $evfile = "EV01";
|
928 |
892 |
my @ed_versionset;
|
... | ... | |
933 |
897 |
my $total_bytes = 256;
|
934 |
898 |
my $buchungssatz = "";
|
935 |
899 |
$filename++;
|
936 |
|
my $ed_filename = $export_path . $filename;
|
|
900 |
my $ed_filename = $self->export_path . $filename;
|
937 |
901 |
push(@filenames, $filename);
|
938 |
902 |
open(ED, ">", $ed_filename) or die "can't open outputfile: $!\n";
|
939 |
|
my $header = &make_kne_data_header($myconfig, $form, "");
|
|
903 |
my $header = $self->make_kne_data_header($form);
|
940 |
904 |
$remaining_bytes -= length($header);
|
941 |
905 |
|
942 |
906 |
my $fuellzeichen;
|
943 |
|
our $fromto;
|
944 |
|
|
945 |
|
# connect to database
|
946 |
|
my $dbh = $form->dbconnect($myconfig);
|
947 |
907 |
|
948 |
908 |
my (@where, @values) = ((), ());
|
949 |
|
if ($form->{accnofrom}) {
|
|
909 |
if ($self->accnofrom) {
|
950 |
910 |
push @where, 'c.accno >= ?';
|
951 |
|
push @values, $form->{accnofrom};
|
|
911 |
push @values, $self->accnofrom;
|
952 |
912 |
}
|
953 |
|
if ($form->{accnoto}) {
|
|
913 |
if ($self->accnoto) {
|
954 |
914 |
push @where, 'c.accno <= ?';
|
955 |
|
push @values, $form->{accnoto};
|
|
915 |
push @values, $self->accnoto;
|
956 |
916 |
}
|
957 |
917 |
|
958 |
918 |
my $where_str = @where ? ' WHERE ' . join(' AND ', map { "($_)" } @where) : '';
|
... | ... | |
962 |
922 |
$where_str
|
963 |
923 |
ORDER BY c.accno|;
|
964 |
924 |
|
965 |
|
my $sth = $dbh->prepare($query);
|
|
925 |
my $sth = $self->dbh->prepare($query);
|
966 |
926 |
$sth->execute(@values) || $form->dberror($query);
|
967 |
927 |
|
968 |
928 |
while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
|
... | ... | |
1002 |
962 |
|
1003 |
963 |
#Make EV Verwaltungsdatei
|
1004 |
964 |
$ed_versionset[0] =
|
1005 |
|
&make_ed_versionset($header, $filename, $blockcount, $fromto);
|
|
965 |
$self->make_ed_versionset($header, $filename, $blockcount);
|
1006 |
966 |
|
1007 |
|
my $ev_header = &make_ev_header($form, $fileno);
|
1008 |
|
my $ev_filename = $export_path . $evfile;
|
|
967 |
my $ev_header = $self->make_ev_header($form, $fileno);
|
|
968 |
my $ev_filename = $self->export_path . $evfile;
|
1009 |
969 |
push(@filenames, $evfile);
|
1010 |
970 |
open(EV, ">", $ev_filename) or die "can't open outputfile: EV01\n";
|
1011 |
971 |
print(EV $ev_header);
|
... | ... | |
1015 |
975 |
}
|
1016 |
976 |
close(EV);
|
1017 |
977 |
|
1018 |
|
$dbh->disconnect;
|
1019 |
|
###
|
1020 |
|
|
1021 |
|
print qq|<br>Done. <br>
|
1022 |
|
|;
|
|
978 |
$self->add_filenames(@filenames);
|
1023 |
979 |
|
1024 |
980 |
$main::lxdebug->leave_sub();
|
1025 |
981 |
|
1026 |
|
return { 'download_token' => get_download_token_for_path($export_path), 'filenames' => \@filenames };
|
|
982 |
return { 'download_token' => $self->download_token, 'filenames' => \@filenames };
|
|
983 |
}
|
|
984 |
|
|
985 |
sub DESTROY {
|
|
986 |
clean_temporary_directories();
|
1027 |
987 |
}
|
1028 |
988 |
|
1029 |
989 |
1;
|
|
990 |
|
|
991 |
__END__
|
|
992 |
|
|
993 |
=encoding utf-8
|
|
994 |
|
|
995 |
=head1 NAME
|
|
996 |
|
|
997 |
SL::DATEV - Lx-Office DATEV Export module
|
|
998 |
|
|
999 |
=head1 SYNOPSIS
|
|
1000 |
|
|
1001 |
use SL::DATEV qw(:CONSTANTS);
|
|
1002 |
|
|
1003 |
my $datev = SL::DATEV->new(
|
|
1004 |
exporttype => DATEV_ET_BUCHUNGEN,
|
|
1005 |
format => DATEV_FORMAT_KNE,
|
|
1006 |
from => $startdate,
|
|
1007 |
to => $enddate,
|
|
1008 |
);
|
|
1009 |
|
|
1010 |
my $datev = SL::DATEV->new(
|
|
1011 |
exporttype => DATEV_ET_STAMM,
|
|
1012 |
format => DATEV_FORMAT_KNE,
|
|
1013 |
accnofrom => $start_account_number,
|
|
1014 |
accnoto => $end_account_number,
|
|
1015 |
);
|
|
1016 |
|
|
1017 |
# get or set datev stamm
|
|
1018 |
my $hashref = $datev->get_datev_stamm;
|
|
1019 |
$datev->save_datev_stamm($hashref);
|
|
1020 |
|
|
1021 |
# manually clean up temporary directories
|
|
1022 |
$datev->clean_temporary_directories;
|
|
1023 |
|
|
1024 |
# export
|
|
1025 |
$datev->export;
|
|
1026 |
|
|
1027 |
if ($datev->errors) {
|
|
1028 |
die join "\n", $datev->error;
|
|
1029 |
}
|
|
1030 |
|
|
1031 |
# get relevant data for saving the export:
|
|
1032 |
my $dl_token = $datev->download_token;
|
|
1033 |
my $path = $datev->export_path;
|
|
1034 |
my @files = $datev->filenames;
|
|
1035 |
|
|
1036 |
# retrieving an export at a later time
|
|
1037 |
my $datev = SL::DATEV->new(
|
|
1038 |
download_token => $dl_token_from_user,
|
|
1039 |
);
|
|
1040 |
|
|
1041 |
my $path = $datev->export_path;
|
|
1042 |
my @files = glob("$path/*");
|
|
1043 |
|
|
1044 |
=head1 DESCRIPTION
|
|
1045 |
|
|
1046 |
This module implements the DATEV export standard. For usage see above.
|
|
1047 |
|
|
1048 |
=head1 FUNCTIONS
|
|
1049 |
|
|
1050 |
=over 4
|
|
1051 |
|
|
1052 |
=item new PARAMS
|
|
1053 |
|
|
1054 |
Generic constructor. See section attributes for information about hat to pass.
|
|
1055 |
|
|
1056 |
=item get_datev_stamm
|
|
1057 |
|
|
1058 |
Loads DATEV Stammdaten and returns as hashref.
|
|
1059 |
|
|
1060 |
=item save_datev_stamm HASHREF
|
|
1061 |
|
|
1062 |
Saves DATEV Stammdaten from provided hashref.
|
|
1063 |
|
|
1064 |
=item exporttype
|
|
1065 |
|
|
1066 |
See L<CONSTANTS> for possible values
|
|
1067 |
|
|
1068 |
=item has_exporttype
|
|
1069 |
|
|
1070 |
Returns true if an exporttype has been set. Without exporttype most report functions won't work.
|
|
1071 |
|
|
1072 |
=item format
|
|
1073 |
|
|
1074 |
Specifies the designated format of the export. Currently only KNE export is implemented.
|
|
1075 |
|
|
1076 |
See L<CONSTANTS> for possible values
|
|
1077 |
|
|
1078 |
=item has_format
|
|
1079 |
|
|
1080 |
Returns true if a format has been set. Without format most report functions won't work.
|
|
1081 |
|
|
1082 |
=item download_token
|
|
1083 |
|
|
1084 |
Returns a download token for this DATEV object.
|
|
1085 |
|
|
1086 |
Note: If either a download_token or export_path were set at the creation these are infered, otherwise randomly generated.
|
|
1087 |
|
|
1088 |
=item export_path
|
|
1089 |
|
|
1090 |
Returns an export_path for this DATEV object.
|
|
1091 |
|
|
1092 |
Note: If either a download_token or export_path were set at the creation these are infered, otherwise randomly generated.
|
|
1093 |
|
|
1094 |
=item filenames
|
|
1095 |
|
|
1096 |
Returns a list of filenames generated by this DATEV object. This only works if th files were generated during it's lifetime, not if the object was created from a download_token.
|
|
1097 |
|
|
1098 |
=item net_gross_differences
|
|
1099 |
|
|
1100 |
If there were any net gross differences during calculation they will be collected here.
|
|
1101 |
|
|
1102 |
=item sum_net_gross_differences
|
|
1103 |
|
|
1104 |
Sum of all differences.
|
|
1105 |
|
|
1106 |
=item clean_temporary_directories
|
|
1107 |
|
|
1108 |
Forces a garbage collection on previous exports which will delete all exports that are older than 8 hours. It will be automatically called on destruction of the object, but is advised to be called manually before delivering results of an export to the user.
|
|
1109 |
|
|
1110 |
=item errors
|
|
1111 |
|
|
1112 |
Returns a list of errors that occured. If no errors occured, the export was a success.
|
|
1113 |
|
|
1114 |
=item export
|
|
1115 |
|
|
1116 |
Exports data. You have to have set L<exporttype> and L<format> or an error will
|
|
1117 |
occur. OBE exports are currently not implemented.
|
|
1118 |
|
|
1119 |
=back
|
|
1120 |
|
|
1121 |
=head1 ATTRIBUTES
|
|
1122 |
|
|
1123 |
This is a list of attributes set in either the C<new> or a method of the same name.
|
|
1124 |
|
|
1125 |
=over 4
|
|
1126 |
|
|
1127 |
=item dbh
|
|
1128 |
|
|
1129 |
Set a database handle to use in the process. This allows for an export to be
|
|
1130 |
done on a transaction in progress without committing first.
|
|
1131 |
|
|
1132 |
=item exporttype
|
|
1133 |
|
|
1134 |
See L<CONSTANTS> for possible values. This MUST be set before export is called.
|
|
1135 |
|
|
1136 |
=item format
|
|
1137 |
|
|
1138 |
See L<CONSTANTS> for possible values. This MUST be set before export is called.
|
|
1139 |
|
|
1140 |
=item download_token
|
|
1141 |
|
|
1142 |
Can be set on creation to retrieve a prior export for download.
|
|
1143 |
|
|
1144 |
=item from
|
|
1145 |
|
|
1146 |
=item to
|
|
1147 |
|
|
1148 |
Set boundary dates for the export. Currently thse MUST be set for the export to work.
|
|
1149 |
|
|
1150 |
=item accnofrom
|
|
1151 |
|
|
1152 |
=item accnoto
|
|
1153 |
|
|
1154 |
Set boundary account numbers for the export. Only useful for a stammdaten export.
|
|
1155 |
|
|
1156 |
=back
|
|
1157 |
|
|
1158 |
=head1 CONSTANTS
|
|
1159 |
|
|
1160 |
=head2 Supplied to L<exporttype>
|
|
1161 |
|
|
1162 |
=over 4
|
|
1163 |
|
|
1164 |
=item DATEV_ET_BUCHUNGEN
|
|
1165 |
|
|
1166 |
=item DATEV_ET_STAMM
|
|
1167 |
|
|
1168 |
=back
|
|
1169 |
|
|
1170 |
=head2 Supplied to L<format>.
|
|
1171 |
|
|
1172 |
=over 4
|
|
1173 |
|
|
1174 |
=item DATEV_FORMAT_KNE
|
|
1175 |
|
|
1176 |
=item DATEV_FORMAT_OBE
|
|
1177 |
|
|
1178 |
=back
|
|
1179 |
|
|
1180 |
=head1 ERROR HANDLING
|
|
1181 |
|
|
1182 |
This module will die in the following cases:
|
|
1183 |
|
|
1184 |
=over 4
|
|
1185 |
|
|
1186 |
=item *
|
|
1187 |
|
|
1188 |
No or unrecognized exporttype or format was provided for an export
|
|
1189 |
|
|
1190 |
=item *
|
|
1191 |
|
|
1192 |
OBE rxport was called, which is not yet implemented.
|
|
1193 |
|
|
1194 |
=item *
|
|
1195 |
|
|
1196 |
general I/O errors
|
|
1197 |
|
|
1198 |
=back
|
|
1199 |
|
|
1200 |
Errors that occur during th actual export will be collected in L<errors>. The following types can occur at the moment:
|
|
1201 |
|
|
1202 |
=over 4
|
|
1203 |
|
|
1204 |
=item *
|
|
1205 |
|
|
1206 |
C<Unbalanced Ledger!>. Exactly that, your ledger is unbalanced. Should never occur.
|
|
1207 |
|
|
1208 |
=item *
|
|
1209 |
|
|
1210 |
C<Datev-Export fehlgeschlagen! Bei Transaktion %d (%f).> This error occurs if a
|
|
1211 |
transaction could not be reliably sorted out, or had rounding errors over the acceptable threshold.
|
|
1212 |
|
|
1213 |
=back
|
|
1214 |
|
|
1215 |
=head1 BUGS AND CAVEATS
|
|
1216 |
|
|
1217 |
=over 4
|
|
1218 |
|
|
1219 |
=item *
|
|
1220 |
|
|
1221 |
Handling of Vollvorlauf is currently not fully implemented. You must provide both from and to to get a working export.
|
|
1222 |
|
|
1223 |
=item *
|
|
1224 |
|
|
1225 |
OBE export is currently not implemented.
|
|
1226 |
|
|
1227 |
=back
|
|
1228 |
|
|
1229 |
=head1 TODO
|
|
1230 |
|
|
1231 |
- handling of export_path and download token is a bit dodgy, clean that up.
|
|
1232 |
|
|
1233 |
=head1 SEE ALSO
|
|
1234 |
|
|
1235 |
L<SL::DATEV::KNEFile>
|
|
1236 |
|
|
1237 |
=head1 AUTHORS
|
|
1238 |
|
|
1239 |
Philip Reetz E<lt>p.reetz@linet-services.deE<gt>,
|
|
1240 |
|
|
1241 |
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>,
|
|
1242 |
|
|
1243 |
Jan Büren E<lt>jan@lx-office-hosting.deE<gt>,
|
|
1244 |
|
|
1245 |
Geoffrey Richardson E<lt>information@lx-office-hosting.deE<gt>,
|
|
1246 |
|
|
1247 |
Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>,
|
|
1248 |
|
|
1249 |
Stephan Köhler
|
|
1250 |
|
|
1251 |
=cut
|
DATEV Export modular gekapselt.