Conciliação bancária
Bom dia pessoal, estou precisando de uma ajuda.
Estou desenvolvendo a opção de conciliação bancária de um sistema, procurei na internet sobre isso e código em Delphi, e encontrei o código abaixo (código que fiz algumas poucas alterações), mas se por exemplo eu leio um OFX do Itaú ele funciona, já para o Banco do Brasil não, pois existe uma diferença de tags, e se eu adapto para o BB aí não funciona para o Itaú. O problema é que isto pode ocorrer com outros bancos, gostaria de algo genérico. Acredito que isto deveria ser um padrão.
Alguém tem alguma ideia, dica, código de como eu poderia proceder?
Segue o código:
Obrigado desde já!
Estou desenvolvendo a opção de conciliação bancária de um sistema, procurei na internet sobre isso e código em Delphi, e encontrei o código abaixo (código que fiz algumas poucas alterações), mas se por exemplo eu leio um OFX do Itaú ele funciona, já para o Banco do Brasil não, pois existe uma diferença de tags, e se eu adapto para o BB aí não funciona para o Itaú. O problema é que isto pode ocorrer com outros bancos, gostaria de algo genérico. Acredito que isto deveria ser um padrão.
Alguém tem alguma ideia, dica, código de como eu poderia proceder?
Segue o código:
unit YMOFXReader_2;
interface
uses classes, SysUtils, Controls;
type
TOFXItem = class
MovType : string;
MovDate : TDate;
Value : double;
ID : string;
Document : string;
Desc : string;
CheckNum:string;
end;
TYMOFXReader = class(TComponent)
public
BankID : integer;
AccountID : string;
AccountType : string;
InitialBalance : double;
FinalBalance : double;
DtStart,DtEnd:TDate;
Ag,CC:string;
Org:string;
constructor Create( AOwner: TComponent ); override;
destructor Destroy; override;
function Process: boolean;
function Get(iIndex: integer): TOFXItem;
function Count: integer;
private
FOFXFile : string;
FListItems : TList;
procedure Clear;
procedure Delete( iIndex: integer );
function Add: TOFXItem;
function PrepareFloat( sString : string ) : string;
function InfLine ( sLine : string ): string;
function FindString ( sSubString, sString : string ): boolean;
function ReplaceString(sString: string; sOld: string; sNew: string; bInsensitive : boolean = true): string;
protected
published
property OFXFile: string read FOFXFile write FOFXFile;
end;
procedure Register;
implementation
constructor TYMOFXReader.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FListItems := TList.Create;
end;
destructor TYMOFXReader.Destroy;
begin
FListItems.Free;
inherited Destroy;
end;
procedure TYMOFXReader.Delete( iIndex: integer );
begin
TOFXItem(FListItems.Items[iIndex]).Free;
FListItems.Delete( iIndex );
end;
procedure TYMOFXReader.Clear;
//var
// i: integer;
// oPointer : Pointer;
begin
while FListItems.Count > 0 do
Delete(0);
FListItems.Clear;
end;
function TYMOFXReader.Count: integer;
begin
Result := FListItems.Count;
end;
function TYMOFXReader.Get(iIndex: integer): TOFXItem;
begin
Result := TOFXItem(FListItems.Items[iIndex]);
end;
function TYMOFXReader.Process: boolean;
var
oFile : TStringList;
i : integer;
bOFX : boolean;
oItem : TOFXItem;
sLine : string;
dBalance : double;
begin
Result := false;
Clear;
bOFX := false;
if not FileExists(FOFXFile) then
exit;
oFile := TStringList.Create;
oFile.LoadFromFile(FOFXFile);
dBalance := 0;
i := 0;
while i < oFile.Count do
begin
sLine := oFile.Strings[i];
if FindString('<OFX>', sLine) then
bOFX := true;
if bOFX then
begin
// -----------------------------------------------------------------------
// BankID
if FindString('<BANKID>', sLine) then BankID := StrToIntDef(InfLine(sLine), 0);
// -----------------------------------------------------------------------
// AccountID
if FindString('<ACCTID>', sLine) then AccountID := InfLine(sLine);
// -----------------------------------------------------------------------
// AccountType
if FindString('<ACCTTYPE>', sLine) then AccountType := InfLine(sLine);
// -----------------------------------------------------------------------
// FinalBalance
if FindString('<LEDGER>', sLine) then FinalBalance := StrToFloat(PrepareFloat(InfLine(sLine)));
// -----------------------------------------------------------------------
//DtStart
if FindString('<DTSTART>', sLine) then DtStart := EncodeDate(StrToIntDef(copy(InfLine(sLine),1,4), 0),
StrToIntDef(copy(InfLine(sLine),5,2), 0),
StrToIntDef(copy(InfLine(sLine),7,2), 0));
// -----------------------------------------------------------------------
//DtEnd
if FindString('<DTEND>', sLine) then DtEnd := EncodeDate(StrToIntDef(copy(InfLine(sLine),1,4), 0),
StrToIntDef(copy(InfLine(sLine),5,2), 0),
StrToIntDef(copy(InfLine(sLine),7,2), 0));
// -----------------------------------------------------------------------
//Agência
if FindString('<BRANCHID>', sLine) then Ag := InfLine(sLine);
// -----------------------------------------------------------------------
//Conta corrente
if FindString('<ACCTID>', sLine) then CC := InfLine(sLine);
// -----------------------------------------------------------------------
//Organização
if FindString('<ORG>', sLine) then Org := InfLine(sLine);
// -----------------------------------------------------------------------
// Moviment
if FindString('<STMTTRN>', sLine) then
begin
oItem := Add;
Inc(i);
sLine := oFile.Strings[i];
if FindString('<TRNTYPE>', sLine) then oItem.MovType := InfLine(sLine);
Inc(i);
sLine := oFile.Strings[i];
if FindString('<DTPOSTED>', sLine) then oItem.MovDate := EncodeDate(StrToIntDef(copy(InfLine(sLine),1,4), 0),
StrToIntDef(copy(InfLine(sLine),5,2), 0),
StrToIntDef(copy(InfLine(sLine),7,2), 0));
Inc(i);
sLine := oFile.Strings[i];
if FindString('<TRNAMT>', sLine) then
begin
oItem.Value := StrToFloat(PrepareFloat(InfLine(sLine)));
dBalance := dBalance - oItem.Value;
end;
Inc(i);
sLine := oFile.Strings[i];
if FindString('<FITID>', sLine) then oItem.ID := InfLine(sLine);
Inc(i);
sLine := oFile.Strings[i];
//if FindString('<CHKNUM>', sLine) then oItem.Document := InfLine(sLine);
if FindString('<CHECKNUM>', sLine) then oItem.CheckNum := InfLine(sLine);
Inc(i);
sLine := oFile.Strings[i];
if FindString('<REFNUM>', sLine) then oItem.Document := InfLine(sLine);
Inc(i);
sLine := oFile.Strings[i];
if FindString('<MEMO>', sLine) then oItem.Desc := InfLine(sLine);
// end;
end;
// -----------------------------------------------------------------------
end;
Inc(i);
end;
InitialBalance := FinalBalance + dBalance;
Result := bOFX;
end;
function TYMOFXReader.PrepareFloat( sString : string ) : string;
begin
Result := sString;
Result := ReplaceString(Result, '.', FormatSettings.DecimalSeparator);
Result := ReplaceString(Result, ',', FormatSettings.DecimalSeparator);
end;
function TYMOFXReader.ReplaceString(sString: string; sOld: string; sNew: string; bInsensitive : boolean = true): string;
var
iPosition: integer ;
sTempNew: string ;
begin
iPosition := 1;
sTempNew := '';
while (iPosition > 0) do
begin
if bInsensitive then
iPosition := AnsiPos(UpperCase(sOld),UpperCase(sString))
else
iPosition := AnsiPos(sOld,sString);
if (iPosition > 0) then
begin
sTempNew := sTempNew + copy(sString, 1, iPosition - 1) + sNew;
sString := copy(sString, iPosition + Length(sOld), Length(sString) );
end;
end;
sTempNew := sTempNew + sString;
Result := (sTempNew);
end;
function TYMOFXReader.InfLine ( sLine : string ): string;
var
iTemp : integer;
begin
Result := '';
sLine := Trim(sLine);
if FindString('>', sLine) then
begin
sLine := Trim(sLine);
iTemp := Pos('>', sLine);
Result := copy(sLine, iTemp+1, Length(sLine)-iTemp+1);
end;
//26/12/2013
if FindString('<', result) then
begin
sLine := Trim(result);
iTemp := Pos('<', result);
Result := copy(result, 1, iTemp-1);
end;
end;
function TYMOFXReader.Add: TOFXItem;
var
oItem : TOFXItem;
begin
oItem := TOFXItem.Create;
FListItems.Add(oItem);
Result := oItem;
end;
function TYMOFXReader.FindString ( sSubString, sString : string ): boolean;
begin
Result := Pos(UpperCase(sSubString), UpperCase(sString)) > 0;
end;
procedure Register;
begin
RegisterComponents('YoungArts', [TYMOFXReader]);
end;
end.
Obrigado desde já!
Rubens Filho
Curtidas 0
Melhor post
Rubens Filho
08/01/2014
Fala pessoal.
Acredito que deste modo posso resolver qualquer tipo de layout que apareça. O que eu fiz foi que a cada linha que passe do arquivo OFX é procurado qual tag da linha correspondente se encaixa em um conjunto de tags, assim, bastando incluir neste conjunto de tags a nova tag que não possui, assim:
Agora o código todo fica assim:
[code]
unit YMOFXReader_2;
interface
uses classes, SysUtils, Controls;
type
TOFXItem = class
MovType : string;
MovDate : TDate;
Value : double;
ID : string;
Document : string;
Desc : string;
CheckNum:string;
end;
TYMOFXReader = class(TComponent)
public
BankID : integer;
AccountID : string;
AccountType : string;
InitialBalance : double;
FinalBalance : double;
DtStart,DtEnd:TDate;
Ag,CC:string;
Org:string;
constructor Create( AOwner: TComponent ); override;
destructor Destroy; override;
function Process: boolean;
function Get(iIndex: integer): TOFXItem;
function Count: integer;
private
FOFXFile : string;
FListItems : TList;
procedure Clear;
procedure Delete( iIndex: integer );
function Add: TOFXItem;
function PrepareFloat( sString : string ) : string;
function InfLine ( sLine : string ): string;
function FindString ( sSubString, sString : string ): boolean;
function ReplaceString(sString: string; sOld: string; sNew: string; bInsensitive : boolean = true): string;
procedure ProcuraTag(vTag:string;var oItem : TOFXItem);
protected
published
property OFXFile: string read FOFXFile write FOFXFile;
end;
procedure Register;
implementation
constructor TYMOFXReader.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FListItems := TList.Create;
end;
destructor TYMOFXReader.Destroy;
begin
FListItems.Free;
inherited Destroy;
end;
procedure TYMOFXReader.Delete( iIndex: integer );
begin
TOFXItem(FListItems.Items[iIndex]).Free;
FListItems.Delete( iIndex );
end;
procedure TYMOFXReader.Clear;
//var
// i: integer;
// oPointer : Pointer;
begin
while FListItems.Count > 0 do
Delete(0);
FListItems.Clear;
end;
function TYMOFXReader.Count: integer;
begin
Result := FListItems.Count;
end;
function TYMOFXReader.Get(iIndex: integer): TOFXItem;
begin
Result := TOFXItem(FListItems.Items[iIndex]);
end;
function TYMOFXReader.Process: boolean;
var
oFile : TStringList;
i : integer;
bOFX : boolean;
oItem : TOFXItem;
sLine : string;
dBalance : double;
begin
Result := false;
Clear;
bOFX := false;
if not FileExists(FOFXFile) then
exit;
oFile := TStringList.Create;
oFile.LoadFromFile(FOFXFile);
dBalance := 0;
i := 0;
while i < oFile.Count do
begin
sLine := oFile.Strings[i];
if FindString('<OFX>', sLine) then
bOFX := true;
if bOFX then
begin
// -----------------------------------------------------------------------
// BankID
if FindString('<BANKID>', sLine) then BankID := StrToIntDef(InfLine(sLine), 0);
// -----------------------------------------------------------------------
// AccountID
if FindString('<ACCTID>', sLine) then AccountID := InfLine(sLine);
// -----------------------------------------------------------------------
// AccountType
if FindString('<ACCTTYPE>', sLine) then AccountType := InfLine(sLine);
// -----------------------------------------------------------------------
// FinalBalance
if FindString('<LEDGER>', sLine) then FinalBalance := StrToFloat(PrepareFloat(InfLine(sLine)));
// -----------------------------------------------------------------------
//DtStart
if FindString('<DTSTART>', sLine) then DtStart := EncodeDate(StrToIntDef(copy(InfLine(sLine),1,4), 0),
StrToIntDef(copy(InfLine(sLine),5,2), 0),
StrToIntDef(copy(InfLine(sLine),7,2), 0));
// -----------------------------------------------------------------------
//DtEnd
if FindString('<DTEND>', sLine) then DtEnd := EncodeDate(StrToIntDef(copy(InfLine(sLine),1,4), 0),
StrToIntDef(copy(InfLine(sLine),5,2), 0),
StrToIntDef(copy(InfLine(sLine),7,2), 0));
// -----------------------------------------------------------------------
//Agência
if FindString('<BRANCHID>', sLine) then Ag := InfLine(sLine);
// -----------------------------------------------------------------------
//Conta corrente
if FindString('<ACCTID>', sLine) then CC := InfLine(sLine);
// -----------------------------------------------------------------------
//Organização
if FindString('<ORG>', sLine) then Org := InfLine(sLine);
// -----------------------------------------------------------------------
// Moviment
if FindString('<STMTTRN>', sLine) then
begin
oItem := Add;
Inc(i);
sLine := oFile.Strings[i];
ProcuraTag(sLine,oItem);
//if FindString('<TRNTYPE>', sLine) then oItem.MovType := InfLine(sLine);
Inc(i);
sLine := oFile.Strings[i];
ProcuraTag(sLine,oItem);
//if FindString('<DTPOSTED>', sLine) then oItem.MovDate := EncodeDate(StrToIntDef(copy(InfLine(sLine),1,4), 0),
// StrToIntDef(copy(InfLine(sLine),5,2), 0),
//
Acredito que deste modo posso resolver qualquer tipo de layout que apareça. O que eu fiz foi que a cada linha que passe do arquivo OFX é procurado qual tag da linha correspondente se encaixa em um conjunto de tags, assim, bastando incluir neste conjunto de tags a nova tag que não possui, assim:
procedure TYMOFXReader.ProcuraTag(vTag: string;var oItem : TOFXItem);
begin
if FindString('<TRNTYPE>', vTag) then oItem.MovType := InfLine(vTag);
if FindString('<DTPOSTED>', vTag) then oItem.MovDate := EncodeDate(StrToIntDef(copy(InfLine(vTag),1,4), 0),
StrToIntDef(copy(InfLine(vTag),5,2), 0),
StrToIntDef(copy(InfLine(vTag),7,2), 0));
if FindString('<TRNAMT>', vTag) then
begin
oItem.Value := StrToFloat(PrepareFloat(InfLine(vTag)));
//dBalance := dBalance - oItem.Value;
end;
if FindString('<FITID>', vTag) then oItem.ID := InfLine(vTag);
//if FindString('<CHKNUM>', vTag) then oItem.Document := InfLine(vTag);
if FindString('<CHECKNUM>', vTag) then oItem.CheckNum := InfLine(vTag);
if FindString('<REFNUM>', vTag) then oItem.Document := InfLine(vTag);
if FindString('<MEMO>', vTag) then oItem.Desc := InfLine(vTag);
end;
Agora o código todo fica assim:
[code]
unit YMOFXReader_2;
interface
uses classes, SysUtils, Controls;
type
TOFXItem = class
MovType : string;
MovDate : TDate;
Value : double;
ID : string;
Document : string;
Desc : string;
CheckNum:string;
end;
TYMOFXReader = class(TComponent)
public
BankID : integer;
AccountID : string;
AccountType : string;
InitialBalance : double;
FinalBalance : double;
DtStart,DtEnd:TDate;
Ag,CC:string;
Org:string;
constructor Create( AOwner: TComponent ); override;
destructor Destroy; override;
function Process: boolean;
function Get(iIndex: integer): TOFXItem;
function Count: integer;
private
FOFXFile : string;
FListItems : TList;
procedure Clear;
procedure Delete( iIndex: integer );
function Add: TOFXItem;
function PrepareFloat( sString : string ) : string;
function InfLine ( sLine : string ): string;
function FindString ( sSubString, sString : string ): boolean;
function ReplaceString(sString: string; sOld: string; sNew: string; bInsensitive : boolean = true): string;
procedure ProcuraTag(vTag:string;var oItem : TOFXItem);
protected
published
property OFXFile: string read FOFXFile write FOFXFile;
end;
procedure Register;
implementation
constructor TYMOFXReader.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FListItems := TList.Create;
end;
destructor TYMOFXReader.Destroy;
begin
FListItems.Free;
inherited Destroy;
end;
procedure TYMOFXReader.Delete( iIndex: integer );
begin
TOFXItem(FListItems.Items[iIndex]).Free;
FListItems.Delete( iIndex );
end;
procedure TYMOFXReader.Clear;
//var
// i: integer;
// oPointer : Pointer;
begin
while FListItems.Count > 0 do
Delete(0);
FListItems.Clear;
end;
function TYMOFXReader.Count: integer;
begin
Result := FListItems.Count;
end;
function TYMOFXReader.Get(iIndex: integer): TOFXItem;
begin
Result := TOFXItem(FListItems.Items[iIndex]);
end;
function TYMOFXReader.Process: boolean;
var
oFile : TStringList;
i : integer;
bOFX : boolean;
oItem : TOFXItem;
sLine : string;
dBalance : double;
begin
Result := false;
Clear;
bOFX := false;
if not FileExists(FOFXFile) then
exit;
oFile := TStringList.Create;
oFile.LoadFromFile(FOFXFile);
dBalance := 0;
i := 0;
while i < oFile.Count do
begin
sLine := oFile.Strings[i];
if FindString('<OFX>', sLine) then
bOFX := true;
if bOFX then
begin
// -----------------------------------------------------------------------
// BankID
if FindString('<BANKID>', sLine) then BankID := StrToIntDef(InfLine(sLine), 0);
// -----------------------------------------------------------------------
// AccountID
if FindString('<ACCTID>', sLine) then AccountID := InfLine(sLine);
// -----------------------------------------------------------------------
// AccountType
if FindString('<ACCTTYPE>', sLine) then AccountType := InfLine(sLine);
// -----------------------------------------------------------------------
// FinalBalance
if FindString('<LEDGER>', sLine) then FinalBalance := StrToFloat(PrepareFloat(InfLine(sLine)));
// -----------------------------------------------------------------------
//DtStart
if FindString('<DTSTART>', sLine) then DtStart := EncodeDate(StrToIntDef(copy(InfLine(sLine),1,4), 0),
StrToIntDef(copy(InfLine(sLine),5,2), 0),
StrToIntDef(copy(InfLine(sLine),7,2), 0));
// -----------------------------------------------------------------------
//DtEnd
if FindString('<DTEND>', sLine) then DtEnd := EncodeDate(StrToIntDef(copy(InfLine(sLine),1,4), 0),
StrToIntDef(copy(InfLine(sLine),5,2), 0),
StrToIntDef(copy(InfLine(sLine),7,2), 0));
// -----------------------------------------------------------------------
//Agência
if FindString('<BRANCHID>', sLine) then Ag := InfLine(sLine);
// -----------------------------------------------------------------------
//Conta corrente
if FindString('<ACCTID>', sLine) then CC := InfLine(sLine);
// -----------------------------------------------------------------------
//Organização
if FindString('<ORG>', sLine) then Org := InfLine(sLine);
// -----------------------------------------------------------------------
// Moviment
if FindString('<STMTTRN>', sLine) then
begin
oItem := Add;
Inc(i);
sLine := oFile.Strings[i];
ProcuraTag(sLine,oItem);
//if FindString('<TRNTYPE>', sLine) then oItem.MovType := InfLine(sLine);
Inc(i);
sLine := oFile.Strings[i];
ProcuraTag(sLine,oItem);
//if FindString('<DTPOSTED>', sLine) then oItem.MovDate := EncodeDate(StrToIntDef(copy(InfLine(sLine),1,4), 0),
// StrToIntDef(copy(InfLine(sLine),5,2), 0),
//
GOSTEI 1
Mais Respostas
Douglas
06/01/2014
Rubens, eu não ainda não programarei algo de conciliação bancária, porém se você não encontrar algo padrão, então
infelizmente terá que realizar verificações código.
infelizmente terá que realizar verificações código.
GOSTEI 0
Leandro Chiodini
06/01/2014
RUBENS FORNAZIERO FILHO
Boa tarde Amigo,
Posso te falar, pois programo muito esse tipo de rotina,
Infelizmente cada banco tem o seu layout,
hoje nao existe um layout unificado para todos os bancos
em materia de conciliação,
entao infelizmente você tera que desenvolver, uma rotina para o BB
e outra para outro banco.
A dica que eu te dou, antes de desenvolver um novo, da uma olhada nos que voce ja tem,
pois alguns bancos utilizam layouts iguais, porem pode acontecer o que você esta vendo agora.
dois diferentes,
dai neste caso, voce precisa fazer o tratamento , diferente por bancos.
espero ter ajudado.
att
Chiodini
Boa tarde Amigo,
Posso te falar, pois programo muito esse tipo de rotina,
Infelizmente cada banco tem o seu layout,
hoje nao existe um layout unificado para todos os bancos
em materia de conciliação,
entao infelizmente você tera que desenvolver, uma rotina para o BB
e outra para outro banco.
A dica que eu te dou, antes de desenvolver um novo, da uma olhada nos que voce ja tem,
pois alguns bancos utilizam layouts iguais, porem pode acontecer o que você esta vendo agora.
dois diferentes,
dai neste caso, voce precisa fazer o tratamento , diferente por bancos.
espero ter ajudado.
att
Chiodini
GOSTEI 0
Alan Souza
06/01/2014
eu já tive um problema parecido, mas com outro arquivo bancário, e a solução foi criar uma classe genérica com as rotinas comuns de todos os bancos, e classes herdando da genérica para cada banco, com a rotina específica de leitura do arquivo (creio que seja a 'process' no seu caso). Desse modo teria que ter uma rotina para dizer de qual banco é o arquivo para chamar a classe correspondente.
GOSTEI 0
Rubens Filho
06/01/2014
Muito obrigado pelas respostas pessoal.
Farei algo genérico mesmo e irei especializando.
Abraços.
Farei algo genérico mesmo e irei especializando.
Abraços.
GOSTEI 0