FoxPro/Visual FoxPro - Grabar en entorno de red

 
Vista:
sin imagen de perfil
Val: 31
Ha disminuido su posición en 2 puestos en FoxPro/Visual FoxPro (en relación al último mes)
Gráfica de FoxPro/Visual FoxPro

Grabar en entorno de red

Publicado por ANTONIO (29 intervenciones) el 02/03/2018 00:28:41
Buenas amigos ya estoy loco con un tema.
Estoy haciendo un pequeño programa para clínicas y en mono usuario funciona bien hasta ahora todo lo que tengo terminado.
Tengo las tablas compartidas con shared in 0, y en un principio casi todo me funcionaba bien, salvo a la hora de probar con los presupuestos y facturas que es un mismo modulo donde según sea uno u otro abre la tabla presu como cabeza y presupuesto como detalle o factu como cabeza y facturas como detalle.

Una vez puestos en antecedentes les paso el código que tengo puesto una vez realizado la captura de datos en unos cursores me dispongo a grabar la información y a sumar uno al contador en la tabla empresas.

Los pasos que sigo son:
- guardar el nº en una variable
- sumar 1 al contador
- guardar lo creado o modificado

Si lo abro en dos sitios a la vez y genero el proceso a la vez en dos no va bien.

Espero que me puedan ayudar.

Desde ya Muchas gracias.

Antonio Z.




*********** Nº DE FACTURAS Y PRESUPUESTOS ********
&&numfac guardará el nº de presupuesto o factura por el que vamos
DO CASE
CASE donde = 1 .and. thisform.quehago = "alta"
_numfac = empresas.npre
CASE donde = 1 .and. thisform.quehago <> "alta"
_numfac = cabeza.nfra
CASE donde = 2 .and. thisform.quehago = "alta"
_numfac = empresas.nfra
CASE donde = 2 .and. thisform.quehago <> "alta"
_numfac = cabeza.nfra
ENDCASE

****************************************************
IF thisform.quehago = "alta"
SELECT empresas
RLOCK()
IF donde = 1
replace npre WITH ALLTRIM(STR(VAL(empresas.npre)+1))
ELSE
replace nfra WITH ALLTRIM(STR(VAL(empresas.nfra)+1))
ENDIF
UNLOCK IN empresas
ENDIF
**************************************************

SELECT cabeza && presu o factu según sea....
RLOCK()
IF thisform.quehago = "alta"
APPEND BLANK
endif
replace nfra WITH _numfac
replace codigocli WITH thisform.txtcliente.Value
replace fecha WITH thisform.txtfecha.Value
replace totalfra WITH thisform.desglose.page1.text6.value
replace base WITH thisform.desglose.page1.text4.value
replace iva WITH thisform.desglose.page1.text5.value
UNLOCK

IF thisform.quehago <> "alta" && propiedad para saber si es alta o modificación
SELECT detalle
RLOCK()
DELETE FOR nfra = cabeza.nfra .and. YEAR(fecha) = year(cabeza.fecha)
UNLOCK
ENDIF

SELECT facturas2 && en este cursor esta todo el contenido ya sea creado o modificado (detalle)
GOTO TOP
numc = 1
DO WHILE !RLOCK()
ENDDO
DO WHILE !EOF()
SELECT detalle
RLOCK()
APPEND BLANK
replace nc WITH numc
replace fecha WITH facturas2.fecha
replace nfra WITH _numfac
replace codigocli WITH thisform.txtcliente.Value

replace concepto WITH facturas2.concepto
replace cantidad WITH facturas2.cantidad
replace precio_u WITH facturas2.precio_u
replace base WITH facturas2.base
replace dto WITH facturas2.dto
replace iva WITH facturas2.iva
replace total WITH facturas2.total
UNLOCK
SELECT facturas2
SKIP
numc = numc +1
ENDDO
SELECT facturas2
GOTO TOP
thisform.mostrar && carga la información y la muestra en pantalla
thisform.grlistado.refresh
thisform.grlistado.SetFocus
thisform.txtquehace.Visible = .F.
thisform.shaQuehace.Visible = .F.
thisform.quehago = ""
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
sin imagen de perfil
Val: 31
Ha disminuido su posición en 2 puestos en FoxPro/Visual FoxPro (en relación al último mes)
Gráfica de FoxPro/Visual FoxPro

