O NeoMatrix Tech está de casa nova!

Você deverá ser redirecionado em 6 segundos. Se não, visite:
http://www.leonelfraga.com/neomatrixtech
e atualize seus favoritos.

Aviso IMPORTANTÍSSIMO!

Aviso aos navegantes:

O NeoMatrix Tech mudou de casa!!!

A partir de agora, acessem pelo novo endereço:

http://www.leonelfraga.com/neomatrixtech

Ué... mas é só o domínio mudou de lugar?

R: Na verdade, não é bem assim hehe. Este domínio que você acessa agora aponta para um blog hospedado no Blogger, enquanto no novo, aponta para um blog na plataforma Wordpress, hospedagem própria, muito mais rápida e com um layout mais agradável de ler ;)

Não vou fechar este domínio igual ao que eu fiz com o NM Light (que já está 100% na nova plataforma). Talvez beeeeeeem depois eu faça isso.

Todos os posts daqui se encontram lá, e novos posts serão colocados somente no novo endereço.
A única coisa que não consegui importar foram os comentários. Mas em breve vai ter um post contando sobre a epopéia que foi migrar o NeoMatrix Tech!

Somente vou fechar a área de comentários daqui. Caso queiram comentar, favor ver o post correspondente no "Novo NeoMatrix Tech" e comentem por lá. É bem melhor! (pena que os permalinks "amigáveis para SEO" não funcionam lá, dá erro 404 e não consigo fazer a configuração funcionar. E olha que eu já vi vários artigos falando desse assunto :( ).

Quem assina o feed, já está lendo o conteúdo do novo NeoMatrix Tech!

quarta-feira, 17 de junho de 2009

Fazendo Arquivos EDI com C# aplicando POO Parte 1

Esta série de quatro artigos são republicações da série “Fazendo Arquivos EDI com C# aplicando POO” que coloquei, a algum tempo atrás, em meu site do Multiply.

Este é um artigo que propõe a construção de um lay-out de arquivo do tipo fixo-blocado, utilizando a linguagem C# e com técnicas de Programação Orientada a Objetos.

Um arquivo do tipo fixo-blocado é utilizado por várias empresas com a finalidade de trocar informações entre sistemas (daí o EDI - Electronic Data Interchange do título) através de troca de arquivos.

Sua característica principal é que os campos em cada um dos registros (linhas do arquivo) possuirem tamanho fixo (em quantidade de caracteres) e são organizados sequencialmente.

Um arquivo é composto de várias linhas, e cada linha de vários campos descritos acima; cada campo possui uma máscara, ou formatação.

Cada sistema que utiliza-se deste método possui um documento onde são descritas as características do arquivo, tais como o tamanho dos registros, tipos de registros e a formatação dos campos, o famigerado lay-out.

Geralmente, cada arquivo possui um registro Header (Cabeçalho), onde geralmente é apresentado campos que indicam a data de geração, tipo de arquivo, entre outros;
vários registros detalhe e um registro final (Trailler).

Para o artigo, vamos construir um lay-out bem simples, e um programa para apresentar os registros em tela, com os campos devidamente separados.

O lay-out proposto consiste em:

Descrição            Tipo      Tamanho   Posição Inicial  Obs.
 Nome                  X           40            1
 Data de Nascimento    D            8           41         DDMMAAAA
 Tipo de Pessoa        X            1           49         F ou J
 Documento             N(0)        20           50
 Saldo Atual           N(2)        12           70         10 posições, 2 decimais s/ separador

Primeiramente, vamos "transformar" o conceito de arquivo fixo blocado em objetos, ou seja, modelar as classes que irão compor o nosso projeto.

Bem, você poderia perguntar, "simplesmente posso construir um programa que separa substrings, aplica em cada campo e exibe na tela, não é"?

Sim, isso pode ser feito, eu também já fiz várias vezes dessa forma, sempre repetindo o mesmo código várias vezes, claro que com as devidas sutilezas em cada implementação.

Minha proposta neste artigo é a construção de um "motor", que tem a capacidade de interpretar qualquer tipo de layout, um mecanismo básico, que poderá ser implementado
em qualquer layout específico.

Retomando o raciocínio... Um arquivo do tipo fixo-blocado é uma *coleção* de registros; cada registro é uma *coleção* de campos, e estes campos possuem atributos tais como o seu tamanho de caracteres, o seu tipo (que pode ser alfanumérico, data, numérico, etc), uma máscara (por exemplo, DDMMAAAA - data sem separador), quantidade de casas decimais, no caso de numéricos e sua posição inicial dentro da linha.

Vejam o abuso da palavra *coleção*. Significa que utilizaremos bastante coleções em nosso projeto.

Vamos começar pela parte mais básica (e a mais complexa, por sinal) de um arquivo: os campos de cada registro. Cada campo possui os atributos conforme dito acima. Temos os seguintes atributos em cada campo:

- Tipo
- Descrição
- Tamanho
- Posições Inicial e Final
- Quantidade Casas Decimais

Podemos ainda ter:

- Valor Padrão
- Separadores de data, decimais, milhar, hora, etc.
- Ordem do campo no Registro.

Os tipos de campo, podem ser basicamente numéricos e alfanuméricos, sendo os outros derivados deste, com as suas respectivas máscaras de formatação, podendo formar datas separadas por barra, ponto, números decimais sem separador, entre muitos outros. Para delimitar os tipos com que a nossa classe de campo irá trabalhar, vamos representar cada tipo através de um item de uma enumeração, assim podemos saber quais tipos poderemos ter em cada campo. Veja a implementação a seguir:

   1: /// <summary>
   2: /// Representa cada tipo de dado possível em um arquivo EDI.
   3: /// </summary>
   4: public enum TTiposDadoEDI
   5: {
   6:    /// <summary>
   7:    /// Representa um campo alfanumérico, alinhado à esquerda e com brancos à direita. A propriedade ValorNatural é do tipo String
   8:    /// </summary>
   9:    ediAlpha,
  10:    /// <summary>
  11:    /// Representa um campo numérico inteiro alinhado à direita com zeros à esquerda. A propriedade ValorNatural é do tipo Int ou derivados
  12:    /// </summary>
  13:    ediInteiro,
  14:    /// <summary>
  15:    /// Representa um campo numérico com decimais, sem o separador de decimal. A propriedade ValorNatural é do tipo Double
  16:    /// </summary>
  17:    ediNumericoSemSeparador,
  18:    /// <summary>
  19:    /// Representa um campo numérico com decimais, com o caracter ponto (.) como separador decimal,
  20:    /// alinhado à direita com zeros à esquerda. A propriedade ValorNatural é do tipo Double
  21:    /// </summary>
  22:    ediNumericoComPonto,
  23:    /// <summary>
  24:    /// Representa um campo numérico com decimais, com o caracter vírgula (,) como separador decimal,
  25:    /// alinhado à direita com zeros à esquerda. A propriedade ValorNatural é do tipo Double
  26:    /// </summary>
  27:    ediNumericoComVirgula,
  28:    /// <summary>
  29:    /// Representa um campo de data no formato ddm/mm/aaaa. A propriedade ValorNatural é do tipo DateTime
  30:    /// </summary>
  31:    ediDataDDMMAAAA,
  32:    /// <summary>
  33:    /// Representa um campo de data no formato aaaa/mm/dd. A propriedade ValorNatural é do tipo DateTime
  34:    /// </summary>
  35:    ediDataAAAAMMDD,
  36:    /// <summary>
  37:    /// Representa um campo de data no formato dd/mm. A propriedade ValorNatural é do tipo DateTime, com o ano igual a 1900
  38:    /// </summary>
  39:    ediDataDDMM,
  40:    /// <summary>
  41:    /// Representa um campo de data no formato mm/aaaa. A propriedade ValorNatural é do tipo DateTime, com o dia igual a 01
  42:    /// </summary>
  43:    ediDataMMAAAA,
  44:    /// <summary>
  45:    /// Representa um campo de data no formato mm/dd. A propriedade ValorNatural é do tipo DateTime com o ano igual a 1900
  46:    /// </summary>
  47:    ediDataMMDD,
  48:    /// <summary>
  49:    /// Representa um campo de hora no formato HH:MM. A propriedade ValorNatural é do tipo DateTime, com a data igual a 01/01/1900
  50:    /// </summary>
  51:    ediHoraHHMM,
  52:    /// <summary>
  53:    /// Representa um campo de hora no formato HH:MM:SS. A propriedade ValorNatural é do tipo DateTime, com a data igual a 01/01/1900
  54:    /// </summary>
  55:    ediHoraHHMMSS,
  56:    /// <summary>
  57:    /// Representa um campo de data no formato DD/MM/AAAA. A propriedade ValorNatural é do tipo DateTime.
  58:    /// </summary>
  59:    ediDataDDMMAA,
  60:    /// <summary>
  61:    /// Representa um campo de data no formato DD/MM/AAAA, porém colocando zeros no lugar de espaços no ValorFormatado. A propriedade
  62:    /// ValorNatural é do tipo DateTime, e este deve ser nulo caso queira que a data seja zero.
  63:    /// </summary>
  64:    ediDataDDMMAAAAWithZeros,
  65:    /// <summary>
  66:    /// Representa um campo de data no formato AAAA/MM/DD, porém colocando zeros no lugar de espaços no ValorFormatado. A propriedade
  67:    /// ValorNatural é do tipo DateTime, e este deve ser nulo caso queira que a data seja zero.
  68:    /// </summary>
  69:    ediDataAAAAMMDDWithZeros
  70: }

Cada tipo suportado está comentado, dispensando maiores comentários a respeito deles.
Ah, quanto ao prefixo "T" em cada classe... coisas de quem veio do Delphi :-)

