Ver Mensaje Individual
  #7  
Antiguo 02-07-2014
Avatar de hgiacobone
hgiacobone hgiacobone is offline
Miembro
 
Registrado: may 2003
Ubicación: La Plata, Bs. As., Argentina
Posts: 165
Reputación: 21
hgiacobone Va por buen camino
Thumbs up Solucionado

Gracias a todos por participar.
Nobleza obliga, les dejo como lo hice.

Tuve que optimizar los StoreProc de la base de datos y el codigo, pero funciona bien. En 1 Hs está procesado.

En la Db de Firebird cree 2 tablas temporales (una para cada alicuota) sin indexar, con campo CUIT y ALICUOTA.
Mi tabla del padron principal tiene 3 campos: CUIT / Ali_Percep / Ali_Reten indexado con clave sobre el primero.

El proceso se hace desde el sistema disparando diferentes SP en la DB.
Primero un SP hace el borrado de las tablas temporales.
Luego cargo en un TStringList uno de los archivos para obtener los datos necesarios y almacenarlos en la tabla temporal correspondiente con un proceso similar a este:

<DELPHI>
Código Delphi [-]
var
    InicioSesion, FinSesion: TDateTime;
    s, m, sMsgErrores, sCuit: string;
    sAliPer,sAliRet:string;
    MyStringList:TStringList;
    n,i,Max:integer;
Begin

    InicioSesion:= Now;

    MyStringList := TStringList.Create;
    i:=0;
    progress1.Min:=0;
    progress1.Position:=0;
    MyStringList.LoadFromFile( 'x:\padron_retenciones.txt' );

     progress1.Min:=0;
     progress1.Max:= MyStringList.Count;
     progress1.Position:=0;

                DM.SP100.StoredProcName:='SP_TEMP_PER_INS';
                DM.SP101.StoredProcName:='SP_TEMP_RET_INS';
                DM.WriteTrans.StartTransaction;   //Transaccion inicial

                for i:=0 to MyStringList.Count-1 do
                begin
                  Application.ProcessMessages;

{Este es el metodo para acceder por campo delimitado
    MyStringList.Delimiter := '|';
    MyStringList.StrictDelimiter := True;
    MyStringList.DelimitedText := LineaDelArchivoDelimitado; // R|20100707121|1|2|000-0000000-0|16| ;
    Tabla.Campo1.Value := MyStringList[0];
    Tabla.Campo2.Value := MyStringList[1];
}

{Este es el metodo por posicion fija}
                  s:=MyStringList[i];
                  sCuit  :=Copy(s,30,11);
                  sAliRet:='0';
                  sAliPer:='0';

                  if ( (s[1]='P' {Percep}) or (s[1]='R' {Retenciones}) ) then
                  begin
                      if (s[1]='P')
                       then sAliPer:=Copy(s,48,4)
                        else sAliRet:=Copy(s,48,4);

                      LInfo.Caption:=Format('Procesando registro %d de %d... (CUIT %s)', [i, Max, sCuit ]);
                      Pinfo.Refresh;

                      progress1.Position:= i;

                          if (s[1]='P') then
                          begin
                          DM.SP100.ParamByName('Cuit').AsString   := sCuit;
                          DM.SP100.ParamByName('Alicuota').AsFloat:= StrToCurr(Copy(sAliPer,1,1)+'.'+Copy(sAliPer,3,2));
                          DM.SP100.Prepare;
                          DM.SP100.ExecProc;
                          end
                          else begin
                          DM.SP101.ParamByName('Cuit').AsString   := sCuit;
                          DM.SP101.ParamByName('Alicuota').AsFloat:= StrToCurr(Copy(sAliRet,1,1)+'.'+Copy(sAliRet,3,2));
                          DM.SP101.Prepare;
                          DM.SP101.ExecProc;
                          end;


                          //graba cada 500 registros
                          IF ((i mod 500) = 0) THEN
                          BEGIN
                            TRY
                              LInfo.Caption:=Format('Grabando bloque %d/%d...', [i, Max ]);
                              Pinfo.Refresh;

                              if (DM.WriteTrans.InTransaction) then
                              begin
                                 DM.WriteTrans.Commit;
                                 DM.WriteTrans.StartTransaction;  //Inicia una Trans consecutiva
                              end
                              else DM.WriteTrans.StartTransaction;  //Fuerza iniciar una Trans
                            Except
                              on E:Exception do
                              begin
                               DM.WriteTrans.Rollback;
                               Bien:= FALSE;
                               PInfo.Visible:=False;
                               sMsgErrores:= sMsgErrores + 'Error al grabar bloque de datos.'#13+E.Message;
                               Break;
                              end;
                            End;
                          END;
                  end;
                end;{lineas_del_archivo}


                //Compruebo si hay un resto sobre ultimos 500 con transac activa los guarda tambien
                if (DM.WriteTrans.InTransaction) then
                begin
                  TRY
                    DM.WriteTrans.Commit;
                  Except
                    on E:Exception do
                    begin
                     DM.WriteTrans.Rollback;
                     Bien:= FALSE;
                     PInfo.Visible:=False;
                     sMsgErrores:= sMsgErrores + 'Error al guardar el RESTO.'#13+E.Message;
                     Break;
                    end;
                  End;
                end;