Grabar en entorno de red

Publicado por ANTONIO (29 intervenciones) el 02/03/2018 11:32:18
Me voy respondiendo yo solo, aunque todavía no he encontrado la solución.

Si ejecuto el formulario 2 veces desde dentro de foxpro funciona correctamente, si lo hago desde el ejecutable no.

Parece que se queda en memoria el nº de fra/pres y no pasa al siguiente, aunque mirando la tabla desde fuera ya se ha actualizado.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 1.011
Oro
Ha mantenido su posición en FoxPro/Visual FoxPro (en relación al último mes)
Gráfica de FoxPro/Visual FoxPro

Grabar en entorno de red

Publicado por Fidel José (657 intervenciones) el 02/03/2018 13:48:30
No mencionas que es lo que sale mal. De todos modos, hay algunos cambios que conviene realizar en el código.
1) Evitar el uso de APPEND BLANK reemplazándolo por INSERT INTO
2) Cuidar mejor el bloqueo manual. Por ejemplo, para un proceso DELETE FOR o DELETE ALL, el bloqueo de registro (RLOCK) no funciona. Necesariamente se debe bloquear la tabla, por lo que es mejor reemplazarlo por un código que use bloqueo de registros.
3) SCAN / ENDSCAN resulta más eficiente que DO WHILE !EOF() en la mayoría de los casos. El ENDSCAN repone el area de trabajo inicial por lo que no es necesario volver a seleccionar el area.
4) Los llamados a métodos deben hacerse con los paréntesis [ Thisform.Mostrar() ]
5) La propiedad QueHago, debería llenarse con una sola letra: "A","B","M". La baja no está contemplada en el proceso.

Sugiero intentar con este código, que no es óptimo pero es un poco mejor.
Pero no intento sugerir algo mejor porque no tengo en vista el desarrollo.

Acá no lo hice, pero se puede evitar la doble consulta del valor de la propiedad QueHago, si se trabaja ordenadamente.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
IF thisform.quehago = "alta"
	INSERT INTO cabeza ;
		(Nfra,;
		Codigocli,;
		Fecha,;
		Totalfra,;
		Base,;
		Iva);
	VALUES ;
		(_numfac,;
		thisform.txtcliente.Value,;
		thisform.txtfecha.Value,;
		thisform.desglose.page1.text6.value,;
		thisform.desglose.page1.text4.value,;
		thisform.desglose.page1.text5.value)
         UNLOCK IN CABEZA
ELSE
	SELECT cabeza
	IF RLOCK()
		replace nfra WITH _numfac,;
			codigocli WITH thisform.txtcliente.Value ,;
			fecha WITH thisform.txtfecha.Value,;
			totalfra WITH thisform.desglose.page1.text6.value,;
			base WITH thisform.desglose.page1.text4.value,;
			iva WITH thisform.desglose.page1.text5.value
 
 
		UNLOCK
	ENDIF
ENDIF
 
IF thisform.quehago <> "alta"
       * genera una array con los números de registro (recno() ) que hay que borrar.
	SELECT RECNO() as ph_rec ;
		FROM detalle ;
		WHERE nfra = cabeza.nfra AND YEAR(fecha) = year(cabeza.fecha) ;
		INTO ARRAY laRecord
	lnTally = _tally
 
	SELECT detalle
	FOR i = 1 TO m.lnTally
		GO laRecord[i,1]
		IF RLOCK()
			DELETE
			UNLOCK
		ENDIF
	NEXT
ENDIF
 
numc = 1
SELECT facturas2
SCAN
	INSERT INTO detalle ;
		(Nc,;
		Fecha,;
		Nfra,;
		Codigocli,;
		Concepto,;
		Cantidad,;
		Precio_u,;
		Base,;
		Dto,;
		Iva,;
		Total);
	VALUES ;
		(numc,;
		facturas2.fecha,;
		_numfac,;
		thisform.txtcliente.Value,;
		facturas2.concepto,;
		facturas2.cantidad,;
		facturas2.precio_u,;
		facturas2.base,;
		facturas2.dto,;
		facturas2.iva,;
		facturas2.total)
 
	numc = numc + 1