Agora, vamos implementar a classe básica de interpretação dos layouts, em partes:

   1: public class TCampoRegistroEDI
   2: {
   3:     #region Variáveis Privadas
   4:     private string _DescricaoCampo;
   5:     private TTiposDadoEDI _TipoCampo;
   6:     private int _TamanhoCampo;
   7:     private int _QtdDecimais;
   8:     private object _ValorNatural;
   9:     private string _ValorFormatado;
  10:     private int _OrdemNoRegistroEDI;
  11:     private string _SeparadorDatas;
  12:     private string _SeparadorHora;
  13:     private int _PosicaoInicial;
  14:     private int _PosicaoFinal;
  15:     #endregion
  16:  
  17:     #region Propriedades
  18:     /// <summary>
  19:     /// Descrição do campo no registro EDI (meramente descritivo)
  20:     /// </summary>
  21:     public string DescricaoCampo
  22:     {
  23:         get { return _DescricaoCampo; }
  24:         set { _DescricaoCampo = value; }
  25:     }
  26:  
  27:     /// <summary>
  28:     /// Tipo de dado de ORIGEM das informações do campo EDI.
  29:     /// </summary>
  30:     public TTiposDadoEDI TipoCampo
  31:     {
  32:         get { return _TipoCampo; }
  33:         set { _TipoCampo = value; }
  34:     }
  35:  
  36:     /// <summary>
  37:     /// Tamanho em caracteres do campo no arquivo EDI (DESTINO)
  38:     /// </summary>
  39:     public int TamanhoCampo
  40:     {
  41:         get { return _TamanhoCampo; }
  42:         set { _TamanhoCampo = value; }
  43:     }
  44:  
  45:     /// <summary>
  46:     /// Quantidade de casas decimais do campo, caso ele seja do tipo numérico sem decimais. Caso
  47:     /// não se aplique ao tipo de dado, o valor da propriedade será ignorado nas funções de formatação.
  48:     /// </summary>
  49:     public int QtdDecimais
  50:     {
  51:         get { return _QtdDecimais; }
  52:         set { _QtdDecimais = value; }
  53:     }
  54:  
  55:     /// <summary>
  56:     /// Valor de ORIGEM do campo, sem formatação, no tipo de dado adequado ao campo. O valor deve ser atribuido
  57:     /// com o tipo de dado adequado ao seu proposto, por exemplo, Double para representar valor, DateTime para
  58:     /// representar datas e/ou horas, etc.
  59:     /// </summary>
  60:     public object ValorNatural
  61:     {
  62:         get { return _ValorNatural; }
  63:         set { _ValorNatural = value; }
  64:     }
  65:  
  66:     /// <summary>
  67:     /// Valor formatado do campo, pronto para ser utilizado no arquivo EDI. A formatação será de acordo
  68:     /// com a especificada na propriedade TipoCampo, com numéricos alinhados à direita e zeros à esquerda
  69:     /// e campos alfanuméricos alinhados à esquerda e com brancos à direita.
  70:     /// Também pode receber o valor vindo do arquivo EDI, para ser decodificado e o resultado da decodificação na propriedade
  71:     /// ValorNatural
  72:     /// </summary>
  73:     public string ValorFormatado
  74:     {
  75:         get { return _ValorFormatado; }
  76:         set { _ValorFormatado = value; }
  77:     }
  78:  
  79:     /// <summary>
  80:     /// Número de ordem do campo no registro EDI
  81:     /// </summary>
  82:     public int OrdemNoRegistroEDI
  83:     {
  84:         get { return _OrdemNoRegistroEDI; }
  85:         set { _OrdemNoRegistroEDI = value; }
  86:     }
  87:  
  88:     /// <summary>
  89:     /// Caractere separador dos elementos de campos com o tipo DATA. Colocar null caso esta propriedade
  90:     /// não se aplique ao tipo de dado.
  91:     /// </summary>
  92:     public string SeparadorDatas
  93:     {
  94:         get { return _SeparadorDatas; }
  95:         set { _SeparadorDatas = value; }
  96:     }
  97:  
  98:     /// <summary>
  99:     /// Caractere separador dos elementos de campos com o tipo HORA. Colocar null caso esta propriedade
 100:     /// não se aplique ao tipo de dado.
 101:     /// </summary>
 102:     public string SeparadorHora
 103:     {
 104:         get { return _SeparadorHora; }
 105:         set { _SeparadorHora = value; }
 106:     }
 107:  
 108:     /// <summary>
 109:     /// Posição do caracter inicial do campo no arquivo EDI
 110:     /// </summary>
 111:     public int PosicaoInicial
 112:     {
 113:         get { return _PosicaoInicial; }
 114:         set { _PosicaoInicial = value; }
 115:     }
 116:  
 117:     public int PosicaoFinal
 118:     {
 119:         get { return _PosicaoFinal; }
 120:         set { _PosicaoFinal = value; }
 121:     }
 122:     #endregion

Note que temos os atributos que abstraimos no início deste artigo, e dois atributos mais "curiosos":

- ValorNatural, do tipo object: Irá receber o valor do campo no tipo de dado que ele representa, ou seja, se for número inteiro, um int, se for decimal, double,
data, DateTime e assim por diante. Através do tipo de dados iremos aplicar a formatação adequada.

- ValorFormatado, do tipo string: Irá receber o valor já formatado, no momento da interpretação de um arquivo, e fornecerá o valor formatado no momento da geração.

Temos também os construtores da classe, que irão inicializar as propriedades com valores padrão:

   1: #region Construtores
   2: /// <summary>
   3: /// Cria um objeto TCampoRegistroEDI
   4: /// </summary>
   5: public TCampoRegistroEDI()
   6: { }
   7:  
   8: /// <summary>
   9: /// Cria um objeto do tipo TCampoRegistroEDI inicializando as propriedades básicas.
  10: /// </summary>
  11: /// <param name="pTipoCampo">Tipo de dado de origem dos dados</param>
  12: /// <param name="pTamanho">Tamanho em caracteres do campo (destino)</param>
  13: /// <param name="pDecimais">Quantidade de decimais do campo (destino)</param>
  14: /// <param name="pValor">Valor do campo (Origem), no tipo de dado adequado ao propósito do campo</param>
  15: /// <param name="pSeparadorHora">Separador de hora padrão; null para sem separador</param>
  16: /// <param name="pSeparadorData">Separador de data padrão; null para sem separador</param>
  17: /// <param name="pPosicaoInicial">Posição Inicial do Campo no Arquivo</param>
  18: public TCampoRegistroEDI(TTiposDadoEDI pTipoCampo, int pTamanho, int pDecimais, object pValor, string pSeparadorHora, string pSeparadorData, int pPosicaoInicial)
  19: {
  20:     this._TipoCampo = pTipoCampo;
  21:     this._TamanhoCampo = pTamanho;
  22:     this._QtdDecimais = pDecimais;
  23:     this._ValorNatural = pValor;
  24:     this._SeparadorHora = pSeparadorHora;
  25:     this._SeparadorDatas = pSeparadorData;
  26:     this._OrdemNoRegistroEDI = 0;
  27:     this._DescricaoCampo = "";
  28:     this._PosicaoInicial = pPosicaoInicial - 1; //Compensa a indexação com base em zero
  29:     this._PosicaoFinal = pPosicaoInicial + this._TamanhoCampo;
  30: }
  31: #endregion

Agora que vem a parte legal, que é onde será feita a formatação do valor informado através da propriedade ValorNatural em uma formatação condizente com o nosso lay-out:
No momento da geração do arquivo, vamos utilizar:

   1: /// <summary>
   2: /// Aplica formatação ao valor do campo em ValorNatural, colocando o resultado na propriedade ValorFormatado
   3: /// </summary>
   4: public void CodificarNaturalParaEDI()
   5: {
   6:     switch (this._TipoCampo)
   7:     {
   8:         case TTiposDadoEDI.ediAlpha:
   9:             {
  10:                 this._ValorFormatado = this._ValorNatural.ToString().Trim().PadRight(this._TamanhoCampo, ' ');
  11:                 break;
  12:             }
  13:         case TTiposDadoEDI.ediInteiro:
  14:             {
  15:                 this._ValorFormatado = this._ValorNatural.ToString().Trim().PadLeft(this._TamanhoCampo, '0');
  16:                 break;
  17:             }
  18:         case TTiposDadoEDI.ediNumericoSemSeparador:
  19:             {
  20:                 string Formatacao = "{0:f" + this._QtdDecimais.ToString() + "}";
  21:                 this._ValorFormatado = String.Format(Formatacao, this._ValorNatural).Replace(",","").Replace(".","").Trim().PadLeft(this._TamanhoCampo, '0');
  22:                 break;
  23:             }
  24:         case TTiposDadoEDI.ediNumericoComPonto:
  25:             {
  26:                 string Formatacao = "{0:f" + this._QtdDecimais.ToString() + "}";
  27:                 this._ValorFormatado = String.Format(Formatacao, this._ValorNatural).Replace(",", ".").Trim().PadLeft(this._TamanhoCampo, '0');
  28:                 break;
  29:             }
  30:         case TTiposDadoEDI.ediNumericoComVirgula:
  31:             {
  32:                 string Formatacao = "{0:f" + this._QtdDecimais.ToString() + "}";
  33:                 this._ValorFormatado = String.Format(Formatacao, this._ValorNatural).Replace(".", ",").Trim().PadLeft(this._TamanhoCampo, '0');
  34:                 break;
  35:             }
  36:         case TTiposDadoEDI.ediDataAAAAMMDD:
  37:             {
  38:                 if ( (DateTime)this._ValorNatural != DateTime.MinValue)
  39:                 {
  40:                     string sep = (this._SeparadorDatas == null ? "" : this._SeparadorDatas.ToString());
  41:                     string Formatacao = "{0:yyyy" + sep + "MM" + sep + "dd}";
  42:                     this._ValorFormatado = String.Format(Formatacao, this._ValorNatural);
  43:                 }
  44:                 else
  45:                 {
  46:                     this._ValorNatural = "";
  47:                     goto case TTiposDadoEDI.ediAlpha;
  48:                 }
  49:                 break;
  50:             }
  51:         case TTiposDadoEDI.ediDataDDMM:
  52:             {
  53:                 if ((DateTime)this._ValorNatural != DateTime.MinValue)
  54:                 {
  55:                     string sep = (this._SeparadorDatas == null ? "" : this._SeparadorDatas.ToString());
  56:                     string Formatacao = "{0:dd" + sep + "MM}";
  57:                     this._ValorFormatado = String.Format(Formatacao, this._ValorNatural);
  58:                 }
  59:                 else
  60:                 {
  61:                     this._ValorNatural = "";
  62:                     goto case TTiposDadoEDI.ediAlpha;
  63:                 }
  64:                 break;
  65:             }
  66:         case TTiposDadoEDI.ediDataDDMMAAAA:
  67:             {
  68:                 if ((DateTime)this._ValorNatural != DateTime.MinValue)
  69:                 {
  70:                     string sep = (this._SeparadorDatas == null ? "" : this._SeparadorDatas.ToString());
  71:                     string Formatacao = "{0:dd" + sep + "MM" + sep + "yyyy}";
  72:                     this._ValorFormatado = String.Format(Formatacao, this._ValorNatural);
  73:                 }
  74:                 else
  75:                 {
  76:                     this._ValorNatural = "";
  77:                     goto case TTiposDadoEDI.ediAlpha;
  78:                 }
  79:                 break;
  80:             }
  81:         case TTiposDadoEDI.ediDataDDMMAA:
  82:             {
  83:                 if ((DateTime)this._ValorNatural != DateTime.MinValue)
  84:                 {
  85:                     string sep = (this._SeparadorDatas == null ? "" : this._SeparadorDatas.ToString());
  86:                     string Formatacao = "{0:dd" + sep + "MM" + sep + "yy}";
  87:                     this._ValorFormatado = String.Format(Formatacao, this._ValorNatural);
  88:                 }
  89:                 else
  90:                 {
  91:                     this._ValorNatural = "";
  92:                     goto case TTiposDadoEDI.ediAlpha;
  93:                 }
  94:                 break;
  95:             }
  96:         case TTiposDadoEDI.ediDataMMAAAA:
  97:             {
  98:                 if ((DateTime)this._ValorNatural != DateTime.MinValue)
  99:                 {
 100:                     string sep = (this._SeparadorDatas == null ? "" : this._SeparadorDatas.ToString());
 101:                     string Formatacao = "{0:MM" + sep + "yyyy}";
 102:                     this._ValorFormatado = String.Format(Formatacao, this._ValorNatural);
 103:                 }
 104:                 else
 105:                 {
 106:                     this._ValorNatural = "";
 107:                     goto case TTiposDadoEDI.ediAlpha;
 108:                 }
 109:                 break;
 110:             }
 111:         case TTiposDadoEDI.ediDataMMDD:
 112:             {
 113:                 if ((DateTime)this._ValorNatural != DateTime.MinValue)
 114:                 {
 115:                     string sep = (this._SeparadorDatas == null ? "" : this._SeparadorDatas.ToString());
 116:                     string Formatacao = "{0:MM" + sep + "dd}";
 117:                     this._ValorFormatado = String.Format(Formatacao, this._ValorNatural);
 118:                 }
 119:                 else
 120:                 {
 121:                     this._ValorNatural = "";
 122:                     goto case TTiposDadoEDI.ediAlpha;
 123:                 }
 124:                 break;
 125:             }
 126:         case TTiposDadoEDI.ediHoraHHMM:
 127:             {
 128:                 string sep = (this._SeparadorHora == null ? "" : this._SeparadorHora.ToString());
 129:                 string Formatacao = "{0:HH" + sep + "mm}";
 130:                 this._ValorFormatado = String.Format(Formatacao, this._ValorNatural);
 131:                 break;
 132:             }
 133:         case TTiposDadoEDI.ediHoraHHMMSS:
 134:             {
 135:                 string sep = (this._SeparadorHora == null ? "" : this._SeparadorHora.ToString());
 136:                 string Formatacao = "{0:HH" + sep + "mm" + sep + "ss}";
 137:                 this._ValorFormatado = String.Format(Formatacao, this._ValorNatural);
 138:                 break;
 139:             }
 140:         case TTiposDadoEDI.ediDataDDMMAAAAWithZeros:
 141:             {
 142:                 string sep = (this._SeparadorDatas == null ? "" : this._SeparadorDatas.ToString());
 143:                 if ( (this._ValorNatural != null) || (!this.ValorNatural.ToString().Trim().Equals("")))
 144:                 {
 145:                     string Formatacao = "{0:dd" + sep + "MM" + sep + "yyyy}";
 146:                     this._ValorFormatado = String.Format(Formatacao, this._ValorNatural);
 147:                 }
 148:                 else
 149:                 {
 150:                     this._ValorFormatado = "00" + sep + "00" + sep + "0000";
 151:                 }
 152:                 break;
 153:             }
 154:         case TTiposDadoEDI.ediDataAAAAMMDDWithZeros:
 155:             {
 156:                 string sep = (this._SeparadorDatas == null ? "" : this._SeparadorDatas.ToString());
 157:                 if (this._ValorNatural != null)
 158:                 {
 159:                     string Formatacao = "{0:yyyy" + sep + "MM" + sep + "dd}";
 160:                     this._ValorFormatado = String.Format(Formatacao, this._ValorNatural);
 161:                 }
 162:                 else
 163:                 {
 164:                     this._ValorFormatado = "00" + sep + "00" + sep + "0000";
 165:                 }
 166:                 break;
 167:             }
 168:     }
 169: }

Note que nesta ocasião, dependendo do tipo de dado informado, fazemos a conversão do object em ValorNaturalpara string, aplicando a máscara informada na mesma, e retornando essa string na propriedade ValorFormatado

Já no momento da interpretação do campo, iremos utilizar o seguinte:

   1: /// <summary>
   2: /// Transforma o valor vindo do campo do registro EDI da propriedade ValorFormatado para o valor natural (com o tipo
   3: /// de dado adequado) na propriedade ValorNatural
   4: /// </summary>
   5: public void DecodificarEDIParaNatural()
   6: {
   7:     if (this._ValorFormatado.Trim().Equals(""))
   8:     {
   9:         this._ValorNatural = null;
  10:     }
  11:     else
  12:     {
  13:         switch (this._TipoCampo)
  14:         {
  15:             case TTiposDadoEDI.ediAlpha:
  16:                 {
  17:                     this._ValorNatural = this._ValorFormatado.ToString().Trim();
  18:                     break;
  19:                 }
  20:             case TTiposDadoEDI.ediInteiro:
  21:                 {
  22:                     this._ValorNatural = long.Parse(this._ValorFormatado.ToString().Trim());
  23:                     break;
  24:                 }
  25:             case TTiposDadoEDI.ediNumericoSemSeparador:
  26:                 {
  27:                     string s = this._ValorFormatado.Substring(0, this._ValorFormatado.Length - this._QtdDecimais) + "," + this._ValorFormatado.Substring(this._ValorFormatado.Length - this._QtdDecimais, this._QtdDecimais);
  28:                     this._ValorNatural = Double.Parse(s.Trim());
  29:                     break;
  30:                 }
  31:             case TTiposDadoEDI.ediNumericoComPonto:
  32:                 {
  33:                     this._ValorNatural = Double.Parse(this._ValorFormatado.ToString().Replace(".", ",").Trim());
  34:                     break;
  35:                 }
  36:             case TTiposDadoEDI.ediNumericoComVirgula:
  37:                 {
  38:                     this._ValorNatural = Double.Parse(this._ValorFormatado.ToString().Trim().Replace(".", ","));
  39:                     break;
  40:                 }
  41:             case TTiposDadoEDI.ediDataAAAAMMDD:
  42:                 {
  43:                     if (!this._ValorFormatado.Trim().Equals(""))
  44:                     {
  45:                         string cAno = "";
  46:                         string cMes = "";
  47:                         string cDia = "";
  48:                         if (this._SeparadorDatas != null)
  49:                         {
  50:                             string[] split = this._ValorFormatado.Split(this._SeparadorDatas.ToCharArray());
  51:                             cAno = split[0];
  52:                             cMes = split[1];
  53:                             cDia = split[2];
  54:                         }
  55:                         else
  56:                         {
  57:                             cAno = this._ValorFormatado.Substring(0, 4);
  58:                             cMes = this._ValorFormatado.Substring(4, 2);
  59:                             cDia = this._ValorFormatado.Substring(6, 2);
  60:                         }
  61:                         if ((cDia.Equals("00") && cMes.Equals("00") && cAno.Equals("0000")))
  62:                         {
  63:                             this._ValorNatural = null;
  64:                         }
  65:                         else
  66:                         {
  67:                             this._ValorNatural = DateTime.Parse(cDia + "/" + cMes + "/" + cAno);
  68:                         }
  69:                     }
  70:                     else
  71:                     {
  72:                         this._ValorNatural = null;
  73:                     }
  74:                     break;
  75:                 }
  76:             case TTiposDadoEDI.ediDataDDMM:
  77:                 {
  78:                     if (!this._ValorFormatado.Trim().Equals(""))
  79:                     {
  80:                         string cAno = "1900";
  81:                         string cMes = "";
  82:                         string cDia = "";
  83:                         if (this._SeparadorDatas != null)
  84:                         {
  85:                             string[] split = this._ValorFormatado.Split(this._SeparadorDatas.ToCharArray());
  86:                             cMes = split[1];
  87:                             cDia = split[0];
  88:                         }
  89:                         else
  90:                         {
  91:                             cMes = this._ValorFormatado.Substring(2, 2);
  92:                             cDia = this._ValorFormatado.Substring(0, 2);
  93:                         }
  94:                         this._ValorNatural = DateTime.Parse(cDia + "/" + cMes + "/" + cAno);
  95:                     }
  96:                     else
  97:                     {
  98:                         this._ValorNatural = null;
  99:                     }
 100:                     break;
 101:                 }
 102:             case TTiposDadoEDI.ediDataDDMMAAAA:
 103:                 {
 104:                     string cDia = "";
 105:                     string cMes = "";
 106:                     string cAno = "";
 107:                     if (this._SeparadorDatas != null)
 108:                     {
 109:                         string[] split = this._ValorFormatado.Split(this._SeparadorDatas.ToCharArray());
 110:                         cAno = split[2];
 111:                         cMes = split[1];
 112:                         cDia = split[0];
 113:                     }
 114:                     else
 115:                     {
 116:                         cDia = this._ValorFormatado.Substring(0, 2);
 117:                         cMes = this._ValorFormatado.Substring(2, 2);
 118:                         cAno = this._ValorFormatado.Substring(4, 4);
 119:                     }
 120:                     if ((cDia.Equals("00") && cMes.Equals("00") && cAno.Equals("0000")) || this._ValorFormatado.Trim().Equals(""))
 121:                     {
 122:                         this._ValorNatural = DateTime.Parse("01/01/1900"); //data start
 123:                     }
 124:                     else
 125:                     {
 126:                         this._ValorNatural = DateTime.Parse(cDia + "/" + cMes + "/" + cAno);
 127:                     }
 128:                     break;
 129:                 }
 130:             case TTiposDadoEDI.ediDataDDMMAA:
 131:                 {
 132:                     string cDia = "";
 133:                     string cMes = "";
 134:                     string cAno = "";
 135:                     if (this._SeparadorDatas != null)
 136:                     {
 137:                         string[] split = this._ValorFormatado.Split(this._SeparadorDatas.ToCharArray());
 138:                         cAno = split[2];
 139:                         cMes = split[1];
 140:                         cDia = split[0];
 141:                     }
 142:                     else
 143:                     {
 144:                         cDia = this._ValorFormatado.Substring(0, 2);
 145:                         cMes = this._ValorFormatado.Substring(2, 2);
 146:                         cAno = this._ValorFormatado.Substring(4, 2);
 147:                     }
 148:                     this._ValorNatural = DateTime.Parse(cDia + "/" + cMes + "/" + cAno);
 149:                     break;
 150:                 }
 151:             case TTiposDadoEDI.ediDataMMAAAA:
 152:                 {
 153:                     string cDia = "01";
 154:                     string cMes = "";
 155:                     string cAno = "";
 156:                     if (this._SeparadorDatas != null)
 157:                     {
 158:                         string[] split = this._ValorFormatado.Split(this._SeparadorDatas.ToCharArray());
 159:                         cAno = split[1];
 160:                         cMes = split[0];
 161:                     }
 162:                     else
 163:                     {
 164:                         cMes = this._ValorFormatado.Substring(0, 2);
 165:                         cAno = this._ValorFormatado.Substring(2, 4);
 166:                     }
 167:                     this._ValorNatural = DateTime.Parse(cDia + "/" + cMes + "/" + cAno);
 168:                     break;
 169:                 }
 170:             case TTiposDadoEDI.ediDataMMDD:
 171:                 {
 172:                     string cDia = "";
 173:                     string cMes = "";
 174:                     string cAno = "1900";
 175:                     if (this._SeparadorDatas != null)
 176:                     {
 177:                         string[] split = this._ValorFormatado.Split(this._SeparadorDatas.ToCharArray());
 178:                         cMes = split[0];
 179:                         cDia = split[1];
 180:                     }
 181:                     else
 182:                     {
 183:                         cDia = this._ValorFormatado.Substring(2, 2);
 184:                         cMes = this._ValorFormatado.Substring(0, 2);
 185:                     }
 186:                     this._ValorNatural = DateTime.Parse(cDia + "/" + cMes + "/" + cAno);
 187:                     break;
 188:                 }
 189:             case TTiposDadoEDI.ediHoraHHMM:
 190:                 {
 191:                     string cHora = "";
 192:                     string cMinuto = "";
 193:                     if (this._SeparadorHora != null)
 194:                     {
 195:                         string[] split = this._ValorFormatado.Split(this._SeparadorHora.ToCharArray());
 196:                         cHora = split[0];
 197:                         cMinuto = split[1];
 198:                     }
 199:                     else
 200:                     {
 201:                         cHora = this._ValorFormatado.Substring(0, 2);
 202:                         cMinuto = this._ValorFormatado.Substring(2, 2);
 203:                     }
 204:                     this._ValorNatural = DateTime.Parse(cHora + ":" + cMinuto + ":00");
 205:                     break;
 206:                 }
 207:             case TTiposDadoEDI.ediHoraHHMMSS:
 208:                 {
 209:                     string cHora = "";
 210:                     string cMinuto = "";
 211:                     string cSegundo = "";
 212:                     if (this._SeparadorHora != null)
 213:                     {
 214:                         string[] split = this._ValorFormatado.Split(this._SeparadorHora.ToCharArray());
 215:                         cHora = split[0];
 216:                         cMinuto = split[1];
 217:                         cSegundo = split[2];
 218:                     }
 219:                     else
 220:                     {
 221:                         cHora = this._ValorFormatado.Substring(0, 2);
 222:                         cMinuto = this._ValorFormatado.Substring(2, 2);
 223:                         cSegundo = this._ValorFormatado.Substring(4, 2);
 224:                     }
 225:                     this._ValorNatural = DateTime.Parse(cHora + ":" + cMinuto + ":00");
 226:                     break;
 227:                 }
 228:             case TTiposDadoEDI.ediDataDDMMAAAAWithZeros:
 229:                 {
 230:                     goto case TTiposDadoEDI.ediDataDDMMAAAA;
 231:                 }
 232:             case TTiposDadoEDI.ediDataAAAAMMDDWithZeros:
 233:                 {
 234:                     goto case TTiposDadoEDI.ediDataAAAAMMDD;
 235:                 }
 236:         }
 237:     }
 238: }

Note que trabalhamos essencialmente com a conversão da string contida em ValorFormatado (obtida através da leitura do arquivo, que será detalhada na segunda parte
do artigo) nos tipos de dado correspondente à máscara informada, e retornando este objeto na propriedade ValorNatural.

Pronto, temos construída a classe que irá representar cada campo de um registro em um arquivo fixo-blocado. Note que esta classe é genérica, não foi informado nenhum atributo específico do layout que iremos construir, falado no início do artigo. Na segunda parte, vamos aplicar o conceito de POO sobre um registro de um arquivo.

Longo (principalmente os code-snippets :-)), não foi? Embora possamos fazer o proposto via ODBC (ainda não testei como se faz), esta série de artigos é mais para a aplicação do conceito de POO mesmo, embora eu já me utilizei deste código em alguns sistemas em produção :-)

Um abraço!

0 comentários:


Postar um comentário

Para tornar este artigo ainda mais interessante, escreva suas críticas (desde que construtivas e sem ofenças), elogios, sugestões, complementos, dúvidas, etc, etc, etc!!!

  © Blogger templates ProBlogger Template by Ourblogtemplates.com 2008 - Editado e configurado por Leonel F.

Voltar ao TOPO