image2data

Der Tech-Blog

...weitermachen, wo OCR aufhört

Ein automatischer Eingangspostverteiler nebst Rechnungsdatenerkenner in unter 100 Zeilen

Mai 062015

Ein immer wiederkehrendes Thema ist das automatische Verteilen von Eingangspost. Mit image2data lässt sich ein schneller und effektiver Eingangspostverteiler mit geringem Aufwand erstellen.

Das folgende Skript ist nicht für den Produktivbetrieb konzipiert und zeigt beispielhaft einen möglichen Ansatz:
image2data durchsucht ein Eingangsverzeichnis nach Dateien mit der Endung ".tif", führt auf die ersten beiden Seiten einer jeden Datei eine Texterkennung aus und durchsucht den gewonnenen Text nach bestimmten Schlüsselwörtern.
Die Dokumente im Eingangsverzeichnis können Scans, welche z.B. durch einen Netzwerkscanner dort abgelegt wurden, aber auch manuell oder über die image2data Toolbar dort platzierte Dateien sein.

Werden die Wörter "Rechnung" oder "Gutschrift" gefunden, wird das Dokument einer Rechnungsdatenerkennung unterzogen und die ermittelten Rechnungsdaten werden zu dem Scan in einer gleichnamigen ".dat"-Datei gespeichert. Beide Dateien werden dann in den Ordner "Eingangspost Buchhaltung" verschoben.

Werden die Begriffe "Kündigung" oder "Beendigung" auf dem Scan gefunden, wird dieser in den Ordner "Eingangspost Kundenbetreuung" verschoben, wird keiner der o.g. Wörter gefunden, so landet der Scan in dem Ordner "Eingangspost Unbekannt".

Die folgende Implementierung ist zur Erklärung des Prinzips mit Schwerpunkt auf Transparenz erfolgt. Im Produktivbetrieb werden die Quell- und Zielpfade sowie die Sortierbegriffe aus einer Konfiguration entnommen und viele weitere Szenarien abgebildet.

{$I i2dxFiles}
{$I i2dxIDEx}
{$I i2dcOCRAndExtraction.i2dspt}
 
const
  MAXPAGECOUNT = 2;
 
  RECHNUNGSTAG1 = 'Rechnung';
  RECHNUNGSTAG2 = 'Gutschrift';
  KUENDIGUNGSTAG1 = 'Kündigung';
  KUENDIGUNGSTAG2 = 'Beendigung';
 
  QUELLPFAD = 'Z:\Scan-Eingang\';
  ZIELPFADRECHNUNGEN = 'Z:\Eingangspost Buchhaltung\';
  ZIELPFADKUENDIGUNGEN = 'Z:\Eingangspost Kundenbetreuung\';
  ZIELPFADUNBEKANNT = 'Z:\Eingangspost Unbekannt\';
 
var
  i, j, k, l: Integer;
 
  sFilePath: String;
  sFileName: String;
  sDatFileName: String;
  sTargetPath: String;
  sText: String;
 
  sInvoiceNumber: String;
  dInvoiceDate: TDateTime;
  fAmountNet: Currency;
  fVATRate: Currency;
  fAmountVAT: Currency;
  fAmountGross: Currency;
  sCountryCode: String;
 
  iPageCount: Integer;
 
  oFiles: TStringList;
  oDat: TStringList;
 
begin 
  oFiles := TStringList.Create;
 
  try
    i2dxFilesFindFiles(QUELLPFAD, '*.tif', False, False, oFiles);
 
    for i := 0 to oFiles.Count - 1 do begin
      sFilePath := i2dxFilesExtractFilePath(oFiles[i]);
      sFileName := i2dxFilesExtractFileName(oFiles[i]);
 
      iPageCount := i2dGetImagePageCount(oFiles[i]);
 
      if iPageCount > MAXPAGECOUNT then
        iPageCount := MAXPAGECOUNT;
 
      sText:= '';
      for j := 1 to iPageCount do
        sText := sText + i2dcOAEExtractTextOrPerformOCROnPage(oFiles[i], j, 3, 0, True, True) + #13#10;
 
      if (i2dGetTextPos(sText, RECHNUNGSTAG1, 1) > 0) or (i2dGetTextPos(sText, RECHNUNGSTAG2, 1) > 0) then begin
        i2dxIDExExtractInvoiceData('DE', sText, '', 19, 7, MAXINT, 0, sCountryCode, sInvoiceNumber, dInvoiceDate, fAmountNet, fVATRate, fAmountVAT, fAmountGross, k, l);
 
        sDatFileName := i2dxFilesChangeFileExt(sFileName, '.dat');
 
        sTargetPath := ZIELPFADRECHNUNGEN;
        i2dxFilesForceDirectories(sTargetPath);
 
        oDat := TStringList.Create;
 
        try
          oDat.Add('Rechnungsnummer=' + sInvoiceNumber);
          oDat.Add('Rechnungsdatum=' + DateToStr(dInvoiceDate));
          oDat.Add('Nettobetrag=' + FloatToStr(fAmountNet));
          oDat.Add('USt.-Satz=' + FloatToStr(fVATRate));
          oDat.Add('USt.-Betrag=' + FloatToStr(fAmountVAT));
          oDat.Add('Bruttobetrag=' + FloatToStr(fAmountGross));
 
          i2dxFilesForceDirectories(sTargetPath);
          oDat.SaveToFile(sTargetPath + sDatFileName);
        finally
          oDat.Free;
        end;
      end else if (i2dGetTextPos(sText, KUENDIGUNGSTAG1, 1) > 0) or (i2dGetTextPos(sText, KUENDIGUNGSTAG2, 1) > 0) then
        sTargetPath := ZIELPFADKUENDIGUNGEN
      else
        sTargetPath := ZIELPFADUNBEKANNT;
 
      i2dxFilesForceDirectories(sTargetPath);
      i2dxFilesRenameFile(oFiles[i], sTargetPath + sFileName);
    end;
  finally
    oFiles.Free;
  end;
end.

 

Atom

powered by Nibbleblog