+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::DATEV - kivitendo DATEV Export module
+
+=head1 SYNOPSIS
+
+ use SL::DATEV qw(:CONSTANTS);
+
+ my $startdate = DateTime->new(year => 2014, month => 9, day => 1);
+ my $enddate = DateTime->new(year => 2014, month => 9, day => 31);
+ my $datev = SL::DATEV->new(
+ exporttype => DATEV_ET_BUCHUNGEN,
+ format => DATEV_FORMAT_KNE,
+ from => $startdate,
+ to => $enddate,
+ );
+
+ # To only export transactions from a specific trans_id: (from and to are ignored)
+ my $invoice = SL::DB::Manager::Invoice->find_by( invnumber => '216' );
+ my $datev = SL::DATEV->new(
+ exporttype => DATEV_ET_BUCHUNGEN,
+ format => DATEV_FORMAT_KNE,
+ trans_id => $invoice->trans_id,
+ );
+
+ my $datev = SL::DATEV->new(
+ exporttype => DATEV_ET_STAMM,
+ format => DATEV_FORMAT_KNE,
+ accnofrom => $start_account_number,
+ accnoto => $end_account_number,
+ );
+
+ # get or set datev stamm
+ my $hashref = $datev->get_datev_stamm;
+ $datev->save_datev_stamm($hashref);
+
+ # manually clean up temporary directories older than 8 hours
+ $datev->clean_temporary_directories;
+
+ # export
+ $datev->export;
+
+ if ($datev->errors) {
+ die join "\n", $datev->error;
+ }
+
+ # get relevant data for saving the export:
+ my $dl_token = $datev->download_token;
+ my $path = $datev->export_path;
+ my @files = $datev->filenames;
+
+ # retrieving an export at a later time
+ my $datev = SL::DATEV->new(
+ download_token => $dl_token_from_user,
+ );
+
+ my $path = $datev->export_path;
+ my @files = glob("$path/*");
+
+ # Only test the datev data of a specific trans_id, without generating an
+ # export file, but filling $datev->errors if errors exist
+
+ my $datev = SL::DATEV->new(
+ trans_id => $invoice->trans_id,
+ );
+ $datev->generate_datev_data;
+ # if ($datev->errors) { ...
+
+
+=head1 DESCRIPTION
+
+This module implements the DATEV export standard. For usage see above.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item new PARAMS
+
+Generic constructor. See section attributes for information about what to pass.
+
+=item generate_datev_data
+
+Fetches all transactions from the database (via a trans_id or a date range),
+and does an initial transformation (e.g. filters out tax, determines
+the brutto amount, checks split transactions ...) and stores this data in
+$self->{DATEV}.
+
+If any errors are found these are collected in $self->errors.
+
+This function is needed for all the exports, but can be also called
+independently in order to check transactions for DATEV compatibility.
+
+=item generate_datev_lines
+
+Parse the data in $self->{DATEV} and transform it into a format that can be
+used by DATEV, e.g. determines Konto and Gegenkonto, the taxkey, ...
+
+The transformed data is returned as an arrayref, which is ready to be converted
+to a DATEV data format, e.g. KNE, OBE, CSV, ...
+
+At this stage the "DATEV rule" has already been applied to the taxkeys, i.e.
+entries with datevautomatik have an empty taxkey, as the taxkey is already
+determined by the chart.
+
+=item get_datev_stamm
+
+Loads DATEV Stammdaten and returns as hashref.
+
+=item save_datev_stamm HASHREF
+
+Saves DATEV Stammdaten from provided hashref.
+
+=item exporttype
+
+See L<CONSTANTS> for possible values
+
+=item has_exporttype
+
+Returns true if an exporttype has been set. Without exporttype most report functions won't work.
+
+=item format
+
+Specifies the designated format of the export. Currently only KNE export is implemented.
+
+See L<CONSTANTS> for possible values
+
+=item has_format
+
+Returns true if a format has been set. Without format most report functions won't work.
+
+=item download_token
+
+Returns a download token for this DATEV object.
+
+Note: If either a download_token or export_path were set at the creation these are infered, otherwise randomly generated.
+
+=item export_path
+
+Returns an export_path for this DATEV object.
+
+Note: If either a download_token or export_path were set at the creation these are infered, otherwise randomly generated.
+
+=item filenames
+
+Returns a list of filenames generated by this DATEV object. This only works if the files were generated during its lifetime, not if the object was created from a download_token.
+
+=item net_gross_differences
+
+If there were any net gross differences during calculation they will be collected here.
+
+=item sum_net_gross_differences
+
+Sum of all differences.
+
+=item clean_temporary_directories
+
+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.
+
+=item errors
+
+Returns a list of errors that occured. If no errors occured, the export was a success.
+
+=item export
+
+Exports data. You have to have set L<exporttype> and L<format> or an error will
+occur. OBE exports are currently not implemented.
+
+=item csv_export_for_tax_accountant
+
+Generates up to four downloadable csv files containing data about sales and
+purchase invoices, and their respective payments:
+
+Example:
+ my $startdate = DateTime->new(year => 2012, month => 1, day => 1);
+ my $enddate = DateTime->new(year => 2012, month => 12, day => 31);
+ SL::DATEV->new(from => $startdate, to => $enddate)->csv_export_for_tax_accountant;
+ # {
+ # 'download_token' => '1488551625-815654-22430',
+ # 'filenames' => [
+ # 'Zahlungen Kreditorenbuchungen 2012-01-01 - 2012-12-31.csv',
+ # 'Kreditorenbuchungen 2012-01-01 - 2012-12-31.csv',
+ # 'Zahlungen Debitorenbuchungen 2012-01-01 - 2012-12-31.csv',
+ # 'Debitorenbuchungen 2012-01-01 - 2012-12-31.csv'
+ # ]
+ # };
+
+
+=item csv_buchungsexport
+
+Generates the CSV-Format data for the CSV DATEV export and returns
+an 2-dimensional array as an array_ref.
+
+Requires $self->fromto for a valid DATEV header.
+
+Furthermore we assume that the first day of the fiscal year is
+the first of January and we cannot guarantee that our data in kivitendo
+is locked, that means a booking cannot be modified after a defined (vat tax)
+period.
+Some validity checks (max_length and regex) will be done if the
+data structure contains them and the field is defined.
+
+To add or alter the structure of the data take a look at SL::DATEV::CSV.pm
+
+=item _csv_buchungsexport_to_file
+
+Generates one downloadable csv file wrapped in a zip archive.
+Basically this method is just a thin wrapper for TEXT::CSV_XS.pm
+
+Generates a CSV-file with the same encodings as defined in DATEV Format CSV 2015:
+ $ file
+ $ EXTF_Buchungsstapel.csv: ISO-8859 text, with very long lines, with CRLF line terminators
+
+Usage: _csv_buchungsexport_to_file($self, data => $self->csv_buchungsexport);
+
+
+=back
+
+=head1 ATTRIBUTES
+
+This is a list of attributes set in either the C<new> or a method of the same name.
+
+=over 4
+
+=item dbh
+
+Set a database handle to use in the process. This allows for an export to be
+done on a transaction in progress without committing first.
+
+Note: If you don't want this code to commit, simply providing a dbh is not
+enough enymore. You'll have to wrap the call into a transaction yourself, so
+that the internal transaction does not commit.
+
+=item exporttype
+
+See L<CONSTANTS> for possible values. This MUST be set before export is called.
+
+=item format
+
+See L<CONSTANTS> for possible values. This MUST be set before export is called.
+
+=item download_token
+
+Can be set on creation to retrieve a prior export for download.
+
+=item from
+
+=item to
+
+Set boundary dates for the export. Unless a trans_id is passed these MUST be
+set for the export to work.
+
+=item trans_id
+
+To check only one gl/ar/ap transaction, pass the trans_id. The attributes
+L<from> and L<to> are currently still needed for the query to be assembled
+correctly.
+
+=item accnofrom
+
+=item accnoto
+
+Set boundary account numbers for the export. Only useful for a stammdaten export.
+
+=back
+
+=head1 CONSTANTS
+
+=head2 Supplied to L<exporttype>
+
+=over 4
+
+=item DATEV_ET_BUCHUNGEN
+
+=item DATEV_ET_STAMM
+
+=back
+
+=head2 Supplied to L<format>.
+
+=over 4
+
+=item DATEV_FORMAT_KNE
+
+=item DATEV_FORMAT_OBE
+
+=back
+
+=head1 ERROR HANDLING
+
+This module will die in the following cases:
+
+=over 4
+
+=item *
+
+No or unrecognized exporttype or format was provided for an export
+
+=item *
+
+OBE export was called, which is not yet implemented.
+
+=item *
+
+general I/O errors
+
+=back
+
+Errors that occur during th actual export will be collected in L<errors>. The following types can occur at the moment:
+
+=over 4
+
+=item *
+
+C<Unbalanced Ledger!>. Exactly that, your ledger is unbalanced. Should never occur.
+
+=item *
+
+C<Datev-Export fehlgeschlagen! Bei Transaktion %d (%f).> This error occurs if a
+transaction could not be reliably sorted out, or had rounding errors above the acceptable threshold.
+
+=back
+
+=head1 BUGS AND CAVEATS
+
+=over 4
+
+=item *
+
+Handling of Vollvorlauf is currently not fully implemented. You must provide both from and to in order to get a working export.
+
+=item *
+
+OBE export is currently not implemented.
+
+=back
+
+=head1 TODO
+
+- handling of export_path and download token is a bit dodgy, clean that up.
+
+=head1 SEE ALSO
+
+L<SL::DATEV::KNEFile>
+L<SL::DATEV::CSV>
+
+=head1 AUTHORS
+
+Philip Reetz E<lt>p.reetz@linet-services.deE<gt>,
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>,
+
+Jan Büren E<lt>jan@lx-office-hosting.deE<gt>,
+
+Geoffrey Richardson E<lt>information@lx-office-hosting.deE<gt>,
+
+Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>,
+
+Stephan Köhler
+
+=cut