Mostrando entradas con la etiqueta Demos. Mostrar todas las entradas
Mostrando entradas con la etiqueta Demos. Mostrar todas las entradas

sábado, 4 de julio de 2009

Copia de seguridad remota


Hace más de un año comenté cómo planeaba y ejecutaba las copias de seguridad en el vServer.

Dije además que enviaba las copias de seguridad a otros servidores remotos para salvaguardar la información de una forma más efectiva, hoy veremos cómo.

Supongamos el caso más sencillo; un vServer y una sola aplicación.

Supongamos también que en el servidor hemos programado una sola tarea de copia de seguridad de la aplicación que cada día a la misma hora machaca la copia del día anterior.

Para acabar de definir el escenario necesitaremos otro vServer en otro lugar que llamaremos remoto, con un recurso compartido (nombre asignado a una carpeta física en disco) al que tiene acceso y control total el usuario SDV.

Ya lo tenemos todo.

Veamos cómo conseguir que nuestra copia de seguridad diaria se copie también en el equipo remoto.

Soy muy amigo de las tablas de configuración y suelo tener en cada aplicación una tabla CFG con un sólo registro conteniendo datos redundantes como la ip-pública del servidor donde publico la aplicación, alias que le pongo a la aplicación, nombre del usuario SDV, su contraseña, etc. Siempre viene bien poder tenerlos a mano dentro de algún proceso y así parametrizo el proceso usando los datos de CFG en vez de tenerlos declarados dentro del proceso. Es mejor cambiar datos de una tabla que editar el proceso si alguno de estos datos cambian.

Así pues declaro una tabla CFG con los siguientes campos: ip pública del servidor remoto, nombre del usuario sdv remoto, contraseña del usuario sdv, nombre del recurso compartido remoto (donde voy a guardar la copia de seguridad remota), y senda completa (senda, nombre y extensión) del archivo vcs que voy a mandar.

Si estos datos suelen ser siempre los mismos, incluso podemos ponerlos como contenido inicial de los campos, en el proceso ONINIT-MAP-SERVER cargamos la tabla CFG por el índice Código, vemos si no hay registros (if !n) y hacemos un Alta directa en la tabla CFG.

Si la tabla CFG es de un sólo registro, para su edición lanzamos un proceso que carga la tabla CFG por el índice Código, selecciona ficha por posición 1, lee la ficha seleccionada y añade como retorno el formulario de edición de la tabla.

Para capturar la senda completa del archivo vcs que voy a mandar uso un proceso como el siguiente:


El proceso con origen una ficha de la tabla CFG, presenta el diálogo para seleccionar un fichero, si aceptan el diálogo y han indicado una ruta, me la guardo ( fAjustaSenda convierte las barras \ en dobles barras \\ ).

Como vamos a enviar periódicamente información entre servidores preparo una tabla de ENVIOS. En esta tabla anotaremos los datos de cada envío; servidor remoto a donde se envía, usuario y contraseña que usamos para ello, fecha y hora del envío, y su resultado como booleano, así como la fecha y hora de finalización para controlar cuánto tardamos.

Ahora sólo queda hacer un proceso no-privado para poder programarlo como tarea en vServer.

En este proceso sin origen cargamos la tabla CFG para tomar los datos que necesitamos del registro 1; ip pública del servidor remoto, nombre del usuario sdv, su contraseña, carpeta remota donde hacer el envío, y de la senda del archivo a enviar nos quedamos con su nombre y extensión (fExtraerNombreExtDeSenda) que luego usaremos añadiéndole un prefijo.

A continuación en el proceso damos un Alta directa en la tabla ENVIOS, anotando en el Pre los datos necesarios, y quedándonos en el Post con el Código del registro de envío.

Preparo además una variable local fecha para guardar la Fecha del envío formateada AAMMDD para añadirla como prefijo al nombre y extensión del archivo que mandamos en el servidor remoto, así no machacaré las copias de seguridad del servidor remoto cada día, si no que las iré guardando todas, todas, todas, con su fecha en el nombre.

Sólo queda componer en el proceso la vrl-destino, es decir, en qué carpeta del servidor remoto vamos a guardar y con qué nombre la copia de seguridad, en qué servidor y con qué usuario y contraseña, mandarlo, y en función del resultado apuntarlo en la tabla ENVIOS.

Y eso es todo amigos.

Sólo queda programar como tarea en el servidor este proceso para que se ejecute cada día tras la copia de seguridad y ya está. Nuestros datos doblemente a buen resguardo.

Os propondría variaciones sobre el tema como tener varios registros en la tabla de configuración, es decir, distintos servidores a los que mandar la copia, o bien todos los días a todos, o cada día a uno, e incluso mandar copias de diferentes carpetas origen (lunes, martes, miércoles, etc...).

Usando una táctica similar se puede mandar también el mapa relativo a la copia de seguridad, archivos de configuración de vServer, etc.

Life is soft!

jueves, 31 de julio de 2008

Google & Velneo (ii)

Desarrollas aplicaciones web?

Usas bibliotecas javascript como jQuery, prototype, script.aculo.us, MooTools o dojo?

Si es así y no quieres perder la cabeza manteniendo las versiones usadas en todos tus proyectos, Google ha sacado un nuevo servicio en GoogleCode que sirve las últimas versiones de todas estas bibliotecas.

Sólo necesitas enlazar con ellas a través de tu APIkey y Google te las sirve, además comprimidas, de forma que su carga está optimizada, y tus páginas liberadas de un gran peso.

Aquí os dejo el enlace

http://code.google.com/apis/ajaxlibs/

Life is soft!!!

domingo, 20 de julio de 2008

Google & Velneo

Hace tiempo que no posteo nada, y es que estoy tan ocupado desarrollando soluciones de gestión empresariales y web con Velneo V6 que no tengo casi tiempo para más.

Esta noche he sacado un hueco y me gustaría comentar mis últimas experiencias de desarrollo en Velneo V6 integrando soluciones Google.


Está claro que Velneo V6 deja bastante que desear a nivel gráfico, informes, conectividad, etc, pero he descubierto que se lleva muy bien con Google para paliar esas deficiencias.

A nivel de informes, la herramienta que incorpora Velneo V6 es bastante limitada, pocos objetos y poco configurables. Desde hace tiempo intento inculcar en la comunidad el concepto de informes html en Velneo. Son informes xhtml+css lanzados desde la aplicación.

