PDA

Ver la Versión Completa : no logro enviar .xml a bd usando el server


giulichajari
22-03-2015, 14:57:42
Buenas amigos, tengo una aplicacion cliente servidor en datasnap con delphi.

Del lado del cliente cuando no hay conexion los tickets y presupuestos se guardan en xml, con el metodo savetofile del clientdataset, ya que trabajo con este componente.

Entonces cuando retorna la conexion, necesito recorrer el directorio tickets por ejemplo y cargar los mismo en la base de datos, para lo mismo se usa el procedimiento del server que se usa siempre.

function cantticket():integer;
var
rec: TSearchRec;
carpeta:string;
cant:integer;

begin
carpeta :=ExtractFilePath(Application.ExeName)+'tickets';
cant:=0;
if FindFirst(carpeta, faAnyFile,rec) = 0 then
begin
try
repeat

if (rec.Attr and faDirectory = 0)
or (rec.Name <> '.')
and (rec.Name <> '..') then
inc(cant);
until FindNext(rec) <> 0;
except
FindClose(rec);
end;
FindClose(rec);
end;
Result:=cant;
ShowMessage(inttostr(cant));
end;


Pense contar la cantidad de archivos primero, pero me identifica 1(uno solo), y por ende no envia nada.

procedure LeerDirectorio();
var
rec: TSearchRec;
carpeta:string;
t,x:integer;
nombrearchivo,nombrecopia:string;
a:TServerMethods1Client;
l:integer;
fechae,horae:string;
cantidad,importe,preciou,efectivo,vuelto:Double;
idc,ids,idprodu,numero:Integer;
nuevoticket:string;
begin
if ClientModule1.SQLConnection1.Connected then
begin
a:=TServerMethods1Client.Create(ClientModule1.SQLConnection1.DBXConnection);

if (cantticket(carpeta)>0) then
begin
t:=cantticket(carpeta);


carpeta := ExtractFilePath(Application.ExeName)+'tickets';
SetCurrentDir(carpeta);
for x := 0 to t do

begin

if FindFirst(carpeta,FaAnyfile,rec)=0 then
begin
nombrearchivo:=rec.Name;
ShowMessage(nombrearchivo);
ClientModule1.cdsticketpendiente.LoadFromFile(nombrearchivo);
nombrecopia:=ExtractFileName(Application.ExeName) + 'ticketscopia\' + nombrearchivo;
CopyFile(Pchar(nombrearchivo),Pchar(nombrecopia),True);
idc:=1;
ids:=1;
numero:=1;
importe:=ClientModule1.cdsticketpendiente.FieldByName('total').Value;
fechae:=ClientModule1.cdsticketpendientefechae.AsString;
horae:=ClientModule1.cdsticketpendientehorae.AsString;
efectivo:=ClientModule1.cdsticketpendienteefectivo.AsFloat;
vuelto:=efectivo - importe;
a.nuevoticket(numero,ids,idc,importe,efectivo,vuelto,fechae,horae);

end;
end;

end
else
begin
ShowMessage('no quedan transacciones pendientes');
end;
end
else
begin
ShowMessage('no hay conexion para enviar los datos');
end;
end;

Lo que hice lo saque de ejemplos del foro y de la web, pero me esta costando.
Saludos

bitbow
22-03-2015, 17:24:31
Debes realizar la busqueda recursiva de archivos, hay muchos ejemplos de esto.

Enalces foro:
http://www.clubdelphi.com/foros/showthread.php?t=7181
http://www.clubdelphi.com/foros/showthread.php?t=86325

Saludos.

giulichajari
22-03-2015, 20:50:47
Bueno pues use la funcion de neftali:

