Revision 631b4c04
Von Sven Schöling vor mehr als 12 Jahren hinzugefügt
SL/DATEV.pm | ||
---|---|---|
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 |
Auch abrufbar als: Unified diff
DATEV Export modular gekapselt.