Si todo anduvo bien (yo utilizo banderas de status, pero lo anterior puede encapsularse en una funcion que devuelva True/False y obrar en consecuencia) entonces unimos mediante otro SP encargado de unir en el padron definitivo las alicuotas existentes en las dos tablas temporales:

Código Delphi [-]
              Linfo.Caption:='Guardando datos. Aguarde...';
              PInfo.Refresh;

              DM.WriteTrans.StartTransaction;
              TRY
                DM.SP101.StoredProcName:='';
                DM.SP101.StoredProcName:='SP_PADRON_MERGE';
                DM.SP101.ExecProc;
                DM.WriteTrans.Commit;

                  Linfo.Caption:='Verificando clientes...';
                  PInfo.Refresh;

                  Actualizar_Alicuotas_Clientes; //actaulizamos Tabla clientes

                  FinSesion:= Now;
                  m:= Format('(Tiempo: %s)', [ TimeToStr(FinSesion - InicioSesion) ]);

                  Linfo.Caption:='Importación Finalizada - ' + m;
                  PInfo.Refresh;

                  Application.MessageBox(PChar('Proceso finalizado correctamente.'#13 + m),
                    'Aviso', MB_OK+MB_ICONINFORMATION);

              Except
                on E:Exception do
                begin
                 DM.WriteTrans.Rollback;
                 Bien:= FALSE;
                 PInfo.Visible:=False;
                 MessageDlg('Error al actualizar el padrón.'#13#13'Tipo de error:'#13+E.Message, mtError, [mbOk],0);
                end;
              End;
end;


------
<FIREBIRD>

En la DB, el SP encargado de unir a la tabla del Padron definitivo las alicuotas existentes en las dos tablas temporales es esto:

Código SQL [-]
Create or Alter Procedure SP_PADRON_MERGE
as
declare variable sCUIT char(13);
declare variable nP numeric(6,2);
declare variable nR numeric(6,2);
begin
/*
  Se utiliza cuando las alicuotas vienen en 2 archivos separados.
*/

--Paso 1: borramos padron anterior
 execute procedure SP_PADRON_DEL;

--Paso 2: Insertamos toda la tabla de Retenciones
   INSERT INTO PADRON (CUIT, ALICUOTA_RETENCION, ALICUOTA_PERCEPCION)
          SELECT R.cuit, coalesce(R.alicuota,0), 0
          FROM TEMP_RETEN R ;

--Paso 3: Buscamos e insertamos desde tabla Percepciones
   For
     Select T.cuit, coalesce(T.alicuota,0) From TEMP_PERCEP T
     Into :sCUIT, :nP
     Do
     Begin
       Select P.ALICUOTA_RETENCION from PADRON P
       Where (P.CUIT = :sCUIT)
       Rows 1 to 1
       into :nR ;

       UPDATE or INSERT INTO PADRON (CUIT, ALICUOTA_RETENCION, ALICUOTA_PERCEPCION)
       VALUES (:sCUIT, coalesce(:nR, 0) , coalesce(:nP, 0) )
       MATCHING (CUIT);
     End
end;

Saludos a la comunidad,
__________________
Gracias de antemano por vuestra ayuda.
·.:*:.·Yako·.:*:.·
Responder Con Cita