Este tipo de informes son al fin y al cabo como cualquier página web lanzada desde Velneo; un proceso accesible web, que como tal tiene acceso a todas las tablas de la aplicación para componer un informe sin limitaciones impuestas por el origen del proceso; ningún origen, cabecera, líneas, da igual, estamos en un proceso y podemos hacer lo que queramos.

En el proceso podemos cargar datos de una tabla, de otra, de muchas..., componemos el html resultante a base de componentes html, y el resultado se devuelve como Añadir retorno texto.

La maquetación corre a cargo del css que da forma al xhtml generado, y ya tenemos un informe (página html) que se previsualiza siempre y se puede imprimir a gusto del usuario.

Los informes nativos Velneo disponen de gráficos, rejillas de histórico, etc, para su composición, y a nivel de gráficos encontré muy gratificante el API de GoogleCharts.

Es un API gratuita, sólo hay que tener una cuenta Google, y se ataca de forma muy sencilla:

  1. Recopilas los datos a representar
  2. Los escalas y trasladas en función del número de datos y la codificación correspondiente
  3. Eliges el tipo de gráfico
  4. Rellenas datos accesorios; ejes, rótulos, títulos, tipos de punto, línea, etc
  5. Mandas la petición a GoogleCharts y te devuelve un png del gráfico solicitado
  6. Este png se inserta como img dentro del informe html y a correr

Una de mis ocupaciones anteriores consistía en desarrollar soluciones GIS personalizadas usando MapInfo. Es un entorno muy profesional y especializado que necesita de técnicos formados para su mantenimiento.

Hace años integré MapInfo con Velneo, pero era una solución muy cara a nivel de licencias de desarrollo. Investigando GoogleCode encontré el API de GoogleMaps y GoogleEarth, gratuítas igualmente, que permiten mandar un formato KML a Google, que no es más que un formato XML con los datos a representar gráficamente en el mapa, y recibes un formáto gráfico mapa de GoogleMaps o GoogleEarth interactivo que muestra tus datos en el mapa.

Su uso es tan sencillo como el de GoogleMaps y no son necesarios técnicos especialistas para su mantenimiento ya que representa automáticamente lo que hay en la base de datos y para ello sólo es necesario rellenar un formulario de alta o modificación.

Y es todo gratuíto mientras sea público.

Así surgió mi primer GIS con Velneo. GoogleMaps se encarga de representar los datos de Velneo en el mapa, y si lo quieres más espectacular le encargas la tarea a GoogleEarth.

A nivel de conectividad a la hora de compartir documentación, GoogleDocs nos permite generar documentos "Word", "Excel", "PowerPoint" en la nube y compartirlos con los usuarios autorizados.

Hay API's disponibles para todo ello en GoogleCode, fáciles de estudiar e implementar en Velneo y que dotan a nuestras aplicaciones de nuevas funcionalidades con un costo realmente bajo: GRATIS.

Así sigo ampliando las capacidades de la herramienta de desarrollo que elegí hace años, Velneo, de la cual aún no he encontrado el techo (esto no lo puedo hacer), y sigo dando años de vida a soluciones V6, utilizado código abierto y gratuíto, en este caso el de Google.

Life is soft!!!

miércoles, 28 de mayo de 2008

vTiger

Siempre se ha dicho que Velneo peca de una interfaz de usuario muy pobre y puede que sea así.

Disponemos de pocas posibilidades a la hora de hacer un interfaz vistoso, con muchos efectos y colores, pero si nos esmeramos usando esas pocas posibilidades podemos obtener algo bastante al gusto del usuario.

Cuando miro ahora alguna de mis primeras aplicaciones me parecen francamente horribles, en cuanto al interfaz de usuario al menos; fuentes poco acertadas, colores demasiado llamativos, disposición de elementos poco pensada, etc, en definitiva, una mala experiencia para el usuario.

El interfaz y la usuabilidad de las aplicaciones es un tema muy importante, y más ahora que viene la V7 multiplataforma y vamos a poder entrar en el mercado de usuarios acostumbrados a otro aspecto para sus aplicaciones; linux, mac, etc.

Si nos lo proponemos, con una cuidadosa preparación y unos pocos elementos podemos ir adaptando el aspecto de nuestras aplicaciones hacia ese nuevo mercado que se nos abre.

El siguiente ejemplo es un formulario V6 hecho a partir de una captura de pantalla del OSX-Tiger, tratado con mucho mimo con Photoshop para que no pese, y ejecutado con la V6 en un Windows 2000 Professional.


Usa los colores básicos del OSX-Tiger, fuentes similares, botones al estilo Mac y disposición de elementos similar al OSX-Tiger, para no despistar al usuario Mac.

Así que, aunque no podemos hacerlo todo, sí que podemos hacer bastantes cosas para que el usuario tenga una experiencia agradable y no se encuentre perdido en nuestras aplicaciones Velneo.

Life is Soft!!!

sábado, 3 de mayo de 2008

Errores en Velneo

Contrariamente a lo que puede sugerir el título de esta entrada del blog, no voy a denunciar un error o bug de Velneo como entorno de desarrollo, voy a exponer un error de programación en el que ya he caído más de una vez, así a vosotros os servirá de experiencia y a mí de recordatorio para no volver a repetirlo.

Un Cargar Lista por un índice de tipo Palabras o Trozos de palabras, resolviendo el índice por alguna de sus partes no funciona.

No es que no funcione, es que parte el motor.

Life is soft!

viernes, 4 de abril de 2008

Fechas en Velneo

Muchas veces, por ejemplo al realizar una agenda donde apuntar eventos por día, me he encontrado en Velneo con la siguiente duda:

Pero para eso necesito tener todos los días de todos los años generados?

Afortunadamente en la mayoría de ocasiones la respuesta ha sido NO.


No es necesaria una tabla maestra Años y una submaestra Días para una agenda.

Lo que suelo hacer es generar al vuelo, en una tabla en memoria los registros que necesito mostrar como calendario. Es como las famosas tablas "Dummy" de Fran, pero para fechas.

Dicha tabla en principio sólo necesita un campo Código autonumérico y un campo Fecha. En ella daremos de alta por proceso las fechas compredidas en el intervalo fecha_desde - fecha_hasta necesarias para la visualización del periodo de la agenda deseado.

Adicionalmente podemos disponer diversos campos fórmula alfabética que nos muestren cada fecha ya formateada según las necesidades.

Veamos algunas posibilidades de fecha formateada en Velneo.

Supongamos una fecha; 2-01-2008

Utilizando la función fFormatFecha(fecha, szFormato) donde fecha es el campo o variable fecha que vamos a transformar y szFormato es la subcadena de formato que vamos a aplicar a esa fecha para darle la forma deseada, podemos obtener una enorme diversidad de formas para la fecha.