ENDSCAN
UNLOCK IN detalle
FLUSH    && muy importante, sobre todo en ambiente de red
 
SELECT facturas2
GOTO TOP
thisform.mostrar() && supongo que es un método del form
 
thisform.txtquehace.Visible = .F.
thisform.shaQuehace.Visible = .F.
thisform.quehago = ""
thisform.grlistado.refresh
thisform.grlistado.SetFocus()
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 31
Ha disminuido su posición en 2 puestos en FoxPro/Visual FoxPro (en relación al último mes)
Gráfica de FoxPro/Visual FoxPro

Grabar en entorno de red

Publicado por ANTONIO (29 intervenciones) el 02/03/2018 14:39:50
Fidel como siempre estas ahí para poder responder muchas gracias. Hay ciertas cosas que todavía no domino, pues trabajo mas en local que en red y despues todo hay q hacerlo rápido y cuando no se puede.

Muchas gracias, voy a ir mirando y te comento.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 31
Ha disminuido su posición en 2 puestos en FoxPro/Visual FoxPro (en relación al último mes)
Gráfica de FoxPro/Visual FoxPro

Grabar en entorno de red

Publicado por ANTONIO (29 intervenciones) el 03/03/2018 02:46:07
Buenas madrugadas aquí Fidel.

Para empezar es cierto que el código se puede optimizar mejor y de echo lo estoy empezando a hacer después de que tu me lo dijeras, pues no hay como otro para que te diga como puedes mejorar. Gracias por eso.

He creado esta madrugada un pequeño ejemplo del problema que tengo para no complicar mucho he creado el formulario con dos de las tablas que trabajo simplificadas a lo mínimo para que el ejemplo sea sencillo pero intentar coger la base.

Si ejecutas el programa y le das a guardar presupuesto veras que va añadiendo registros al prespuesto como si de ellos fuesen y que en la tabla empresas se va cambiando el nº. Hasta ahí todo bien.
El problema esta si se ejecuta dos veces el programa y se va guardando presupuestos en uno o en la otra instancia es cuando empiezan a fallar los números se solapan y lo cierto es que ya no se por donde seguir aquí.

Como verás he empezado a utilizar los comandos para guardar de sql en fox (a ver si me acostumbro y cambio todo el programa y puedo psar poco a poco las dbf a otro formato mas estable).

Si pudieses echarle un vistazo te estaría tremendamente agradecido pues esto me para mucho para terminar ciertas cosas que las tengo ya casí listas.

Gracias de antemano.
Un abrazo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 1.011
Oro
Ha mantenido su posición en FoxPro/Visual FoxPro (en relación al último mes)
Gráfica de FoxPro/Visual FoxPro

Grabar en entorno de red

Publicado por Fidel José (657 intervenciones) el 03/03/2018 13:07:06
Antonio:
Los comandos INSERT SQL o UPDATE SQL no emplean bloqueo manual.
1) INSERT SQL crea un registro nuevo y por lo tanto no se debe bloquear un registro, porque dicho registro no existe. Al igual que cualquier comando que agregue registros a una tabla dbf, bloquea la cabecera de la tabla, por lo que es bueno usar UNLOCK después de INSERT INTO, cuando se trabaja con bloqueo manual.

2) En el caso de UPDATE SQL o DELETE SQL, lo recomendable es trabajar con Buffering, no con bloqueo manual (RLOCK(), FLOCK())
Ejemplito:
1
2
3
4
5
6
lSuccess=CURSORSETPROP("Buffering", 5, PR)
IF lSuccess
	INSERT INTO pr (npre);
	VALUES (x)
	TABLEUPDATE( 1, .T., PR ) && ver los parámetros que se necesitan en cada caso
ENDIF

