55 lines
2.4 KiB
Ruby
55 lines
2.4 KiB
Ruby
#
|
|
# Produktiver Lauf: Buchungen prüfen, Summe und Saldo abgleichen, wiederholbar in die Buchhaltungs-Datenbank
|
|
# und als CSV in Windows-1252 für das Zielsystem schreiben; mit Sperre, Laufhistorie und Slack bei Problemen
|
|
#
|
|
# bin/etl run examples/buchungen_export.rb [--out=tmp] [--dry-run]
|
|
#
|
|
require 'fileutils'
|
|
require 'datapipeline'
|
|
|
|
DATA = File.expand_path('data', __dir__)
|
|
out = DataPipeline.params.fetch(:out, 'tmp')
|
|
FileUtils.mkdir_p(out)
|
|
|
|
# Zugangsdaten stehen nicht im Skript, sondern in der Verbindungsdatei (Default: config/connections.yml)
|
|
DataPipeline.connections_file = File.expand_path('config/connections.yml', __dir__)
|
|
|
|
DataPipeline.new do
|
|
name 'buchungen_export'
|
|
lock "#{out}/.buchungen.lock" # läuft schon ein Export, bricht dieser ab (Exit-Code 3)
|
|
history "#{out}/runs.ndjson" # eine JSON-Zeile je Lauf, auch nach Abbruch
|
|
notify DataPipeline::Slack.new(channel: '#etl') if ENV['SLACK_TOKEN'] # Meldung nur bei Problemen
|
|
|
|
read container(:csv, file: "#{DATA}/buchungen.csv", csv: { col_sep: ';' })
|
|
|
|
# 1. prüfen: ohne on_error bricht ein Fehler den Lauf ab, es entsteht keine halbe Buchung
|
|
validate 'belnr' => { required: true, format: /\A\d{10}\z/ },
|
|
'konto' => { required: true, format: /\A\d+\z/ },
|
|
'betrag' => { required: true, type: :decimal }
|
|
|
|
# 2. umbauen mit Kurzschritten und einem map
|
|
default 'text' => 'ohne Text'
|
|
rename 'text' => 'buchungstext'
|
|
cast 'buzei' => :integer, 'datum' => :date, 'betrag' => :decimal
|
|
map do |row|
|
|
row.merge('shkzg' => row['betrag'].negative? ? 'H' : 'S', 'dmbtr' => format('%.2f', row['betrag'].abs))
|
|
end
|
|
select %w[belnr buzei datum konto shkzg dmbtr betrag buchungstext]
|
|
|
|
# 3. abgleichen, bevor etwas geschrieben wird
|
|
totals 'betrag'
|
|
reconcile do |stats|
|
|
quelle, ergebnis = stats.total('betrag', :read), stats.total('betrag')
|
|
next "Summe geändert: Quelle #{DataPipeline.decimal(quelle)}, Ergebnis #{DataPipeline.decimal(ergebnis)}" if quelle != ergebnis
|
|
|
|
"Soll und Haben ungleich, Saldo #{DataPipeline.decimal(ergebnis)}" unless ergebnis.zero?
|
|
end
|
|
|
|
# 4. schreiben: Upsert macht den Lauf wiederholbar; die CSV-Datei im Zeichensatz des Zielsystems
|
|
write connection(:buchhaltung)
|
|
write container(:csv, file: "#{out}/buchungen_sap.csv", encoding: 'Windows-1252', csv: { col_sep: ';' },
|
|
columns: %w[belnr buzei datum konto shkzg dmbtr buchungstext])
|
|
|
|
on_finish { |stats| puts "#{stats.name}: #{stats}" }
|
|
end.run
|