Disponemos de los siguientes formateadores:

&d -> Visualiza el día del mes con uno o dos dígitos, según corresponda (1 - 31)

En nuestro caso sería: 2


&e -> Visualiza el día del mes siempre con dos dígitos (01 - 31)

En nuestro caso sería: 02


&L -> Visualiza, en Español, el día de la semana en texto; Lunes, Martes, ...

En nuestro caso sería: Miércoles


&A -> Visualiza, en Inglés, el día de la semana en texto; Monday, Tuesday, ...

En nuestro caso sería: Wednesday


&l -> (L minúscula). Visualiza, en Español, el día de la semana abreviado a tres letras; Lun, Mar, ...

En nuestro caso sería: Mie


&a -> Visualiza, en Inglés, el día de la semana abreviado a tres letras; Mon, Tue, ...

En nuestro caso sería: Wed


&m -> Visualiza el número del mes con uno o dos dígitos, según corresponda (1 - 12)

En nuestro caso sería: 1


&n -> Visualiza el número del mes siempre con dos dígitos (01 - 12)

En nuestro caso sería: 01


&K -> Visualiza, en Español, el mes en texto; Enero, Febrero, ...

En nuestro caso sería: Enero


&B -> Visualiza, en Inglés, el mes en texto; January, February, ...

En nuestro caso sería: January


&k -> Visualiza, en Español, el mes en texto abreviado a tres letras; Ene, Feb, ...

En nuestro caso sería: Ene


&b -> Visualiza, en Inglés, el mes en texto abreviado a tres letras; Jan, Feb, ...

En nuestro caso sería: Jan


&j -> Visualiza el día del año de un campo fecha (1 - 366)

En nuestro caso sería: 2


&u -> Visualiza el día de la semana en número dentro del rango 1 a 7 siendo 1=Lunes

En nuestro caso sería: 3


&w -> Visualiza el número del día de la semana dentro del rango 0 a 6 siendo 0=Domingo

En nuestro caso sería: 3


&W -> Visualiza el número de la semana del año dentro del rango 0 a 51

En nuestro caso sería: 1


&U -> Visualiza el número de la semana del año dentro del rango 1 a 52

En nuestro caso sería: 1


&x -> Formatea la fecha en la forma que el sistema esté configurado

En mi caso sería: miércoles, 02 de enero de 2008


&Y -> Visualiza el año con todos sus dígitos

En nuestro caso sería: 2008


&y -> Visualiza el año sin siglo con uno o dos dígitos, según corresponda

En nuestro caso sería: 8


&z -> Visualiza el año sin siglo siempre con dos dígitos

En nuestro caso sería: 08


Todos estos formateadores también están disponibles al seleccionar un campo fecha en el editor de fórmulas, dentro del apartado Subcadena de formato (opcional) - Opciones.

Al ser una subcadena, los formateadores admiten cualquier símbolo que podamos teclear dentro de la cadena.

Así, por ejemplo, podríamos mostrar nuestra fecha 2-01-2008 como 08/01/02, Wed. usando la función siguiente

fFormatFecha(2/01/2008, "&z/&n/&e, &a.")

Fácil, como todo en Velneo.


Ahora veamos algunas combinaciones de funciones que nos facilitarán mucho la vida a la hora de trabajar con fechas.


En qué semana del año me encuentro?

fFormatFecha( fHoy(), "&U")


En qué día del año me encuentro?

fFormatFecha( fHoy(), "&j")


Qué día de la semana es el primer día del mes actual?

fFormatFecha( fFecha( 1 ), "&L")


Y el último día del mes que viene?

fFormatFecha( fFecha( fDiasDelMes( fMes( fHoy() ) + 1, fAño( fHoy() ) ), fMes( fHoy() ) + 1 ), "&L")


Y así podríamos seguir complicándolo o simplificándolo, depende de cómo se mire, tanto como deseemos o necesitemos.

Espero que esto ayude a resolver algunas dudas al respecto de las fechas en Velneo.

Life is Soft!

martes, 11 de marzo de 2008

Copias de seguridad


En las aplicaciones Velneo que instalo en clientes siempre monto un sistema de copias de seguridad programado en el vServer de la siguiente forma.

Creo una carpeta CopiaSeguridad, a poder ser en un disco físico diferente de aquel donde reside la aplicación (una segunda unidad, una unidad mapeada, etc). Si no puede ser en otro disco, la creo en un directorio diferente al de la aplicación.

Dentro de esa carpeta creo esta serie de subcarpetas; 01-lunes, 02-martes, 03-miercoles, 04-jueves, 05-viernes, 06-sabado y 07-domingo. Le pongo ese nombre a las carpetas para que salgan ordenadas alfabéticamente por día de la semana.

Creo una serie de tareas programadas en el servidor para que semanalmente se realice una copia de seguridad en la carpeta correspondiente; una para los lunes en la carpeta 01-lunes, otra los martes en la carpeta 02-martes, etc.

Como hora de la copia elijo un horario libre de carga y enganches en el servidor, normalmente al finalizar la jornada laboral o por la noche.

Así planteado, el lunes por la noche se realiza copia de seguridad de los datos de la aplicación en la carpeta 01-lunes, el martes en la 02-martes, etc, de forma que si las cosas fuesen muy mal, y nadie se diese cuenta, podría tirar hasta de siete copias de seguridad con un día de diferencia entre cada una de ellas, es decir tengo un colchón de una semana de datos.

Como la copia que realiza vServer es sólo de datos (vcs) hay que ingeniarse un sistema para junto con los datos guardar también la versión del mapa, por si hay que restaurar y se ha modificado el código, así como los ficheros de variables y configuración por ser estrictos.

Adicionalmente, como Velneo nos da esa facilidad, en instalaciones críticas añado la funcionalidad de envío de la copia de seguridad a un servidor remoto mediante SDV, así dispongo de esas copias en otro servidor Velneo por si ocurre alguna hecatombe como que casquen todos los discos duros a la vez, se quemen en un incendio todos los ordenadores o algún informático avezado restaure el sistema a una fecha tres meses anterior.

Life is Soft!

martes, 26 de febrero de 2008

Integridad de la bd Velneo

Hace tiempo me ocurrió una cosa curiosa a la vez que catastrófica para una de mis bases de datos Velneo:

Tenía una tabla maestra de Apartados y tenía otra tabla maestra Fichas. En Fichas tenía un puntero a maestro apuntando a Apartados para así poder indicar a qué apartado pertenecía una ficha.