El bloqueo con buffering tiene una ventaja sobre el manual (aún cuando es más trabajoso por la necesidad de establecer el CURSORSETPROP() para cada tabla de destino). Puedes grabar todos los cambios y si no hubo error, hacer los TABLEUPDATE() correspondiente o utilizar TABLEREVERT() para deshacer los cambios.
TABLEREVERT( [lAllRows [, cTableAlias | nWorkArea] ] )

3) Los numeradores de documentos (facturas, presupuestos, pagos, etc) no deben tomarse como el último número de una tabla + 1, porque esto te puede generar repeticiones en la medida en que haya procesos concomitantes. La mejor estrategia, sobre todo con dbf, es tener una tabla de numeradores.
En este link tenés un ejemplo que puede ser mejorado o adaptado a tus necesidades.
https://comunidadvfp.blogspot.com/2005/03/numeros-consecutivos-para-nuestras.html
En mi caso, en lugar de nombres de tablas, yo utilizo un código (ID) de comprobante, lo que no cambia mucho la cosa.

En resumen
Para utilizar bloqueo manual [ RLOCK(), FLOCK(), UNLOCK ] debes tener claro el significado del bloqueo:
RLOCK() bloquea el registro actual de la tabla seleccionada (o al menos, lo intenta). Si alguien en la red bloqueo el registro, ese registro será de solo lectura para los demás usuarios hasta que se produzca un desbloqueo (UNLOCK o la ejecución de un comando que provoca un desbloqueo automático).
FLOCK() bloquea completamente la tabla por lo que los demás usuarios no pueden agregar ni modificar registros hasta que se desbloquee la tabla.
Los comandos que agregan registros y otros comandos como COPY TO, bloquean la cabecera de la tabla, por lo que nadie puede agregar registros hasta que se desbloquea (en el caso de COPY TO cuando termina la ejecución se desbloquea). Por este motivo hay que evitar utilizar comandos como COPY TO, SUM, COUNT, etc, sobre tablas compartidas, reemplazandolos por sus equivalentes en SELECT SQL.

Los comandos REPLACE y DELETE necesitan que el registro sobre el que operan esté bloqueado o la tabla abierta en modo exclusivo.
Conviene escribir un solo comando REPLACE por registro con las instrucciones CampoX With ValorX separadas por coma, porque cada comando REPLACE debe verificar el estado de bloqueo, lo cual lo hace muy lento.

Por último:
En todos los procesos de grabacíón de datos, es totalmente recomendable utilizar el control de errores TRY/CATCH/FINALLY/ENDTRY

Te dejo algunos links imprescindibles del blog del gran Fernando D. Bozzo
https://fdbozzo.blogspot.com.ar/2014/01/desmitificando-el-control-de-errores.html
https://fdbozzo.blogspot.com.ar/2014/06/la-importancia-de-un-buen-nombre-para.html
https://fdbozzo.blogspot.com.ar/2014/09/vfp-guia-de-buenas-practicas-de.html
https://fdbozzo.blogspot.com.ar/2015/05/tecnicas-de-optimizacion-en-vfp-tablas.html
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 31
Ha disminuido su posición en 2 puestos en FoxPro/Visual FoxPro (en relación al último mes)
Gráfica de FoxPro/Visual FoxPro

Grabar en entorno de red

Publicado por ANTONIO (29 intervenciones) el 03/03/2018 13:20:47
Muchas gracias. Llevo 3 horas pegado al pc esperandote por si podias responder. Muchas gracias.

Voy a probar y documentarme algo mas, pues como te he dicho para mi ahora mismo es indispensable para terminar ciertos proyectos, pero estoy a tope en otras cosas y no puedo dedicarle todo el tiempo que quisiera al programa pero debo de hacerlo.

Te comento algo según vaya probando.

Por cierto, mi correo es [email protected], me gustaría poder contar contigo para algunas cosas si tengo dudas y gratificarte si así lo pides pues es tu trabajo.

De nuevo Gracias.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 31
Ha disminuido su posición en 2 puestos en FoxPro/Visual FoxPro (en relación al último mes)
Gráfica de FoxPro/Visual FoxPro

