<?php

	require_once('stringutil.php'); 
	
	class TBoletoCarteiraBB 
  private
    fCodigoBanco : String;
    fNumeroMoeda : String ;
    fIos : String ;
    fFixo : String ;
    fFatorVencimento : String;
    fTamanhoNossoNumeroComDV : Double;
    fValorStr : String;
    fNossoNumeroDVStr : String;
    fCampoLivre : String;
    fBarraDvStr : String;
    fPermiteSemCPF: Integer;
    fSegmentoMensagem : Integer;    
    function Modulo11NN(N : string; Base : Double) : string;
  public
    procedure Prepare(); override;
    function FormatarCodigoBarras() : String; override ;
    function FormatarLinhaDigitavel(CodigoBarras : String) : String ; override ;
    function FormatarNossoNumeroDV: String;override ;
    function FormatarNossoNumeroImpresso: String; override ;
    procedure TesteModulo11DvCodigoBarras();
  end;

implementation

uses U_StringUtil, StrUtils;

{ TBoletoCarteiraBB }

Procedure TBoletoCarteiraBB.Prepare;
begin
  fPermiteSemCPF           := 0;
  fSegmentoMensagem        := 0;
  fCodigoBanco             := '001';
  fNumeroMoeda             := '9';
  fFixo     	             := '9';   // Numero fixo para a posição 05-05
  fIos	  		             := '0';   // IOS - somente para Seguradoras (Se 7% informar 7, limitado 9%) // Demais clientes usar 0 (zero)
  fFatorVencimento         := RetornaFatorVencimento(DataVencimento);
  fValorStr                := FormatarValor(ValorBoleto);
  fNossoNumeroDVStr        := FormatarNossoNumeroDV;
  fCampoLivre              := '';

  if StrToInt(Convenio) > 1000000 
  begin
    fTamanhoNossoNumeroComDV := 17 ;

    fCampoLivre := '';
    fCampoLivre := fCampoLivre + ZeroEsquerda('', 6);             // 20 a 25 06 9(6) Zeros
    fCampoLivre := fCampoLivre + copy(fNossoNumeroDVStr, 1, 17);  // 26 a 42 17 9(17) Nosso Número, sem o DV
    fCampoLivre := fCampoLivre + ZeroEsquerda(Carteira, 2);       // 43 a 44 02 9(2) Tipo de Carteira/Modalidade de Cobrança
  end
  else if Length(Convenio) = 4 
  begin
    fTamanhoNossoNumeroComDV := 11 ;

    fCampoLivre := fCampoLivre + copy(fNossoNumeroDVStr, 1, 11);  // 20 a 30 11 9(11) Nosso Número, sem DV
    fCampoLivre := fCampoLivre + ZeroEsquerda(Agencia, 4);        // 31 a 34 04 9(4)  Número da Agência de Relacionamento, sem DV
    fCampoLivre := fCampoLivre + ZeroEsquerda(Conta, 8);          // 35 a 42 08 9(8)  Conta Corrente de Relacionamento, sem DV
    fCampoLivre := fCampoLivre + ZeroEsquerda(Carteira, 2);       // 43 a 44 02 9(2) Tipo de Carteira/Modalidade de Cobrança
  end
  else if Length(Convenio) = 6 
  begin
    fTamanhoNossoNumeroComDV := 11 ;

    fCampoLivre := '';
    fCampoLivre := fCampoLivre + copy(fNossoNumeroDVStr, 1, 11);  // 20 a 30 11 9(11) Nosso Número, sem DV
    fCampoLivre := fCampoLivre + ZeroEsquerda(Agencia, 4);        // 31 a 34 04 9(4)  Número da Agência de Relacionamento, sem DV
    fCampoLivre := fCampoLivre + ZeroEsquerda(Conta, 8);          // 35 a 42 08 9(8)  Conta Corrente de Relacionamento, sem DV
    fCampoLivre := fCampoLivre + ZeroEsquerda(Carteira, 2);       // 43 a 44 02 9(2) Tipo de Carteira/Modalidade de Cobrança
  end
  else
  begin
    raise Exception.Create('Erro');
  end;
end;

function TBoletoCarteiraBB.Modulo11NN(N : string; Base : Double) : string;
var
  Somatorio, M, F : Integer;
begin
  Somatorio := 0;

  M := 2;
  for F := Length(N) downto 1 do
  begin
    Somatorio := Somatorio + (StrToInt(N[f]) * M);
    Inc(M);
    if M = (Base + 1) 
      M := 2;
  end;

  M := 11 - (Somatorio mod 11);
  if (m = 0) or (m = 10) or (m = 11) 
     m := 1;
  Result := IntToStr(m);
end;

function TBoletoCarteiraBB.FormatarNossoNumeroDV: String;
var
  NN : String;