El caso es que por las prisas, el descuido y la desorganización de la edición en grupo de un mapa, la tabla Apartados se quedó sin el histórico de Fichas.

Como estamos tan acostumbrados a la robustez de Velneo manteniendo la integridad de la bd, ni corto ni perezoso un día me dio por cambiar los códigos del maestro de Apartados para reorganización interna, y cuál fue mi sorpresa al ver que había perdido la relación entre Fichas y Apartados.

Me quedé con unas 3.000 fichas sin apartado, y no había vuelta atrás.

Afortunadamente no ocurrió nada ya que tiré de la copia de seguridad de datos diaria y restauré la bd a su estado de por la mañana, perdiendo básicamente la desafortunada modificación de códigos de Apartados.

Al sufrir este susto investigué en el mapa el porqué de la falta de integridad de datos y lo arreglé.

Y es que Velneo es una herramienta que hace lo que debe de hacer; mantener la integridad de datos siempre y cuando en los desarrollos mantengamos unas mínimas reglas de coherencia para establecer esta integridad.

Veamos los pasos necesarios para que en un caso similar no perdamos datos.


En el esquema de tablas vemos cómo en la tabla Fichas tenemos:

- un puntero a maestro apuntando a Apartados


- tenemos además el índice Apartado que es acepta repetidas sobre el puntero a Apartados


- y en la tabla Apartados tenemos declarado el histórico de Fichas sobre el índice Apartado anterior.


Así las cosas Velneo siempre va a mantener la integridad de datos de nuestras bd; si cambiamos el código del maestro de Apartados, cada registro de Fichas apuntará al nuevo código de Apartado gracias a la relación histórica entre ambas tablas a partir del índice Apartado.

Si alguna vez perdéis datos o relaciones entre tablas revisad los punteros a maestro, los índices correspondientes a estos punteros, y lo más importante, la existencia en los maestros del histórico necesario.

Velneo es rápido, robusto, eficaz..., pero no es mágico.

Life is soft!!

P.D.: Esto sólo es necesario cuando trabajamos con tablas maestras con puntero a maestro, si utilizásemos una relación maestro-submaestro Velneo ya hace el trabajo por nosotros creando los índices e históricos necesarios.

miércoles, 16 de enero de 2008

Modelo de cajas CSS

Lo primero que se debería aprender de CSS, y suele no ser así (yo el primero), es el modelo de cajas que utiliza.

El modelo de la caja del CSS describe las cajas rectangulares que se generan para los elementos en el árbol del documento y se presentan según el modelo visual del formato.

Y esto qué quiere decir?

Cada elemento de html; una capa, un párrafo, una lista, una cabecera, etc..., tiene a su alrededor una caja que lo contiene.

Los elementos componentes de esa caja son

Modelo de caja
  • El contenido en sí
  • El relleno (padding)
  • El borde (border)
  • El margen (margin)

Las partes de cada uno de estos elementos se referencian por su posición respecto del contenido y en este orden: arriba (top), derecha (right), abajo (bottom) e izquierda (left).

Este orden es fácil de aprender; se empieza por arriba y se recorre en sentido horario.

Así un elemento de la caja como por ejemplo el margen tendrá cuatro partes: margin-top, margin-right, margin-bottom y margin-left.

Es bueno recordar esto ya que más adelante veremos cómo nos va a permitir definir las propiedades de cada parte de cada elemento en el CSS.

La dimensión de la caja viene dada por la suma de las dimensiones de todos estos elementos, es decir,

ancho-caja = margen-izquierdo + borde-izquierdo + relleno-izquierdo + ancho-contenido + relleno-derecho + borde-derecho + margen-derecho

y esto es así.

Otra cosa es lo que IE hace. Y es que el famoso navegador calcula el ancho a su manera sin respetar el estándard.

Así que si vuestra web se ve bien en navegadores que siguen el estándard como Opera, Safari, Firefox, pero no se ve bien en IE: cambiad de navegador.

Es impresionante la cantidad de consultas en foros sobre el tema que aún están enfocadas al revés: "Mi web se ve perfectamente en IE, pero cuál ha sido mi sorpresa al ver que se descuadra en Firefox!"

La respuesta a este tipo de dudas es: "Si haces las cosas bien tu web se verá perfecta en todos los navegadores que siguen el estándard. IE no respeta el estándard así que si los usuarios de IE no ven bien una web tienen dos opciones; quejarse amargamente de ello a Microsoft, o cambiar de navegador"

Es conveniente saber que cada navegador implementa unos valores predeterminados para los diferentes elementos de cada caja, así que si no los definimos en CSS se tomarán esos por defecto.

Otro tema que entronca directamente con el modelo de caja es el árbol del documento.

Html es un lenguaje de etiquetas, y estas etiquetas en cada página están anidadas de cierta forma. Esta anidación de etiquetas conforma una estructura en árbol jerárquica, de forma que constituye lo que se llama el árbol del documento.

Arbol de documento
En el esquema vemos que una etiqueta puede tener un antecesor, unos descendientes, unos hermanos y compañeros del mismo nivel.

Esto hemos de tenerlo muy en cuenta ya que CSS es un lenguaje de definición de estilos en cascada, es decir las propiedades de los elementos son heredables según el árbol del documento, de forma que si definimos por ejemplo el estilo de letra para el body, todos los elementos descendientes del body heredarán ese estilo.

Si en principio nos quedan claros estos pocos conceptos base sobre cajas, árboles y herencia, ya tendremos mucho avanzado a la hora de entender CSS.

Life is soft!

viernes, 11 de enero de 2008

Diseño web (tablas)

Antiguamente, cuando empecé con el diseño de páginas web, había una escuela de programadores venidos a "diseñadores" web que utilizaban ámpliamente las tablas html para la maquetación visual de los elementos de las páginas; una tabla para centrar la página en el navegador, una tabla para el menú, otra tabla para distribuir los elementos de cada página, etc.

Era una forma fácil de poder hacer que lo que apareciese en los navegadores se asemejara más o menos al diseño gráfico pensado para la web.

Yo también era de esos, planteaba un diseño en Photoshop que luego troceaba y pasaba a Dreamweaver para maquetarlo usando una enorme cantidad de tablas anidadas, lo cual al final ralentizaba la presentación del sitio en los navegadores dada la compleja estructura de tablas anidadas resultantes.

Otro problema subyacente era la accesibilidad. Alguien invidente que utilizase un lector para interpretar esa web fácilmente podía no entender nada de una compleja estructura de tablas que nada tenía que ver con el contenido "real" del sitio web.

