Импорт банковской выписки
Организовать импорт данных из текстововго файла в базу данных Гедымина можно как с помощью встроенного механизма импорта, так и используя регулярные выражения. В данной статье мы рассмотрим второй способ. В качестве образца файла с данными возьмем банковскую выписку Белагропромбанка. Как видно, содержимое файла -- это выписка по одному или нескольким банковским счетам. Напишем процедуру 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