Grabar en entorno de red

Publicado por ANTONIO (29 intervenciones) el 04/03/2018 20:12:24
Por fin pude terminar (de momento) con el código que me distes el tema de la numeración que de momento se va a quedar tal cual viene en los ejemplos.
Va perfecto, ahora solo hace falta estudiar un poco mas de código, todas las indicaciones que me has dado me vendrán bien en un futuro y poco a poco iré mejorando mi código a uno algo mas legible.

Me quiero introducir en el mundo de Mysql o Firdbird para almecenamiento de datos que supongo que dará menos problemas que las dbf normales.

Quería saber tu consejo en cual me aconsejarías de las dos, para en un futuro poder tener las tablas en un formato que se puedan visualizar desde aplicaciones realizadas para web.

Muchas gracias Fidel por tus consejos.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 1.011
Oro
Ha mantenido su posición en FoxPro/Visual FoxPro (en relación al último mes)
Gráfica de FoxPro/Visual FoxPro

Grabar en entorno de red

Publicado por Fidel José (657 intervenciones) el 05/03/2018 14:14:26
Antonio
Lamentablemente no tengo experiencia con sistemas de bases de datos. Por lo que tengo visto, si tuviera que elegir me inclinaria por FireBird o por MariaDb.
Lo que hay que tener en cuenta, es que es necesario interpretar cabalmente la lógica cliente - servidor y programar para ello.
Y lo que resulta realmente muy recomendable, es entrenarse hasta el cansancio con sentencias SQL. En lo básico el lenguaje SQL es bastante compatible, por lo que resulta mucho más sencillo hacer el entrenamiento general con tablas dbf. Es necesario aprender diseño de tablas porque la eficacia y eficiencia del sistema dependerá absolutamente de eso. En las dbf se pueden disimular las deficiencias de diseño porque trabjás con tablas abiertas y tenés recursos que pueden operar más eficientemente que SQL. Pero todo eso no existe en el mundo del administrador de base de datos, donde todo se reduce a cuatro comandos: INSERT, DELETE, UPDATE Y SELECT. Claro que también estan los STORE PROCEDURE, pero no es el principio, sino la mejor manera de gestionar datos que en cada caso se adopta.

No obstante, la programación estructurada que es la base de visual fox, debe tratar de optimizarse, porque lo único que cambia radicalmente es la gestión de datos y no el resto (negocio e interfaz). Por ello recomiendo enfáticamente leer las recomendaciones de los maestros, entre ellos, Fernando D. Bozzo que tiene una gran claridad expositiva.
Al plantear cualquier sistema, se deben resolver tres problemas:
1) Almacenamiento de datos (diseño tablas y relaciones)
2) Las operaciones que se necesitan hacer con esos datos
3) Cómo se mostrará y se permitirá la interacción del usuario para producir las operaciones (negocio).

En los sistemas xbase nos hemos acostumbrado ha programar una mezcolanza de todo, pero es hora de repensar el tema. La ingeniería de separación de capas no debe ponernos los pelos de punta. Debe ser lo necesario y no una chinche.
Ejemplo de mezocolanza es este código;
1
2
3
4
5
6
replace nfra WITH _numfac,;
 		codigocli WITH thisform.txtcliente.Value ,;
			fecha WITH thisform.txtfecha.Value,;
			totalfra WITH thisform.desglose.page1.text6.value,;
			base WITH thisform.desglose.page1.text4.value,;
			iva WITH thisform.desglose.page1.text5.value