Durante un largo periodo de tiempo dedicado a investigar la forma de hacer las cosas en la web me encontré con una escuela de diseñadores web que intentaba separar la forma del contenido, lo cual me interesó mucho por dedicarme básicamente a realizar webs dinámicas donde el contenido está en la base de datos y la forma se encuentra en componentes html que son el front-end para ese medio. Me interesó muchísimo y me puse a estudiarlo.

Así conocí el xhtml + css. Era la nueva web semántica; separación de forma y contenido, la forma se controla mediante css y en el código xhtml no se incluye ninguna etiqueta que tenga que ver con la forma.

Las fuentes y sus tamaños, los colores y fondos, la disposición de elementos, etc, se controla desde css, y el contenido se deja para el código xhtml.

Así las cosas parecía que las tablas eran un elemento a no utilizar en xhtml, pero no es así. Hay elementos claramente tabulares que deben ser mostrados en tablas, que para eso fueron creadas. Así un listado tabulado de información se mostrará utilizando una tabla, un calendario también, y toda aquella información cuya naturaleza sea tabular requerirá de este elemento para ser mostrada.

Las tablas en xhtml no deben ser un tema tabú.


Veamos cómo es una tabla bien formada y accesible.

[table summary="Listado de Repartidores de señal indicando el servicio asociado, las extensiones y pares, así como el elemento D.Hard utilizado"]
[thead]
[tr class="odd"]
[th scope="col" abbr="Repartidor"]Repartidor[/th]
[th scope="col" abbr="Servicio"]Servicio[/th]
[th scope="col" abbr="Extensiones"]Ext.[/th]
[th scope="col" abbr="Pares"]Par[/th]
[th scope="col" abbr="D.Hard"]D.Hard[/th]
[/tr]
[/thead]
[tbody]
[tr]
[td]Ayto. Nuevo - S.S. Yecla[/td]
[td]Jubilados[/td]
[td]2.740[/td]
[td]01[/td]
[td]2.013, 2, 3[/td]
[/tr]
[tr class="odd"]
[td]Parque móvil - Cámaras Becalí[/td]
[td]Bomberos Norte[/td]
[td]4.984[/td]
[td]60[/td]
[td]2.013, 10, 9[/td]
[/tr]
[/tbody]
[/table]

En principio observamos que la tabla tiene un summary que es una descripción de los datos que muestra la tabla. Esto hace que la tabla sea más comprensible.

Debajo del summary podría ir el caption que es el título de la tabla, de forma similar al título de un gráfico de Excel, por ejemplo, para que todos nos entendamos. Este caption también es fácilmente controlable desde css para su aspecto y posición.

Luego pasamos a definir el thead de la tabla que es el grupo de celdas de la tabla que actuarán como cabeceras de columna, como los nombres de columna A, B, C, en una hoja Excel por seguir con la analogía anterior.

En el thead vemos que cada columna cabecera la definimos con th en lugar de td. Esto es así porque esas columnas van a actuar como cabecera de columna y le darán sentido a todos sus td's inferiores.

A continuación del thead podríamos definir de forma similar el tfoot que sería el conjunto de celdas que formarán el pie de la tabla; nota al pie, totalizadores por columna, etc.

Luego viene el tbody, es decir, la "chicha". Aquí es donde van los datos, y se sabe exactamente a qué tipo de dato corresponde cada celda porque lo hemos definido con anterioridad en cada th del thead.

Así un lector de pantalla para invidentes podría leer esa tabla de forma que tenga sentido para el usuario final, y un usuario cualquiera podrá acceder a todas esas propiedades de la tabla desde las opciones de su navegador.

Vemos que no hemos utilizado ninguna etiqueta de presentación dentro de la tabla; ni fuentes, ni colores, ni fondos, ni bordes, ni espaciados de celdas o contenido, ni nada de eso a que, al menos yo, estaba tan acostumbrado. Eso es tarea del css y lo veremos en un próximo artículo.

Hay más elementos que podríamos utilizar dentro de la definición de una tabla que no he comentado, pero para una completa colección de los mismos y su descripción os recomiendo verlos en w3c.

Desde aquí os animo a abandonar viejas malas costumbres para pasar a utilizar tablas bien formadas y definidas, más accesibles en definitiva.

Life is soft!!

jueves, 3 de enero de 2008

Funciones remotas

Las funciones remotas son esas grandes desconocidas de Velneo, funciones normales y corrientes pero que tienen marcado el check accesible VRPC.

Este hecho permite que sean ejecutadas de forma remota desde otros servidores Velneo invocándolas con un simple

Set -> fr,fEjecutarFuncionRemota( servidor-remoto, alias-aplicacion, funcion-remota, pwd-fr, parametro1, parametro2, ... )

donde

  • servidor-remoto es la ip-pública o nombre del servidor remoto donde se va a ejecutar la función remota
  • alias-aplicación es el alias con el cual está publicada la aplicación que contiene la función remota que se va a ejecutar en el servidor remoto
  • funcion-remota es el nombre de la función accesible VRPC a ejecutar
  • pwd-fr es la contraseña de funciones remotas definida en el servidor remoto para la aplicación correspondiente
  • parametro1, parametro2, ... son los diferentes parámetros que puede recibir la función remota separados por comas

Algo tan simple y sencillo como esto dota a nuestras aplicaciones Velneo de una potencia inusitada, permitiéndonos actualización de datos online desde sitios remotos, replicación de servidores en caliente, consolidación de datos de sucursales en una central en tiempo real, o el uso que realmente se nos ocurra.

Una función remota siempre se va a ejecutar en un servidor Velneo, pero su invocación puede ser desde una aplicación publicada en otro servidor Velneo o desde una aplicación cliente ejecutandose en monopuesto, así un portátil trabajando en local en el coche de un comercial puede comunicar al servidor Velneo de la central las ventas que está realizando, siempre que disponga de conexión a internet, y podría incluso bajarse a local las variaciones de tarifa que
necesitase.

Una función remota, como cualquier otra función en Velneo tiene un retorno. Ese retorno puede ser un simple 1 si se ha ejecutado, un parámetro resultado de un cálculo o extracción de la base de datos, o una ristra de parámetros separados por punto y coma por ejemplo para tener como respuesta un registro entero de una tabla de la base de datos.

Si la función remota no tiene definido un retorno explícito la variable local utilizada para su invocación contendrá un 1 en caso de haberse ejecutado y un 0 en caso contrario.