procedure FindFiles(StartDir, FileMask: string; recursively: boolean; var FilesList: TStringList);
const
MASK_ALL_FILES = '*.*';
CHAR_POINT = '.';
var
SR: TSearchRec;
DirList: TStringList;
IsFound: Boolean;
i: integer;
begin
if (StartDir[length(StartDir)] <> '\') then begin
StartDir := StartDir + '\';
end;

// Crear la lista de ficheos en el directorio StartDir (no directorios!)
IsFound := FindFirst(StartDir + FileMask, faAnyFile - faDirectory, SR) = 0;
// MIentras encuentre
while IsFound do begin
FilesList.Add(StartDir + SR.Name);
IsFound := FindNext(SR) = 0;
end;

FindClose(SR);

// Recursivo?
if (recursively) then begin
// Build a list of subdirectories
DirList := TStringList.Create;
// proteccion
try
IsFound := FindFirst(StartDir + MASK_ALL_FILES, faAnyFile, SR) = 0;
while IsFound do
begin
if ((SR.Attr and faDirectory) <> 0) and
(SR.Name[1] <> CHAR_POINT) then
DirList.Add(StartDir + SR.Name);
IsFound := FindNext(SR) = 0;
end;
FindClose(SR);

// Scan the list of subdirectories
for i := 0 to DirList.Count - 1 do
FindFiles(DirList[i], FileMask, recursively, FilesList);
finally
DirList.Free;
end;
end;
end;

Ahora bien mi aplicacion de terminal de puesto de venta tiene un modulo con un edit con la cantidad de ticket(1 por archivo) y un progress bar para programar despues.

El caso es que en el evento OnShow del form llamo a

procedure TForm10.FormShow(Sender: TObject);
var
StartDir, FileMask: string;
recursively: boolean;
FilesList: TStringList;
x,cant:integer;
begin

StartDir:=ExtractFilePath(Application.ExeName) + 'tickets';

FindFiles(StartDir, FileMask, recursively, FilesList);




end;

pasandole los parametros Stardir, pero debo crear el objeto fileslist?

Luego debo agregar obviamente el codigo que quiero se ejecute al encontrar un archivo dentro del while.
procedure FindFiles(StartDir, FileMask: string; recursively: boolean; var FilesList: TStringList);
const
MASK_ALL_FILES = '*.*';
CHAR_POINT = '.';
var
SR: TSearchRec;
DirList: TStringList;
IsFound: Boolean;
i,x: integer;
a:TServerMethods1Client;
l:integer;
fechae,horae,nombrearchivo,nombrecopia:string;
cantidad,importe,preciou,efectivo,vuelto:Double;
idc,ids,idprodu,numero:Integer;
nuevoticket:string;
begin

if (StartDir[length(StartDir)] <> '\') then begin
StartDir := StartDir + '\';
end;
FilesList.Create;
// FileMask:='.xml'
// Crear la lista de ficheos en el directorio StartDir (no directorios!)
IsFound := FindFirst(StartDir + FileMask, faAnyFile - faDirectory, SR) = 0;
// MIentras encuentre

while IsFound do begin

FilesList.Add(StartDir + SR.Name);

IsFound := FindNext(SR) = 0;

end;

if FilesList.Count<>0 then
begin
for x:=FilesList.Count - 1 downto 0 do
begin

Form10.Etick.Text:=IntToStr(FilesList.Count);
nombrearchivo:=SR.Name;
ShowMessage(nombrearchivo);
ClientModule1.cdsticketpendiente.LoadFromFile(nombrearchivo);
nombrecopia:=ExtractFileName(Application.ExeName) + 'ticketscopia\' + nombrearchivo;
CopyFile(Pchar(nombrearchivo),Pchar(nombrecopia),True);
idc:=1;
ids:=1;
numero:=1;
importe:=ClientModule1.cdsticketpendiente.FieldByName('total').Value;
fechae:=ClientModule1.cdsticketpendientefechae.AsString;
horae:=ClientModule1.cdsticketpendientehorae.AsString;
efectivo:=ClientModule1.cdsticketpendienteefectivo.AsFloat;
vuelto:=efectivo - importe;
a.nuevoticket(numero,ids,idc,importe,efectivo,vuelto,fechae,horae);

end;
end;
FilesList.Destroy;

// Recursivo?
if (recursively) then begin
// Build a list of subdirectories
DirList := TStringList.Create;
// proteccion
try
IsFound := FindFirst(StartDir + MASK_ALL_FILES, faAnyFile, SR) = 0;
while IsFound do
begin
if ((SR.Attr and faDirectory) <> 0) and
(SR.Name[1] <> CHAR_POINT) then
DirList.Add(StartDir + SR.Name);
IsFound := FindNext(SR) = 0;
end;
FindClose(SR);

// Scan the list of subdirectories
for i := 0 to DirList.Count - 1 do
FindFiles(DirList[i], FileMask, recursively, FilesList);
finally
DirList.Free;
end;
end;
end;

Neftali [Germán.Estévez]
23-03-2015, 10:31:34
Hola.
No entiendo muy bien lo que estás haciendo con el procedimiento.

Justo está hecho en un procedimiento para que puedas utilizarlo donde quieras y reaprovecharlo. Si modificas el procedimiento y le añades cosas como estas ya no será "reaprovechable":


Form10.Etick.Text:=IntToStr(FilesList.Count);
nombrearchivo:=SR.Name;
ShowMessage(nombrearchivo);
ClientModule1.cdsticketpendiente.LoadFromFile(nombrearchivo);
nombrecopia:=ExtractFileName(Application.ExeName) + 'ticketscopia\' + nombrearchivo;
...


Utiliza el procedimiento para buscar todos los ficheros que hay en el directorio que cumplen unas condiciones. Una vez realizada la búsqueda, utiliza un bucle para hacer el trabajo que necesites... (y coloca tu código ahí)


// Crear la lista que vamos a utilizar
TS := TStringList.Create();
// Buscar ficheros en disco.
FindFiles(pathDeBusqueda, '*.xml', False, TS);
// Para cada fichero encontrado, realizamos el trabajo necesario...
for i := 0 to (TS.Count - 1) do begin
// Extraer nombre del fichero. en TS[i] está el path completo
fName := ExtractFileName(TS[i]);
....

AQUI HAZ LO QUE QUIERAS CON EL FICHERO....


end;
// liberar la lista
TS.Free;

giulichajari
23-03-2015, 18:37:16
Te comento que logre cargar los ficheros xml en el dataset, pero en el xml el metodo savetofile no guarda los internalCalc y los Aggregates, por lo que el dataset ticketspendientes por ej debe contener los mismos campos que el de ticket que se usa a diario.

con la diferencia de que el subtotal de cada registro de compra: precio * cantidad debe ser recalculado, luego mi total si es aggregate.:

FindFiles(pathDeBusqueda, '*.xml', False, TS);
Etick.Text:=IntToStr(TS.Count);
// Para cada fichero encontrado, realizamos el trabajo necesario...
for i := 0 to (TS.Count - 1) do begin
// Extraer nombre del fichero. en TS[i] está el path completo
fName := pathDeBusqueda + ExtractFileName(TS[i]);
if (ClientModule1.SQLConnection1.Connected) then
begin


with ClientModule1.cdsticketpendiente do
begin

LoadFromFile(fname);
Open;

First;
while not Eof do

begin
Edit;
FieldByName('subtotal').AsFloat:=FieldByName('precio').AsFloat * FieldByName('cantidad').AsFloat;
Post;
Next;
end;

end;

importe:=ClientModule1.cdsticketpendientetotal.Value;
fechae:=ClientModule1.cdsticketpendientefechae.AsString;

horae:=ClientModule1.cdsticketpendientehorae.AsString;

efectivo:=ClientModule1.cdsticketpendienteefectivo.AsFloat;
vuelto:=efectivo - importe;


a:=TServerMethods1Client.Create(ClientModule1.SQLConnection1.DBXConnection);
a.nuevoticket(numero,ids,idc,importe,efectivo,vuelto,fechae,horae);
ClientModule1.cdsticketpendiente.EmptyDataSet;

ClientModule1.cdsticketpendiente.Close;
TS.Free;

end
Me dice : list index of bounds(1)
Debo cargar los otros campos?

giulichajari
24-03-2015, 14:59:39
Hola amigos! abro un nuevo hilo porque hice una pregunta en otro creo fuera de lugar:

Cuando no hay conexion guardo los tickets de mi terminal de puesto de venta en un fichero xml.

Y tengo un form donde de haber conexion voy recorriendo el directiorio de los tickets y quiero cargarlos en la base de datos.

Primero que los campos que no son Data no se guardan en xml, por lo tanto hay que recalcularlos.
Y luego que no veo los cambios en la base de datos.
Ademas, no me convendria tener otro tclientdataset distinto para poder hacer tickets mientras vienen clientes en vez de usar el mismo?

procedure TForm8.FormShow(Sender: TObject);
var
TS:TStringList;
pathDeBusqueda,fname:string;
i:integer;
a:TServerMethods1Client;
x:integer;
fechae,horae:string;
cantidad,importe,preciou,efectivo,vuelto:Double;
idc,ids,idprodu,numero:Integer;
nuevoticket:string;
tot:Double;
begin
// Crear la lista que vamos a utilizar
TS := TStringList.Create();
pathDeBusqueda:=ExtractFilePath(Application.ExeName) + 'tickets\';

// Buscar ficheros en disco.
FindFiles(pathDeBusqueda, '*.xml', False, TS);
Etick.Text:=IntToStr(TS.Count);
// Para cada fichero encontrado, realizamos el trabajo necesario...
for i := 0 to (TS.Count - 1) do begin
// Extraer nombre del fichero. en TS[i] está el path completo
fName := pathDeBusqueda + ExtractFileName(TS[i]);
// si hay conexion al server
if (ClientModule1.SQLConnection1.Connected) then
begin
a:=TServerMethods1Client.Create(ClientModule1.SQLConnection1.DBXConnection);
//cargo dataset
with ClientModule1.cdsticket do
begin

LoadFromFile(fname);
Open;
for x := 0 to ClientModule1.cdsticket.RecordCount do

begin
Edit;
FieldByName('subtotal').AsFloat:=FieldByName('precio').AsFloat * FieldByName('cantidad').AsFloat;

Post;

end;

end;
//cargo variables y llamo al server
importe:=ClientModule1.cdsticket.FieldByName('total').Value;
fechae:=ClientModule1.cdsticketfechae.AsString;

horae:=ClientModule1.cdstickethorae.AsString;

efectivo:=ClientModule1.cdsticketefectivo.AsFloat;

vuelto:=efectivo - importe;
idc:=1;
ids:=1;
numero:=1;
a.nuevoticket(numero,ids,idc,importe,efectivo,vuelto,fechae,horae);
a.Free;
ClientModule1.cdsticket.EmptyDataSet;
end;

end;



end;

lo primero que hago es buscar los ficheros, luego compruebo si hay conexion, si hay para cada archivo hago subtotal y total, y llamo al servidor datasnap. vacio el dataset.

Alguien me puede ayudar

Casimiro Notevi
24-03-2015, 18:05:43
Hola amigos! abro un nuevo hilo porque hice una pregunta en otro creo fuera de lugar:Es el mismo asunto y ya te han respondido, no abras otro hilo para lo mismo, sigue con el que habías abierto.
Los he unido.