PDA

Ver la Versión Completa : Array en class(TRemotable)


Miguel Galarza
05-04-2010, 21:44:22
Amigos del foro tengo este sig. problema: no puedo asignar valor a un Array en esta clase TRemotable, es tratando de acceder al WS de la Afip de Argentina para consumir el servicio de factura electronica, Estoy usando D7, parece una estupidez pero en verdad me tiene mal no poder resolverlo.
El esquema que tengo que enviar es el clasico de una facutura, cabecera y detalle precedido esto por por el nodo de autorizacion, el de autorizacion, la cabecera lo asigno pero ... cuando llego a el detalle me da error, supongo que la sintaxis es diferente en esta clase. ClsBFERequest = class(TRemotable)
private
FId: Int64;
FTipo_doc: Smallint;
FNro_doc: Int64;
FZona: Smallint;
FTipo_cbte: Smallint;
FPunto_vta: Integer;
FCbte_nro: Int64;
FImp_total: Double;
FImp_tot_conc: Double;
FImp_neto: Double;
FImpto_liq: Double;
FImpto_liq_rni: Double;
FImp_op_ex: Double;
FImp_perc: Double;
FImp_iibb: Double;
FImp_perc_mun: Double;
FImp_internos: Double;
FImp_moneda_Id: WideString;
FImp_moneda_ctz: Double;
FFecha_cbte: WideString;
FItems: ArrayOfItem;
public
destructor Destroy; override;
published
property Id: Int64 read FId write FId;
property Tipo_doc: Smallint read FTipo_doc write FTipo_doc;
property Nro_doc: Int64 read FNro_doc write FNro_doc;
property Zona: Smallint read FZona write FZona;
property Tipo_cbte: Smallint read FTipo_cbte write FTipo_cbte;
property Punto_vta: Integer read FPunto_vta write FPunto_vta;
property Cbte_nro: Int64 read FCbte_nro write FCbte_nro;
property Imp_total: Double read FImp_total write FImp_total;
property Imp_tot_conc: Double read FImp_tot_conc write FImp_tot_conc;
property Imp_neto: Double read FImp_neto write FImp_neto;
property Impto_liq: Double read FImpto_liq write FImpto_liq;
property Impto_liq_rni: Double read FImpto_liq_rni write FImpto_liq_rni;
property Imp_op_ex: Double read FImp_op_ex write FImp_op_ex;
property Imp_perc: Double read FImp_perc write FImp_perc;
property Imp_iibb: Double read FImp_iibb write FImp_iibb;
property Imp_perc_mun: Double read FImp_perc_mun write FImp_perc_mun;
property Imp_internos: Double read FImp_internos write FImp_internos;
property Imp_moneda_Id: WideString read FImp_moneda_Id write FImp_moneda_Id;
property Imp_moneda_ctz: Double read FImp_moneda_ctz write FImp_moneda_ctz;
property Fecha_cbte: WideString read FFecha_cbte write FFecha_cbte;
property Items: ArrayOfItem read FItems write FItems;
end;

// ************************************************************************ //
// Namespace : http://ar.gov.afip.dif.bfe/
// ************************************************************************ //
Item = class(TRemotable)
private
FPro_codigo_ncm: WideString;
FPro_codigo_sec: WideString;
FPro_ds: WideString;
FPro_qty: Double;
FPro_umed: Integer;
FPro_precio_uni: Double;
FImp_bonif: Double;
FImp_total: Double;
FIva_id: Smallint;
published
property Pro_codigo_ncm: WideString read FPro_codigo_ncm write FPro_codigo_ncm;
property Pro_codigo_sec: WideString read FPro_codigo_sec write FPro_codigo_sec;
property Pro_ds: WideString read FPro_ds write FPro_ds;
property Pro_qty: Double read FPro_qty write FPro_qty;
property Pro_umed: Integer read FPro_umed write FPro_umed;
property Pro_precio_uni: Double read FPro_precio_uni write FPro_precio_uni;
property Imp_bonif: Double read FImp_bonif write FImp_bonif;
property Imp_total: Double read FImp_total write FImp_total;
property Iva_id: Smallint read FIva_id write FIva_id;
end;

ArrayOfItem = array of Item; { "http://ar.gov.afip.dif.bfe/" }
Esto es parte de la unidad que me generó delphi al acceder al wsdl del WS, esto seria lo que yo deberia poder hacer.
procedure Tfrm_menu.Button3Click(Sender: TObject);
var
par4: ClsBFERequest;
par3: Item;
par: Arrayofitem;
begin
GetMem(par,10*SizeOf(ClsBFERequest));
par4.Items:=par;
//setlength(par,10);
///asi no funciona
par[0].Pro_codigo_ncm:='esto';
///si fuera asi tampoco funciona
par4.Items[0].Pro_codigo_ncm:='esto';
end;
El Error que me da es "Out of Memory" usando GetMem o Setlength y una excepcion en una direcc. de memoria si no se le asigna lugar a par.

Agradeceria cualquier ayuda de parte de la comunidad.

Lord Delfos
05-04-2010, 23:58:15
Hhmmmm... A ver.

Primero, a los arreglos dinámicos (los declarados como array of...) no se los puede usar con GetMem. Hay que inicializarlos con SetLength.