Un par de cosas a tener en cuenta: el alias-aplicacion y funcion-remota en mayúsculas tanto en su definición como en su invocación, y así nos evitamos problemas.

Condiciones a cumplir con las funciones remotas:

  1. Una función remota entre servidores distintos que vaya a transaccionar, debe transaccionar ella misma.
  2. Una función remota contra el propio servidor que la invoca que vaya a transaccionar, no debe transaccionar ella misma.

Aquí alguien se puede preguntar; una función remota contra el propio servidor?!! Pues sí. En entornos de desarrollo, para probar una aplicación que ejecuta funciones remotas contra un servidor, si sólo dispones de un servidor para pruebas deberás ejecutar las funciones remotas contra el propio servidor, y en entornos de producción reales yo me he encontrado varios casos donde la ejecución de una función remota contra el propio servidor me ha solucionado más de un problema; enlace gestión-contabilidad, mantenimiento unificado de tablas maestras, etc.

En estos casos hay que evitar que la función remota transaccione sacando la parte del proceso que transacciona a funciones que son llamadas desde la propia función remota.

Hasta aquí hemos visto superficialmente las funciones remotas, su uso y su potencial que vemos que es tremendamente esperanzador ya que nos permite hacer prácticamente todo lo que nos podamos imaginar entre dos aplicaciones Velneo.

Ahora la pega; dos servidores Velneo no pueden ejecutar funciones remotas simultáneas entre ellos, es decir, el servidor 1 no puede lanzar una función remota contra el servidor 2 y a su vez el servidor 2 sobre el servidor 1.

Puede parecer un caso raro y que no vaya a darse nunca, pero en la práctica se da, muy a nuestro pesar. La realidad supera con creces cualquier ficción.

Qué debemos hacer en este caso? Establecer un semáforo, una variable booleana global en disco que condicione la ejecución de las funciones remotas para evitar el "fuego cruzado" entre servidores.

En caso contrario nos encontraremos con dos servidores Velneo bloqueados hasta que uno de ellos se venga abajo. Al tirar abajo uno de los servidores, el otro se recupera y continúa su ejecución como si no hubiese pasado nada.

Como no existe una función específica para acceder al estado del semáforo propio de Velneo al ejecutar funciones remotas, debemos crear y gestionar el nuestro propio. Para acceder al estado del semáforo del servidor remoto lo más sencillo es diseñar un protocolo TCP que informe al otro servidor del estado del semáforo de funciones remotas.

Si la ejecución de la función remota consistiese en la simple petición de un parámetro al otro servidor, como ya tenemos un protocolo TCP establecido entre ambos servidores para la gestión del semáforo, podríamos utilizar el propio protocolo para la transmisión de ese parámetro entre servidores y ahorrarnos la función remota, y el posible problema del "fuego cruzado".

Life is soft!!!

domingo, 11 de noviembre de 2007

Maestro de mí mismo

Con la inestimable colaboración del maestro Agustín:

Todos hemos usado los punteros a maestro y los punteros a histórico para relacionar al menos dos tablas entre sí.

También en algún momento nos puede surgir la necesidad de tener un histórico con registros que pertenecen a la misma tabla.

Veamos estas dos situaciones reales:

  1. En una aplicación tenemos la tabla ARTICULOS . Hay registros de esta tabla que tienen un histórico también formado por otros artículos. Un ejemplo podría ser el artículo vajilla, formado a su vez por artículos platos llanos, platos hondos
  2. En una sociedad, tenemos una tabla de SOCIOS. Los socios menores de edad dependen de sus tutores a la hora, por ejemplo, de emitir los recibos de cuota social. Hay socios que dependen de otros socios.

Para solventar esta problemática desde la parte izquierda del vDeveloper, podemos acudir a la potencia de los punteros a maestro, de los índices, de los enlaces a histórico y de las actualizaciones.

Analizando el primer caso planteado, artículos formados por otros artículos, tendremos una tabla maestra ARTICULOS.


En dicha tabla hemos incluido, además del capo Nombre, el campo PR-COSTE-CALC, que utilizaremos para mediante actualizaciones acumular el coste del artículo como suma de los costes de sus componentes, el campo PRECIO-COSTES, cuyo contenido inicial es el campo PR-COSTE-CALC por si se quiere modificar el precio de coste y no se quiere usar el calculado, y COMPONENTES que nos servirá para saber el número de componentes que tiene el artículo.

Además incluimos un campo puntero a maestro ARTICULOS–MAESTRO que apunta a la misma tablas de ARTICULOS y que nos servirá para indicar si dicho artículo pertenece a otra ficha de artículo, es decir, si es escandallo de otro artículo pero sin dejar de ser un artículo en sí mismo.

Veamos el campo puntero a maestro ARTICULOS-MAESTRO.


  • Está enlazado a la tabla maestra ARTICULOS y no tiene contenido inicial.
  • Este es el campo que nos indica si un artículo forma parte del escandallo de otro artículo.

Ahora creamos el índice que nos permitirá ordenar dentro de una ficha de artículo, sus componentes.


Este índice lo llamamos Componentes de, y está formado por los campos ARTICULOS-MAESTRO, que es el puntero a la misma tabla, y su campo CODIGO, para que los ordene, dentro de un mismo ARTICULO por su orden de inclusión en el histórico.

Sólo nos queda, crear el enlace a histórico desde la misma tabla de ARTICULOS y utilizar el puntero para las actualizaciones.


El primer componente de la actualización aumenta en 1 cada vez que hacemos que un artículo sea componente de otro, el segundo componente nos calcula el PR-COSTE-CALC, para acumular el precio de coste total.



Forma rápida, sencilla y potente, usando sólo elementos de la estructura y sin tener que hacer ni un proceso, de controlar de forma básica un escandallo.

Life is soft!

sábado, 27 de octubre de 2007

vAccessForm

Hace poco surgió en el foro de Velneo una cuestión: "Cómo puedo poner en un formulario de edición de fichas los típicos botones de Access para ir a la primera y última ficha?"

Al principio me extrañó ya que en Velneo hay una y mil formas más eficaces de navegar por los registros de una tabla que con los botoncitos de Access.

En Velneo puede haber muchos primeros o últimos o anteriores o posteriores; por qué índices quieres que calcule el anterior?, la anterior factura del mismo cliente?, la siguiente factura más cara?, la anterior por fecha? o la siguiente por el segundo apellido del cliente?.

Pero luego me dije, y por qué no?, aunque sea por puro divertimento Velneano vamos a hacerlo.

Empecé a garabatear las diferentes posibilidades; por proceso, por puntero singular de plural, por puntero a hermano...