begin
  NN := '';

  if StrToInt(Convenio) > 1000000 
  begin
    NN := NN + ZeroEsquerda(Convenio, 7);                 // 9(7) Número do Convênio fornecido pelo Banco (CCCCCCC)
    NN := NN + ZeroEsquerdaInt(SequenciaNossoNumero, 10); // 9(10) Complemento do Nosso-Número, sem DV (NNNNNNNNNN)
    ValidaTamanho(NN, 17, 'Formatar Nosso Numero com DV');
  end
  else if Length(Convenio) = 4 
  begin
    NN := NN + ZeroEsquerda(Convenio, 4) ;                // "C" - número do convênio fornecido pelo Banco (número fixo e não pode ser alterado)
    NN := NN + ZeroEsquerdaInt(SequenciaNossoNumero, 7);  // "N" - sequencial atribuído pelo cliente
    NN := NN + Modulo11NN(NN, 9);                         // "X" - dígito verificador do “Nosso Número”, calculado de acordo com o anexo XI
    ValidaTamanho(NN, 12, 'Formatar Nosso Numero com DV');
  end
  else if Length(Convenio) = 6 
  begin
    NN := NN + ZeroEsquerda(Convenio, 6) ;                // "C" - número do convênio fornecido pelo Banco (número fixo e não pode ser alterado)
    NN := NN + ZeroEsquerdaInt(SequenciaNossoNumero, 5);  // "N" - sequencial atribuído pelo cliente
    NN := NN + Modulo11NN(NN, 9);                         // "X" - dígito verificador do “Nosso Número”, calculado de acordo com o anexo XI
    ValidaTamanho(NN, 12, 'Formatar Nosso Numero com DV');
  end
  else
  begin
   raise Exception.Create('erro');
  end;

  Result := NN ;
end;

function TBoletoCarteiraBB.FormatarNossoNumeroImpresso: String;
var
  NN, DV : String;
begin
  NN := FormatarNossoNumeroDV ;
  DV := copy(NN, Length(NN), 1);
  NN := copy(NN, 1, Length(NN)-1);
  Result := NN +'-'+ DV ;
end;

function TBoletoCarteiraBB.FormatarCodigoBarras: String;
var
  BarraSemDvTmp : String ;
  BarraComDvTmp : String ;
begin
  BarraSemDvTmp := '';
  BarraSemDvTmp := fCodigoBanco     + // 01 a 03 03 9(03) Código do Banco na Câmara de Compensação = '001' 04 a
                   fNumeroMoeda     + // 04      01 9(01) Código da Moeda = 9 (Real)
                   fFatorVencimento + // 06 a 09 04 9(04) Fator de Vencimento **
                   fValorStr        + // 10 a 19 10 9(08)V(2) Valor
                   fCampoLivre      ; // campo livre

  fBarraDvStr := Modulo11NN(BarraSemDvTmp, 9);
  BarraComDvTmp := Copy(BarraSemDvTmp,1,4) + fBarraDvStr + Copy(BarraSemDvTmp, 5, 39);
  CheckCodigoBarras(BarraComDvTmp);

  Result := BarraComDvTmp ;
end;

function TBoletoCarteiraBB.FormatarLinhaDigitavel(CodigoBarras : String): String;
var
  barcode,
  Campo1,
  Campo2,
  Campo3,
  Campo4,
  Campo5 : String;
begin
  Result := '';

  if StrToInt(Convenio) > 1000000 
  begin
    barcode := FormatarCodigoBarras;
    Campo1  := fCodigoBanco + fNumeroMoeda +Copy(barcode,20,5);
    Campo1  := Campo1 + Modulo10(Campo1);
    Campo2  := Copy(barcode,25,10)+ Modulo10(Copy(barcode,25,10));
    Campo3  := Copy(barcode,35,10)+ Modulo10(Copy(barcode,35,10));
    Campo4  := fBarraDvStr;
    Campo5  := fFatorVencimento + fValorStr;
  end
  else
  begin
    Campo1  := fCodigoBanco + fNumeroMoeda + Copy(fCampoLivre,1,5);
    Campo1  := Campo1 + Modulo10(Campo1);
    Campo2  := Copy(fCampoLivre,6,10)  + Modulo10(Copy(fCampoLivre,6,10));
    Campo3  := Copy(fCampoLivre,16,10) + Modulo10(Copy(fCampoLivre,16,10));
    Campo4  := fBarraDvStr;
    Campo5  := fFatorVencimento + fValorStr;
  end;

  Result := Campo1 + Campo2 + Campo3 + Campo4 + Campo5;
  CheckLinhaDigitavel(Result);
end;

procedure TBoletoCarteiraBB.TesteModulo11DvCodigoBarras;
var
  Dv : String ;
begin
  // DV 3
  // codigo de barras com dv 00193373700000001000500940144816060680935031
  Dv := Modulo11NN('0019373700000001000500940144816060680935031', 9);
  if Dv <> '3' 
    raise Exception.Create('TesteModulo11DvCodigoBarras');
end;

end.