use SL::DATEV::CSV;
use SL::DB;
use SL::HTML::Util ();
+use SL::Iconv;
use SL::Locale::String qw(t8);
use Data::Dumper;
eol => "\r\n",
}) or die "Cannot use CSV: ".Text::CSV_XS->error_diag();
- my $csv_file = IO::File->new($self->export_path . '/' . $filename, '>:encoding(cp1252)') or die "Can't open: $!";
+ # get encoding from defaults - use cp1252 if DATEV strict export is used
+ my $enc = ($::instance_conf->get_datev_export_format eq 'cp1252') ? 'cp1252' : 'utf-8';
+ my $csv_file = IO::File->new($self->export_path . '/' . $filename, ">:encoding($enc)") or die "Can't open: $!";
+
$csv->print($csv_file, $_) for @{ $datev_csv->header };
$csv->print($csv_file, $_) for @{ $datev_csv->lines };
$csv_file->close;
$self->{warnings} = $datev_csv->warnings;
+ # convert utf-8 to cp1252//translit if set
+ if ($::instance_conf->get_datev_export_format eq 'cp1252-translit') {
+
+ my $filename_translit = "EXTF_DATEV_kivitendo_translit" . $self->from->ymd() . '-' . $self->to->ymd() . ".csv";
+ open my $fh_in, '<:encoding(UTF-8)', $self->export_path . '/' . $filename or die "could not open $filename for reading: $!";
+ open my $fh_out, '>', $self->export_path . '/' . $filename_translit or die "could not open $filename_translit for writing: $!";
+
+ my $converter = SL::Iconv->new("utf-8", "cp1252//translit");
+
+ print $fh_out $converter->convert($_) while <$fh_in>;
+ close $fh_in;
+ close $fh_out;
+
+ unlink $self->export_path . '/' . $filename or warn "Could not unlink $filename: $!";
+ $filename = $filename_translit;
+ }
+
return { download_token => $self->download_token, filenames => $filename };
} elsif ($self->exporttype == DATEV_ET_STAMM) {
max_length => 12,
type => 'Text',
default => '',
- input_check => sub { my ($text) = @_; check_encoding($text); },
+ input_check => sub { return 1 unless $::instance_conf->get_datev_export_format eq 'cp1252';
+ my ($text) = @_; check_encoding($text); },
+ valid_check => sub { return 1 if $::instance_conf->get_datev_export_format eq 'cp1252';
+ my ($text) = @_; check_encoding($text); },
formatter => sub { my ($input) = @_; return substr($input, 0, 12) },
},
{
max_length => 60,
type => 'Text',
default => '',
- input_check => sub { my ($text) = @_; return 1 unless $text; check_encoding($text); },
- formatter => sub { my ($input) = @_; return substr($input, 0, 60) },
+ input_check => sub { return 1 unless $::instance_conf->get_datev_export_format eq 'cp1252';
+ my ($text) = @_; check_encoding($text); },
+ valid_check => sub { return 1 if $::instance_conf->get_datev_export_format eq 'cp1252';
+ my ($text) = @_; check_encoding($text); },
}, # pos 14
{
kivi_datev_name => 'not yet implemented',
datev_check_on_gl_transaction => { type => 'boolean', default => 'true' },
datev_check_on_purchase_invoice => { type => 'boolean', default => 'true' },
datev_check_on_sales_invoice => { type => 'boolean', default => 'true' },
+ datev_export_format => { type => 'enum', check_in => [ 'cp1252', 'cp1252-translit', 'utf-8' ], db_type => 'datev_export_format_enum', default => 'cp1252-translit' },
disabled_price_sources => { type => 'array' },
doc_delete_printfiles => { type => 'boolean', default => 'false' },
doc_files => { type => 'boolean', default => 'false' },
'DATEV - Export Assistent' => 'DATEV-Exportassistent',
'DATEV Angaben' => 'DATEV-Angaben',
'DATEV Export' => 'DATEV-Export',
- 'DATEV check configuration' => 'Einstellungen für DATEV-Prüfung',
'DATEV check returned errors:' => 'Die DATEV Prüfung dieser Buchung ergab Fehler:',
+ 'DATEV configuration' => 'Einstellungen für DATEV',
+ 'DATEV expects the encoding to be Western Europe conform (LATIN-1, cp1252). By setting this to "Strict and halt" the DATEV export halts with a error if there is a single character in "Posting Text" which is not LATIN-1 encodeable. By setting this to "Strict but replace" kivitendo will replace the character with a similar one and the export will simply warn about those fields. By setting this to relaxed (UTF-8) the DATEV export encoding will be in kivitendo (UTF-8) encoded and the external import program has to handle this (this may work for DATEV deriviates or future versions of DATEV). Background details: For example turkish characters (Ç) are not valid cp1252 charactes and armenian characters like "Գեղարդ" are probably not replaceable in cp1252' => 'DATEV erwartet westeuropäische Zeichenkodierung (LATIN-1, cp1252). Die Einstellung "Strikt und Abbruch" erlaubt keine nicht kodiebaren Zeichen im DATEV-Export und bricht diesen mit einer Fehlermeldung ab. Die Einstellung "Strikt mit Ersetzungen" versucht ähnliche Zeichen (bspw. c statt ć) zu verwenden und gibt zusätzlich eine Warnung beim DATEV-Expport aus. Die Einstellung "Lax (UTF-8)" ignoriert diese Anforderung und übergibt die Daten im kivitendo-konformen UTF-8 Format. Letzteres kann für zukünftige DATEV-Version oder DATEV-kompatible Alternativen interessant sein. Hintergrund-Info: Beispielsweise sind schon türkische Zeichen (Ç) nicht mehr im westeuropäischen Zeichensätze enthalten und armenische Zeiche wie "Գեղարդ" könnnen sicherlich überhaupt nicht mit Zeichen in cp1252 ersetzt werden.',
'DATEX - Export Assistent' => 'DATEV-Exportassistent',
'DELETED' => 'Gelöscht',
'DFV-Kennzeichen' => 'DFV-Kennzeichen',
'Date missing!' => 'Datum fehlt!',
'Date the payment is due in full' => 'Das Datum, bis die Rechnung in voller Höhe bezahlt werden muss',
'Date the payment is due with discount' => 'Das Datum, bis die Rechnung unter Abzug von Skonto bezahlt werden kann',
+ 'Datev export encoding' => 'DATEV-Export Kodierung',
'Datevautomatik' => 'Datev-Automatik',
'Datum von' => 'Datum von',
'Deactivate by default' => 'Deaktiviert als Voreinstellung',
'Reference / Invoice Number' => 'Referenz / Rechnungsnummer',
'Reference day' => 'Referenztag',
'Reference missing!' => 'Referenz fehlt!',
+ 'Relaxed (UTF-8)' => 'Lax (UTF-8)',
'Release From Stock' => 'Lagerausgang',
'Remaining' => 'Rest',
'Remaining Amount' => 'abzurechnender Betrag',
'Storno (one letter abbreviation)' => 'S',
'Storno Invoice' => 'Stornorechnung',
'Street' => 'Straße',
+ 'Strict and halt' => 'Strikt und Abbruch',
+ 'Strict but replace' => 'Strikt mit Ersetzungen',
'Style the picture with the following CSS code' => 'Bildeigenschaft mit folgendem CSS-Style versehen',
'Stylesheet' => 'Stilvorlage',
'Sub function blocks' => 'Unterfunktionsblöcke',
--- /dev/null
+-- @tag: datev_export_format
+-- @description: Setzt die ausgehende Formatierung des DATEV-Exports
+-- @depends: release_3_5_1
+
+CREATE TYPE datev_export_format_enum AS ENUM ('cp1252', 'cp1252-translit', 'utf-8');
+
+ALTER TABLE defaults ADD COLUMN datev_export_format datev_export_format_enum default 'cp1252-translit';
+
<td>[% L.yes_no_tag('defaults.datev_check_on_gl_transaction', SELF.defaults.datev_check_on_gl_transaction) %]</td>
<td>[% LxERP.t8('Perform check when a gl transaction is posted?') %]</td>
</tr>
+ <tr>
+ <td align="right">[% LxERP.t8('Datev export encoding') %]</td>
+ <td>[% L.select_tag('defaults.datev_export_format', [ [ 'cp1252', LxERP.t8('Strict and halt') ],[ 'cp1252-translit', LxERP.t8('Strict but replace') ],[ 'utf-8', LxERP.t8('Relaxed (UTF-8)') ] ], default=SELF.defaults.datev_export_format) %]
+ <td>[% LxERP.t8('DATEV expects the encoding to be Western Europe conform (LATIN-1, cp1252). By setting this to "Strict and halt" the DATEV export halts with a error if there is a single character in "Posting Text" which is not LATIN-1 encodeable. By setting this to "Strict but replace" kivitendo will replace the character with a similar one and the export will simply warn about those fields. By setting this to relaxed (UTF-8) the DATEV export encoding will be in kivitendo (UTF-8) encoded and the external import program has to handle this (this may work for DATEV deriviates or future versions of DATEV). Background details: For example turkish characters (Ç) are not valid cp1252 charactes and armenian characters like "Գեղարդ" are probably not replaceable in cp1252') %]</td>
+ </tr>
</table>
</div>
<li><a href="#default_accounts">[% LxERP.t8('Default Accounts') %]</a></li>
<li><a href="#posting_configuration">[% LxERP.t8('Posting Configuration') %]</a></li>
[% IF FORM.feature_datev %]
- <li><a href="#datev_check_configuration">[% LxERP.t8('DATEV check configuration') %]</a></li>
+ <li><a href="#datev_check_configuration">[% LxERP.t8('DATEV configuration') %]</a></li>
[% END %]
<li><a href="#orders_deleteable">[% LxERP.t8('Orders / Delivery Orders deleteable') %]</a></li>
[%- IF INSTANCE_CONF.get_doc_storage %]