Defensor como soy de lo simple decidí que no debía ser por proceso y que la solución debería estar integrada en la parte de la bd. Lo comenté con Agustín e hicimos las primeras pruebas pero ocurrió lo de siempre, procesos...

Publicamos dos soluciones no óptimas en el foro y la maestría, buen hacer, serenidad y sencillez de Paco vino a despejar el campo.

En unos 2,5 segundos había pillado la idea, el mapa, lo modificó, lo dejó funcionando y lo dejó de vuelta en el foro, acompañado de unas sabias palabras:

La respuesta no esta 'ahí afuera', la respuesta está en los índices

Sé que me puedo poner pesado pero no me voy a cansar de repetirlo una y otra vez; estructura, relaciones, índices, triggers, ahí está la solución a todos nuestros problemas. Si hay algo que no haces ahí pregúntate por qué?; no sabes hacerlo? o no se te había ocurrido? o no puedes realmente?

Siempre que se pueda hacer en las tablas, ahí se debe hacer. Así independizas la funcionalidad de la apariencia.

No soy amigo de los procesos en formularios. No me gustan los procesos en pérdida o ganancia de foco, prefiero no usar procesos a la apertura o creación de un formulario, o procesos previos al aceptar, para hacer según qué cosas.

Cuando los uso tiendo a pensar que o mi estructura de bd no es óptima o no he exprimido a fondo la parte de definición de la bd.

Después del rollo filosófico vamos al grano y veamos cómo hacer una relación puntero a hermano que desde cualquier registro de una tabla nos lleve al primero o al último.

Lo primero es la estructura de la tabla.


Vemos que es una tabla cualquiera con los punteros a hermano anterior y siguiente que te crea Velneo cuando le dices Campos - Crear puntero a hermano,


tenemos un campo Extremo que es un booleano que dice si el registro es un extremo de la tabla, con contenido inicial a Sí,

y un proceso Anterior a un alta de ficha que fija el contenido de Extremo a Sí sólo para los extremos reales.


Además tenemos dos campos puntero a hermano más; Primero y Último.

Vemos que los punteros Primero y Último usan para su resolución el índice Extremo, y ese es el fundamento de toda esta historia; el índice.

Cómo es ese índice Extremo?

Es un índice acepta repetidas sobre el campo Código condicionado a que el booleano Extremo sea Sí.

Qué hace este índice? Como al dar de alta un registro el trigger vuelve a fijar los extremos sólo a Sí, la condición de indexación de este índice hace que cualquier registro de la tabla sólo tenga un hermano anterior extremo y sólo uno posterior extremo, así la resolución del puntero a hermano anterior y posterior por este índice nos lleva de forma directa al primer y último registro de la tabla respectívamente.


Simple y sencillo como Velneo.

Life is Soft!

miércoles, 12 de septiembre de 2007

Buscador web

Una de las herramientas imprescindibles hoy en día en cualquier web es un buscador sobre los contenidos de la propia web, algo así como un Google pero restringido a los contenidos de nuestra propia web.


Para ello vamos a necesitar varias cosas:

  1. Un gestor de contenidos de nuestra web, es decir, que el contenido de la web se extraiga de tablas. Si por ejemplo nuestra web es el catálogo de productos de nuestra empresa, lo primero es tener en bd la estructura de fichas de productos.
  2. Una variable global accesible web, llamémosla $TXT-BUSQUEDA$, que contendrá el texto a buscar en los contenidos.
  3. Un formulario web para que el usuario introduzca la cadena a buscar.
  4. Uno o varios índices sobre la tabla de productos para realizar la búsqueda por trozos de palabras, todas las palabras o por alguna de las palabras.
  5. La búsqueda en sí.
  6. Un proceso accesible web que reciba la variable global $TXT-BUSQUEDA$, lance la búsqueda y muestre el html de los resultados.

Vayamos por partes.

El gestor de contenidos de nuestra web lo vamos a reducir a una tabla PRODUCTOS. En esta tabla vamos a tener los siguientes campos: Nombre, Referencia y Descripción, por ejemplo, que son los campos sobre los que haremos que actúe el buscador.


Nombre es el campo Nombre que nos crea Velneo por defecto al crear una tabla nueva junto con sus índices Nombre, Palabras y Trozos. Podemos observar cómo están configurados estos índices para tomarlos como referencia a la hora de montar nuestros propios índices.

Referencia es un campo donde introduciremos un código formado tanto por letras como por números, es decir, la referencia del artículo.

Descripción será un campo alfabético de 500 caracteres de longitud, por ejemplo, donde introduciremos una descripción mucho más amplia sobre el producto en cuestión.

Como vamos a querer buscar sobre los tres campos anteriores a la vez, necesitamos un campo que aglutine el contenido de los tres. Así podemos crear un campo TXT-BUSQUEDA Alfa 40 de longitud 500, lo que nos da un total de 750 caracteres, con contenido inicial la concatenación de los tres campos anteriores en cuestión; "" + %NOMBRE% + " " + %REFERENCIA% + " " + %DESCRIPCION%

Ahora necesitamos, por hacerlo fácil, dos índices: uno para buscar por palabras y otro para buscar por trozos de palabras, es decir, por aproximación alfabética ternaria (pones un mínimo de tres letras y la búsqueda ya responde).

Para ello crearemos un nuevo índice PALABRAS-TEXTO-BUSQUEDA, por ejemplo, que será del tipo Palabras sobre el campo TXT-BUSQUEDA.

El segundo índice será TROZOS-TEXTO-BUSQUEDA, del tipo Aproximación alfabética ternaria sobre el mismo campo TXT-BUSQUEDA.

Con esto ya tenemos la estructura de bd necesaria para poder realizar la búsqueda.

Veamos ahora la búsqueda.


Crearemos un nuevo objeto búsqueda que llamaremos BUSCADOR. Esta búsqueda la vamos a configurar en principio para realizar una búsqueda por palabras, así incluiremos en la misma los índices CODIGO con Modo de búsqueda Todo el fichero, y como segundo índice el PALABRAS-TEXTO-BUSQUEDA en Modo Mezcla Cruzar.

Si como segundo índice de la búsqueda incluimos TROZOS-TEXTO-BUSQUEDA en Modo Mezcla Cruzar habremos configurado la búsqueda para que responda por ternas de caracteres.


En cualquiera de los dos casos, debemos indicar como contenido inicial del segundo índice en la búsqueda el contenido de la variable global $TXT-BUSQUEDA$.

Hago aquí un inciso para comentar las dos posibilidades que tenemos al utilizar el índice por Palabras en la búsqueda.

Si os fijáis a la hora de especificar el segundo índice de la búsqueda tenemos dos posibilidades: Todas las palabras o Alguna de las palabras. Qué quiere decir esto?

Si usamos Todas las palabras, estaremos haciendo una búsqueda tipo "Y"; que aparezca la palabra1 y la palabra2 y la palabra3.


Si en cambio usamos Alguna de las palabras, estaremos haciendo una búsqueda tipo "O"; que aparezca la palabra1 o la palabra2 o la palabra3.


Aclarado esto sigamos con nuestro buscador.


Ahora lo que vamos a necesitar es un formulario web con un campo donde el usuario introduzca la cadena de texto a buscar, y de valor a la variable global $TXT-BUSQUEDA$, y un botón BUSCAR.

Eso es algo tan simple como:

<form action="PROCESA-BUSQUEDA.PRO" method="post" name="busqueda" id="busqueda">
<input name="TXT-BUSQUEDA" id="TXT-BUSQUEDA" size="25" maxlength="150" type="text">
<input value="BUSCAR" type="submit">
<form>


Hay que fijarse en que el campo del formulario donde el usuario escribe la cadena a buscar se llama igual que la variable global $TXT-BUSQUEDA$ que va a contener esa cadena.

Otro detalle es que el botón submit del formulario no tiene nombre.

El action del formulario es el proceso PROCESA-BUSQUEDA.PRO


Este es el proceso accesible web que recibirá dentro de la variable global $TXT-BUSQUEDA$ la cadena a buscar. Dentro del proceso lo único que hemos de hacer es lanzar la búsqueda BUSCADOR, que directamente ya nos devuelve una lista de la tabla PRODUCTOS, donde se habrá encontrado la cadena $TXT-BUSQUEDA$ en alguno de los campos %NOMBRE%, %REFERENCIA% o %DESCRIPCION%.

El cómo mostrar los resultados de la búsqueda ya es cuestión de un componente html perteneciente a la tabla PRODUCTOS, que haciendo uso de las repeticiones <AVPR> muestre la lista de productos encontrados, algo como

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Resultado búsqueda</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body>
<p>Resultado de la búsqueda</p>
<p>Se han encontrado #AVPn Productos con #AVP'cadena-a-buscar'</p>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>NOMBRE</td>
<td>REFERENCIA</td>
<td>DESCRIPCION</td>
</tr>
<AVPR>
<tr>
<td>#AVP%NOMBRE%</td>
<td>#AVP%REFERENCIA%</td>
<td>#AVP%DESCRIPCION%</td>
</tr>
</AVPR>
</table>
</body>
</html>

En este ejemplo hemos visto cómo montar un buscador por palabras lo más sencillo posible.

Como ya hemos adelantado antes, esto se podría complicar más incluyendo campos en el formulario para que el usuario pudiese configurar la búsqueda para que actuase por Trozos de palabras, por Palabras y en modo "Y" u "O", habiendo incluido ambos índices en la búsqueda y condicionandolos en consecuencia, pero esto ya lo veremos otro día.

Life is soft!

viernes, 15 de septiembre de 2006

El D.N.I. y Velneo

Leyendo un día microsiervos encontré en la sección de leyendas urbanas un post sobre el DNI. Trataba sobre la leyenda que decía que el número que aparece en la parte de atrás del DNI es el número de personas que se llaman igual que tú. Siguiendo los enlaces encontré la página de Josep Portella Florit donde explicaba el proceso que siguió hasta descifrar la parte de atrás del DNI.

Decidí en ese momento hacer la adaptación a Velneo del proceso y generar una web de coña que generase tu parte de atrás del DNI.

Veamos cómo es esa parte de atrás, algo parecido a esto:

IDESP12345678Z3***************
7410150M0903226ESP***********4
DE*TAL*Y*CUAL**FULANITO*******

Y qué es esto? Por campos,

[ID][ESP][12345678Z][3][***************]
[741015][0][M][090322][6][ESP][***********][4]
[DE*TAL*Y*CUAL][**][FULANITO][*******]

[ID] - Campo que indica el tipo de documento
[ESP] - Campo que indica que el documento es de España
[12345678Z] - Campo con el DNI letra incluida
[3] - Dígito de control del DNI letra incluida
[***************] - Relleno
[741015] - Fecha de nacimiento en formato AAMMDD
[0] - Dígito de control de la fecha de nacimiento
[M] - Sexo
[090322] - Fecha de caducidad del DNI
[6] - Dígito de control de la fecha de caducidad
[ESP] - Campo que indica que el documento es de España
[***********] - Relleno
[4] - Dígito de control de la cadena formada por el DNI letra incluida, su dígito de control, la fecha de nacimiento, su dígito de control, la fecha de caducidad y su dígito de control
[DE*TAL*Y*CUAL] - Apellidos
[**] - Separador
[FULANITO] - Nombre
[*******] - Relleno

Para el cálculo de los rellenos debemos tener en cuenta que la longitud de cada línea es de 30 caracteres.

El cálculo del dígito de control se reduce a tomar una cadena de longitud variable ( DNI, fecha, churro ), separarla caracter por caracter, sustituir los caracteres alfabéticos por su valor numérico según la fórmula (valorASCII - 65), de forma que la A sea 0, la M 12 y la Z 25, y luego aplicar los pesos 7-3-1 a los caracteres de la cadena, obtener la suma total y quedarnos con el último dígito de la suma.

Por pasos, tomando por ejemplo el DNI [12345678Z]

separamos por caracteres [ 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - Z ]

sustituimos la letra [ 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 25 ]

aplicamos los pesos 7-3-1 [ 1*7 - 2*3 - 3*1 - 4*7 - 5*3 - 6*1 - 7*7 - 8*3 - 25*1 ]

sumamos [ 7 + 6 + 3 + 28 + 15 + 6 + 49 + 24 + 25 ] = 163

nos quedamos con el último dígito [3]

y ya tenemos nuestro dígito de control. Así con todos.

La duda que me queda es el tema del sexo. No interviene en el cálculo de ningún dígito de control pero sufre una transformación que creo es M = Hombre, F = Mujer, aunque en el campo del DNI dedicado al sexo pone otra cosa. No sé si tendrá algo que ver también la comunidad autónoma o no.

Ah! Se me olvidaba comentarlo, al componer la última línea debereis tener en cuenta que si en el Nombre o Apellidos aparecen espacios, estos deberán ser sustituidos por [*]