"par" en tu código es un ArrayOfItem, que es un "array of item". Así que la inicialización debe hacerse con SetLength.

Segundo, cuando hacés la asignación "par4.Items:= par"... "par4" no está inicializado, así que no va andar.

Ya que estamos, si lo que querés hacer, según entiendo viendo tu código, es clonar todos los elementos de "par" en "par4", lo mejor que podés hacer es un método en tu clase ClsBFERequest y dejar que él se encargue de la copia.


ClsBFERequest = class(TRemotable)
[...]
procedure CopiarItems(out Destino: ArrayOfItem);
[..]
end;

procedure ClsBFERequest.CopiarItems(out Destino: ArrayOfItem);
begin
Destino:= Copy(FItems, 0, Length(FItems));
end;



¿Se entiende?

Miguel Galarza
06-04-2010, 03:22:18
Gracias por contestar y tomarte el trabajo de tratar de entender esto, muy buena la explicacion, Lo de clonar me quedo claro, pero lo que necesito y no puedo hacer es
1) dar dimension a Items (que es un Arrayofitem)
el error es "incompatible Types.
2) Dar valor a cada elemento de item
setlength(BFERequest.items,9)
BFERequest.items[0].cada_uno_de_los_elementos_de_Item:=xxxxx

Intente esto otro, asignar valor a cada elemento de Item y luego asignar este al Arrayofitem
par3.Pro_codigo_ncm:=Valor_Pro_codigo_ncm;
[....]
par3.Iva_id:=Valor_'Iva_id;
par4.Items[0]:=par3 as TRemotable;
Pero el xml me queda asi de malo
<?xml version="1.0"?>
[......]
<Items xmlns="" xsi:type="NS3:Array" NS3:arrayType="NS1:Item[9]">
<item href="#5"/>
<item xsi:nil="true"/>
<item xsi:nil="true"/>
<item xsi:nil="true"/>
<item xsi:nil="true"/>
<item xsi:nil="true"/>
<item xsi:nil="true"/>
<item xsi:nil="true"/>
<item xsi:nil="true"/>
</Items>
</NS1:ClsBFERequest>
<NS1:Item id="5" xsi:type="NS1:Item">
<Pro_codigo_ncm xmlns="" xsi:type="NS2:string">87.16.40.00</Pro_codigo_ncm>
<Pro_codigo_sec xmlns="" xsi:type="NS2:string">47</Pro_codigo_sec>
<Pro_ds xmlns="" xsi:type="NS2:string">descripcion articulo</Pro_ds>
<Pro_qty xmlns="" xsi:type="NS2:double">1</Pro_qty>
<Pro_umed xmlns="" xsi:type="NS2:int">7</Pro_umed>
<Pro_precio_uni xmlns="" xsi:type="NS2:double">98751.13</Pro_precio_uni>
<Imp_bonif xmlns="" xsi:type="NS2:double">0</Imp_bonif>
<Imp_total xmlns="" xsi:type="NS2:double">109120</Imp_total>
<Iva_id xmlns="" xsi:type="NS2:short">10</Iva_id>
</NS1:Item>
</BFEAuthorize>


O sea que Items xmlns queda vacio y se agrega un nodo mal.
Gracias de nuevo!

Lord Delfos
06-04-2010, 04:27:38
Hmmm... Habría que ver cómo generás el XML, porque haciendo un SetLength(BFERequest.Fitems, 9) te da un arreglo de 0..8... Cómo uno le meta valores debería ser irrelevante, siempre y cuando sea en el rango 0..8.

Miguel Galarza
06-04-2010, 22:44:05
Esto es solo para cerrar y por si a algun despistado como yo le pasa algo parecido.
Aclaro que estas clases fueron generadas por wsdl importer de la paleta webservices, y solo se puede acceder a las propiedades publicadas.
El tema esta en el orden de la creacion de las clases.
para crearlas.
par3:=item.Create; //crear la clase item
setlength(par4,Fact.RecNo);//dimensionar Arrayofitem
par1 :=ClsBFEAuthRequest.Create;//crear BFEResponseAuthorize
par2:=ClsBFERequest.Create; //crear cslBFERequest
par2.Items:=par4;//igualar dimension de par2.Items que es un arrayofitem

Ahora la asignacion de valores que me traia problemas

par2.fecha_cbte:=formatDateTime('d/mm/yyyy',ValorCampo(fact,'fecha_cbte'));
fact.First;
while not fact.Eof do
begin
par3.Pro_precio_uni:=ValorCampo(fact,'Pro_precio_uni');
par3.Imp_bonif:=0;
[...]
par3.Imp_total:=ValorCampo(fact,'Imp_total');
par3.Iva_id:=ValorCampo(fact,'Iva_id');
par4[Fact.RecNo-1]:=par3 as TRemotable; //ponemos el valor del item en Arrayofitem
fact.Next;
end;
for i := 0 to Fact.RecNo-1 do
begin
par2.Items[Fact.RecNo-1]:=par4[Fact.RecNo-1];//asignamos cada arrayofitem a items de par2
end;
y listo ... gracias Lord siempre tan atento vos ... un abrazo