En lugar de eso, se podrían utilizar los ControlSource de los objetos y un objeto contenedor de datos (que puede ser un cursor o un objecto "empty" con una propiedad para cada control que se muestra al usuario liados por ControlSource.
Ejemplo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
*Creación del objeto empty (Init del Formulario)
ADDPROPERTY(thisform,"poGuia",NEWOBJECT("Empty"))
ADDPROPERTY(this.poGuia,"codigocli",0)
ADDPROPERTY(this.poGuia,"fecha",{})
ADDPROPERTY(this.poGuia,"TOTALFRA",0)
ADDPROPERTY(this.poGuia,"base",0)
ADDPROPERTY(this.poGuia,"iva",0)
 
*Asiganación de ControlSource (Init del Formulario)
WITH this
	.txtcliente.ControlSource = "thisform.poguia.codigoCli"
	.txtFecha.ControlSource = "thisform.poGuia.fecha"
	.desglose.page1.text6.ControlSource = "Thisform.poGuia.totalfra"
	.desglose.page1.text4.ControlSource = "Thisform.poGuia.base"
	.desglose.page1.text5.ControlSource = "Thisform.poGuia.Iva"
ENDWITH
 
* Nuevo Código de replace (Método Guardar del Formulario)
replace nfra WITH _numfac,;
	codigocli this.poGuia.codigoCli ,;
	fecha WITH this.poguia.fecha,;
	totalfra WITH this.poGuia.totalfra,;
	base WITH this.poguia.base,;
	iva WITH this.poguia.Iva
Esto, a muchos les parece una caracoleada para llegar al mismo fin. Sin embargo tiene algunas ventajas que, a mi modo de ver, son definitorias.
1) Independiza el manejo de datos temporales de la interfaz. Si la interfaz tiene que cambiar, solo se necesita cambiar el ControlSource del objeto y todo lo demás funcionará como antes.
2) A la hora de insertar los datos en tablas resultará mucho más eficiente porque concentra todo en un único objeto incorpóreo (no visual) de fácil acceso.
3) El objeto es claramente exportable a una clase o procedure de prg con solo pasarlo como parámetro y permite que los datos sean tratados en otro lado, sin tener que pasar la referencia al form o romper la encapsulación. Esto parece algo traido de los pelos, pero es así solamete para la programación "spaghetti".
4) Mirás el código e instantáneamente sabés lo que estás haciendo, sin tener que recorrer todo el form para ver que cosa es este Text1 del page tal, del pageframe tal.

Por último, cuando más intensivo sea el uso de la programación orientada a objetos, más fácil te resultará abordar otros lenguajes de programación, aún cuando la sintaxis sea completamente diferente.

