Импорт банковской выписки

Материал из GedeminWiki
Перейти к: навигация, поиск

Организовать импорт данных из текстововго файла в базу данных Гедымина можно как с помощью встроенного механизма импорта, так и используя регулярные выражения. В данной статье мы рассмотрим второй способ. В качестве образца файла с данными возьмем банковскую выписку Белагропромбанка. Как видно, содержимое файла -- это выписка по одному или нескольким банковским счетам. Напишем процедуру ParseFile, которая будет считывать файл с диска в строку, перекодировать его из ДОС кодировки и вызывать процедуру разбора выписки ParseStatement:

Содержание

ParseFile

Sub ParseFile
  Const ForReading = 1
  Dim s
  s = System.OEMToAnsi(CreateObject("Scripting.FileSystemObject")._
    OpenTextFile("c:\temp\vyp.txt", ForReading).ReadAll)
  ParseStatement s
End Sub

Задача процедуры ParseStatement -- разбить текст на одиночные выписки и вызвать для каждой процедуру ParseOneStatement, передав ей на вход счет, дату выписки и ее текст:

ParseStatement

Sub ParseStatement(s)
  Dim regEx, Matches, I, J
  Set regEx = CreateObject("VBScript.RegExp")
  regEx.IgnoreCase = True
  regEx.Global = True
  regEx.Pattern = "Лицевой\s+по\s+счету\s+N\s+(\d{4})-(\d{9}).+за\D+(\d{1,2})\.(\d{1,2})\.(\d{1,4})" 

  Set Matches = regEx.Execute(s)
  For I = 1 To Matches.Count
   If I = Matches.Count Then
     J = Len(s)
   Else
     J = Matches(I).FirstIndex
   End If
   ParseOneStatement Matches(I - 1).SubMatches(0) & Matches(I - 1).SubMatches(1), _
     DateSerial(Matches(I - 1).SubMatches(4), Matches(I - 1).SubMatches(3), Matches(I - 1).SubMatches(2)), _
     Mid(s, Matches(I - 1).FirstIndex, J - Matches(I - 1).FirstIndex)
  Next
End Sub

Как видно, мы распознаем выписки в файле по заголовку. который содержит строку "Лицевой счет". Из заголовка мы извлекаем номер счета и дату выписки. Обратите внимание, что счет мы "склеиваем" из двух частей, так как в оригинале он содержит разделитель -- дефис. Дату из текста мы извлекаем по-отдельности: день, месяц и год, объединяя их потом с помощью функции DateSerial.

Для каждой выписки, указанная процедура извлекает номер счета, дату выписки и вместе с ее текстом передает на вход процедуре ParseOneStatement.

ParseOneStatement

Sub ParseOneStatement(acc, dt, s)
  Dim regEx, Match, Matches, I
  Set regEx = CreateObject("VBScript.RegExp")
  regEx.IgnoreCase = True
  regEx.Global = True
  regEx.MultiLine = True
  
  regEx.Pattern = "Код банка \d{6}(\d{3})"
  Set Matches = regEx.Execute(s)
 
  Dim AccID
  AccID = FindAccount(acc, Matches(0).SubMatches(0))
  
  regEx.Pattern = "^\s+(\d{1,2}) (\d{3}) (\d{4})-(\d{9})\s+(\d+).{6}\s+([0-9 .]+)"

  Set Matches = regEx.Execute(s)
  If Matches.Count > 0 Then
 
    Dim Creator, ObjV, ObjL
    Set Creator = new TCreator
    Set ObjV = Creator.GetObject(Application, "TgdcBankStatement", "")
    Set ObjL = Creator.GetObject(Application, "TgdcBankStatementLine", "")

    ObjV.Open
    ObjV.Insert
    ObjV.FieldByName("accountkey").AsInteger = AccID
    ObjV.FieldByName("documentdate").AsDateTime = dt
    ObjV.Post
  
    ObjL.Open
    For Each Match In Matches
      ObjL.Insert
      ObjL.FieldByName("operationtype").AsString = Match.SubMatches(0)
      ObjL.FieldByName("account").AsString = Match.SubMatches(2) & Match.SubMatches(3)
      ObjL.FieldByName("bankcode").AsString = Match.SubMatches(1)
      ObjL.FieldByName("number").AsString = Match.subMatches(4)
      ObjL.FieldByName("documentdate").AsDateTime = dt
      If Len(Match.Value) < 55 Then
        ObjL.FieldByName("dsumncu").AsCurrency = Replace(Match.subMatches(5), " ", "")
      Else
        ObjL.FieldByName("csumncu").AsCurrency = Replace(Match.subMatches(5), " ", "")
      End If
      ObjL.FieldByName("parent").AsInteger = ObjV.ID
      ObjL.Post
    Next
  End If
End Sub

В первую очередь, из текста выписки извлекается код нашего банка (он почему-то идет в конце текста). Код банка и номер счета передаются на вход функции FindAccount, которая ищет счет в базе и возвращает его идентификатор. Если такого счета нет, то он создается. Далее, по шаблону ищутся строки выписки. Если выписка не пустая, то создается шапка документа и заполняются позиции. по длине строки мы определяем дебет или кредит.

FindAccount

Function FindAccount(Acc, BankCode) 

  Dim BankID
  BankID = FindBank(BankCode)

  Dim Creator, q
  Set Creator = new TCreator
  Set q = Creator.GetObject(Application, "TIBSQL", "")
  q.Transaction = gdcBaseManager.ReadTransaction
  q.SQL.Text = "SELECT a.id FROM gd_companyaccount a JOIN gd_bank b " &_
    "ON b.bankkey = a.bankkey AND b.bankcode = :BC AND a.account = :ACC "
  q.ParamByName("BC").AsString = BankCode
  q.ParamByName("Acc").AsString = Acc
  q.ExecQuery
  
  If q.EOF Then
    Dim ObjA
    Set ObjA = Creator.GetObject(Application, "TgdcAccount", "")
   
    ObjA.Open
    ObjA.Insert
    ObjA.FieldByName("account").AsString = Acc
    ObjA.FieldByName("companykey").AsInteger = IBLogin.CompanyKey
    ObjA.FieldByName("bankkey").AsInteger = BankID
    ObjA.Post
   
    FindAccount = ObjA.ID
  Else
    FindAccount = q.Fields(0).AsInteger
  End If

End Function

FindBank

Function FindBank(BankCode)
  Dim Creator, q
  Set Creator = new TCreator
  Set q = Creator.GetObject(Application, "TIBSQL", "")
  q.Transaction = gdcBaseManager.ReadTransaction
  q.SQL.Text = "SELECT bankkey FROM gd_bank WHERE bankcode = :BC"
  q.ParamByName("BC").AsString = BankCode
  q.ExecQuery
  If q.EOF Then
    Dim ObjB
    Set ObjB = Creator.GetObject(Application, "TgdcBank", "")
    ObjB.Open
    ObjB.Insert
    ObjB.FieldByName("name").AsString = BankCode
    ObjB.FieldByName("bankcode").AsString = BankCode
    ObjB.Post
    FindBank = ObjB.ID
  Else
    FindBank = q.Fields(0).AsInteger
  End If
End Function
Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
Инструменты