Sobre la utilización de objetos "Empty", es muy bueno entender el funcionamiento de SCATTER NAME y GATHER NAME.
Por ejemplo, la rutina que sigue devuelve un objeto con los datos de un registro de una tabla o el valor null si no encuentra lo que se busca. Utiliza varias UDF por lo que no puedes hacer ningún ejercicio con eso, excepto tratar de descubrir la lógica. La rutina trata de encontrar el dato buscado primero por índices (INDEXSEEK()) y si no hay índices defnidos para el campo buscado, lo intentará por SELECT SQL.
Fijate que se utiliza SYS(2015) para obtener un nombre único de cursores, con lo que se evita cualquier colisión con nombres de cursores o tablas en uso.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
PROCEDURE Get_Record
*----------------------
*!*	Propósito		Devuelve un objeto "EMPTY" con los datos del registro
*!*					de una tabla, a la que se accede como AGAIN ALIAS (lcAlias_table)
*!* Parameters
*!*	tcTable:		Tabla original
*!*	tcField:		Campo clave
*!*	tcSearchValue:	Valor que se busca en el campo clave
*!*	RETURN:			El objeto con los datos del cursor, o null si no encuentra
*!* ------------------------------------------------------------------------------
*!* sample			loRet = get_Record("PROVEDOR","CUIT",m.lcCuit)
*!*					IF VARTYPE(loRet) = "O"
*!*						? loRet.Nombre
*!*						? loRet.Cuit
*!*						? loRet.Idprov
*!*					ENDIF
*!* ------------------------------------------------------------------------------
*!*	Rutinas llamadas
*!*	GetFolder()			Obtiene la ubicación de la tabla
*!*	NetUse()			Abre una tabla dbf
*!*	TelEtiqueta()		Devuelve la etiqueta de un índice que corresponde a un campo
*!*	CloseList()			Cierra las tablas o cursores de la lista
*!*	ShowError()			Muestra el error producido
*!* ------------------------------------------------------------------------------
LPARAMETERS tcTable,tcField,tcSearchValue
TRY
	LOCAL lcAlias_Selected,;
		lcAlias_Table,;
		lcCursor,;
		lcFolder,;
		lcIndi,;
		lcWhere,;
		loEx AS Exception,;
		loObj AS Object
 
 
	lcCursor = "gtr"+SYS(2015)
	lcAlias_table = "ali"+SYS(2015)
	lcWhere = ""
	lcAlias_Selected = ALIAS()
	lcType = VARTYPE(m.tcSearchValue)
	loObj = null
 
	DO WHILE .t.
		lcFolder = GetFolder(m.tcTable)
		IF EMPTY(m.lcFolder) OR EMPTY(m.tcSearchValue)
			EXIT
		ENDIF
		IF !Netuse(ADDBS(m.lcFolder)+m.tcTable,.f.,,m.lcAlias_Table,.t.,.t.)
			EXIT
		ENDIF
 
 
		lcIndi = telEtiqueta(m.lcAlias_Table,m.tcField)
		IF NOT EMPTY(m.lcIndi)
			IF INDEXSEEK(m.tcSearchValue,.f.,m.lcAlias_Table,m.lcIndi)
				loObj = NEWOBJECT("Empty")
				SELECT (m.lcAlias_table)
				INDEXSEEK(m.tcSearchValue,.T.,m.lcAlias_Table,m.lcIndi)
				SCATTER MEMO NAME loObj
				ADDPROPERTY(loObj,"Ph_rec",RECNO(m.lcAlias_Table))
			ENDIF
 
		ELSE
			DO CASE
				CASE VARTYPE(m.tcSearchValue) = "C"
 
					TEXT TO lcWhere TEXTMERGE NOSHOW PRETEXT 15
						ALLTRIM(<<tcField>>) == "<<tcSearchValue>>"
					ENDTEXT
				CASE VARTYPE(m.tcSearchValue) = "D"
					TEXT TO lcWhere TEXTMERGE NOSHOW PRETEXT 15
						<<tcField>> = CTOD("<<tcSearchValue>>")
					ENDTEXT
				CASE VARTYPE(m.tcSearchValue) = "T"
					TEXT TO lcWhere TEXTMERGE NOSHOW PRETEXT 15
						<<tcField>> = CTOT("<<tcSearchValue>>")
					ENDTEXT
				OTHERWISE
					TEXT TO lcWhere TEXTMERGE NOSHOW PRETEXT 15
						<<tcField>> = <<tcSearchValue>>
					ENDTEXT
 
			ENDCASE
 
			SELECT *,RECNO() as ph_rec ;
				FROM (m.lcAlias_table) ;
				WHERE &lcWhere ;
				INTO CURSOR (m.lcCursor)
			IF _tally > 0
				loObj = NEWOBJECT("Empty")
				SELECT (m.lcCursor)
				GO top
				SCATTER MEMO NAME loObj
				ADDPROPERTY(loObj,"Ph_rec",EVALUATE(m.lcCursor+".ph_rec"))
			ENDIF
 
		ENDIF
 
		EXIT
	ENDDO
CATCH TO loex
	loex.UserValue=PROGRAM()+CHR(13)+lcWhere
	ShowError(loex)
FINALLY
	CloseList(m.lcAlias_Table+CHR(44);
		+ m.lcCursor)
 
	IF NOT EMPTY(m.lcAlias_Selected)
		SELECT (m.lcAlias_Selected)
	ENDIF
ENDTRY
 
RETURN loObj
 
ENDPROC
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 31
Ha disminuido su posición en 2 puestos en FoxPro/Visual FoxPro (en relación al último mes)
Gráfica de FoxPro/Visual FoxPro

Grabar en entorno de red

Publicado por ANTONIO (29 intervenciones) el 05/03/2018 14:59:07
Como siempre gracias, iré practicando poco a poco como me comentas e iré haciendo pruebas cuando tenga tiempo pues tengo otra serie de cosas entre manos, pero esto no lo quiero dejar.

Un abrazo en la distancia.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar