Factura, líneas de facturas, artículo

17/11/2006 - 16:03 por Bingen | Informe spam
Hola a todos:

Mi pregunta es la siguiente, la verdad que podría colgarse en cualquier otro
lenguaje pero...

tenemos una clase Factura que agrupa líneas de factura. Estas líneas de
factura tienen una cantidad y una relación con un artículo.

Mi duda es la siguiente, si la línea la relacionamos con un artículo (nos da
la información de descripción de artículo, código artículo precio), es decir
tenemos una propiedad en la clase línea que es un objeto artículo, nuestro
sistema está obligado a no dejarnos borrar artículos ¿verdad?, porque si no,
todas las líneas de facturas que contengan dicho articulo, quedan inutiles ¿
no?.

¿ Que filosofia empleais vosotros ?

otra cosa, algún sitio de discusiones de UML (o preguntas similiares...)

Un saludo, y gracias por vuestro tiempo !!!

Bix

Preguntas similare

Leer las respuestas

#16 Alfredo Novoa
23/11/2006 - 19:03 | Informe spam
On Thu, 23 Nov 2006 14:10:23 -0300, "Daniel Ruzo"
wrote:

Sí, para segurar la integridad lo mejor son los SGBD. Pero los datos se
registran, se recuperan, se presenten (muestran), se procesan para obtener
otros datos, etc., etc.



Para obtener nuevos datos lo mejor son los SGBD.

Tengo una clase que crea el objeto "transacción". Este objeto tiene un
método "leer" que se encarga de leer el cabezal de la transacción y todas
sus lineas.



¿Y por que no la muestras directamente el resultado de la consulta?

Es mejor usar una clase que sirva para cualquier consulta en lugar de
tener que crear una clase para cada consulta.

Los datasets tipados no me gustan demasiado, pero por lo menos se
crean automáticamente.

Con una simple invocación a este método cargo toda la
transacción en el objeto. También existe un método "calcularTotal" que suma
los importes de las lineas de la transacción y devuelve el total.



Esto es una mala práctica. El total se debe de traer ya calculado del
servidor.

Otro
método podría ser "estaVencida" que evalúe la fecha de vencimiento con la
fecha actual.



Lo mismo. "Está vencida" debería ser un campo de una vista.

A partir de este objeto "transacción" yo puedo derivar un objeto "factura de
venta", otro "factura de compra", etc.



Mucho mejor hacer esto con vistas.

La base de datos estaría en
una capa inferior con la que sólo se comunicarían algunos métodos de las
clases. También podría haber una capa superior que se encargue de
interactuar con el usuario.



Con lo cual estarías desaprovechando la mayor parte de la potencia del
SGBD y gestionando los datos en las aplicaciones mediante código
procedimental. Un antipatrón muy conocido.

Separar en capas no es suficiente. La gestión de los datos debe de
quedar fuera de las aplicaciones.

Se que para la forma de pensar habitual suena a loco, pero para grandes
proyectos podría ser una buena manera de encarar las cosas.



Solo si tu objetivo es maximizar los costes de desarrollo y sobre todo
el de mantenimiento.


Saludos
Respuesta Responder a este mensaje
#17 Daniel Ruzo
23/11/2006 - 19:58 | Informe spam

Sí, para segurar la integridad lo mejor son los SGBD. Pero los datos se
registran, se recuperan, se presenten (muestran), se procesan para obtener
otros datos, etc., etc.



Para obtener nuevos datos lo mejor son los SGBD.




Hasta cierto nivel de complejidad es aceptable encargar los cálculos al
SGBD, pero luego de ese nivel se tiene que encargar la aplicación. Si no
terminarías programando todo a través de stored procedures...

¿Calcular un total de un documento? Te lo acepto. ¿Procesar cientos de
facturas de venta de productos consignados para generar una deuda con el
proveedor? No, gracias.


Tengo una clase que crea el objeto "transacción". Este objeto tiene un
método "leer" que se encarga de leer el cabezal de la transacción y todas
sus lineas.



¿Y por que no la muestras directamente el resultado de la consulta?




El resultado de la consulta sería lo que el método "leer" o "cargar" tomaría
para hacer su trabajo. El objeto sería una forma de organizar la información
en memoria.


Es mejor usar una clase que sirva para cualquier consulta en lugar de
tener que crear una clase para cada consulta.




No hablo de una clase por consulta. Hablo de una clase por entidad de
negocio.


Los datasets tipados no me gustan demasiado, pero por lo menos se
crean automáticamente.

Con una simple invocación a este método cargo toda la
transacción en el objeto. También existe un método "calcularTotal" que
suma
los importes de las lineas de la transacción y devuelve el total.



Esto es una mala práctica. El total se debe de traer ya calculado del
servidor.

Otro
método podría ser "estaVencida" que evalúe la fecha de vencimiento con la
fecha actual.



Lo mismo. "Está vencida" debería ser un campo de una vista.




Aceptado. Pero traté de presentar un ejemplo lo más sencillo posible para
explicar las ventajas que se pueden obtener con esta arquitectura de
software. No te concentres en el caso particular.


A partir de este objeto "transacción" yo puedo derivar un objeto "factura
de
venta", otro "factura de compra", etc.



Mucho mejor hacer esto con vistas.




Estoy interactuando con el usuario que está ingresando un documento... ¿Cómo
organizo esa información en memoria antes de registrar e imprimir el
documento?


La base de datos estaría en
una capa inferior con la que sólo se comunicarían algunos métodos de las
clases. También podría haber una capa superior que se encargue de
interactuar con el usuario.



Con lo cual estarías desaprovechando la mayor parte de la potencia del
SGBD y gestionando los datos en las aplicaciones mediante código
procedimental. Un antipatrón muy conocido.




No creo estar desaprovechando nada. Ahora si me dices que quieres programar
toda tu aplicación con stored procedures, entonces tú estarías
desaprovechando la potencia de los lenguajes de programación.


Separar en capas no es suficiente. La gestión de los datos debe de
quedar fuera de las aplicaciones.

Se que para la forma de pensar habitual suena a loco, pero para grandes
proyectos podría ser una buena manera de encarar las cosas.



Solo si tu objetivo es maximizar los costes de desarrollo y sobre todo
el de mantenimiento.




Si tienes una buena definición de objetos vas a llegar a la conclusión de
que un remito es igual al 90% de una factura. Y cuando tengas que programar
el remito me dirás si tienes mayores costos de desarrollo.


Saludos




Lo que presento es apenas un esbozo de una arquitectura posible. Para
aceptarla hay que estar convencido de los beneficios de la POO.

Yo por ahora lo tengo en la categoría de "aceptado". Tal vez un día lo pase
a "aplicado". Ese días les contaré.

Gracias por hacer fecunda la discusión.

¡Saludos!

*****************************************************
Daniel Ruzo
Miembro del GCU (Grupo Clarion Uruguay)
*****************************************************
Respuesta Responder a este mensaje
#18 Alfredo Novoa
23/11/2006 - 20:59 | Informe spam
On Thu, 23 Nov 2006 15:58:14 -0300, "Daniel Ruzo"
wrote:

Para obtener nuevos datos lo mejor son los SGBD.



Hasta cierto nivel de complejidad es aceptable encargar los cálculos al
SGBD, pero luego de ese nivel se tiene que encargar la aplicación.



Más bien es todo lo contrario. Cuanta mayor complejidad en los
cálculos más tienes que ganar utilizando un lenguaje declarativo de
alto nivel como SQL en lugar de uno procedimental de bajo nivel como
C#.

Es evidente que pasar de un lenguaje de alto nivel a otro de bajo
nivel es ir hacia atrás. La diferencia en nivel de abstracción entre
SQL y C# es mucho mayor que entre C# y ensamblador.

Si no
terminarías programando todo a través de stored procedures...



Los "stored procedures" son la peor forma de trabajar con los datos
con un SGBD, y se deben de usar solo como último recurso para lo que
no podamos hacer de forma declarativa. Pero aun así es mucho mejor
manejar los datos con stored procedures que con código de aplicación.

Además es posible crear stored procedures en C# e incorporarlos a SQL
Server. También podemos hacer lo mismo con Oracle y Java.

¿Calcular un total de un documento? Te lo acepto. ¿Procesar cientos de
facturas de venta de productos consignados para generar una deuda con el
proveedor? No, gracias.



Hacer eso con código de aplicación sería una locura. Lo que dices se
podría resolver con una consulta de un par de líneas, y además el SGBD
la optimizaría automáticamente en función de las características de
los datos almacenados. Algunos SGBD son capaces de aprender y
responden a las consultas cada vez más rápido.

¿Y por que no la muestras directamente el resultado de la consulta?




El resultado de la consulta sería lo que el método "leer" o "cargar" tomaría
para hacer su trabajo. El objeto sería una forma de organizar la información
en memoria.



El resultado de la consulta podría mostrarse directamente con muy poco
esfuerzo con lo que tu objeto no aportaría ningún valor. Sería
trabajar para nada aumentando las posibilidades de introducir errores.

Es mejor usar una clase que sirva para cualquier consulta en lugar de
tener que crear una clase para cada consulta.




No hablo de una clase por consulta. Hablo de una clase por entidad de
negocio.



Al final acaba siendo lo mismo. Al resultado de cada consulta se le
puede considerar una entidad de negocio.

¿Acaso una relación de deudas con proveedores no es una entidad de
negocio?

Entidad de negocio es un término basante difuso.

A partir de este objeto "transacción" yo puedo derivar un objeto "factura
de
venta", otro "factura de compra", etc.



Mucho mejor hacer esto con vistas.




Estoy interactuando con el usuario que está ingresando un documento... ¿Cómo
organizo esa información en memoria antes de registrar e imprimir el
documento?



Precisamente para esto está la aplicación. Por ejemplo puedes usar
DataTables.

Lo mejor es usar una transacción por cada línea del documento. Así
cada línea te la valida el SGBD.

No creo estar desaprovechando nada. Ahora si me dices que quieres programar
toda tu aplicación con stored procedures, entonces tú estarías
desaprovechando la potencia de los lenguajes de programación.



La potencia de C# para tratamiento de datos es minúscula comparada con
la de un SGBD. Por eso se crearon los SGBD, para liberar a las
aplicaciones del tratamiento de datos.

Si tienes una buena definición de objetos vas a llegar a la conclusión de
que un remito es igual al 90% de una factura. Y cuando tengas que programar
el remito me dirás si tienes mayores costos de desarrollo.



Pero gestionar una factura por código de aplicación es un trabajo
inmensamente mayor al de hacerlo con un SGBD. Con un SGBD un remito
también será igual al 90% que una factura, solo que ese 10% que falta
será muchísimo menor, al igual que el 100% de la factura.

Lo que tu cuentas ya se ha probado y descartado hace décadas. Los SGBD
se crearon precisamente para poder dejar de trabajar así.

Lo que presento es apenas un esbozo de una arquitectura posible. Para
aceptarla hay que estar convencido de los beneficios de la POO.



En esto estoy de acuerdo, hay que estar muy convencido para no ver las
evidentes desventajas de trabajar así.

Yo por ahora lo tengo en la categoría de "aceptado". Tal vez un día lo pase
a "aplicado". Ese días les contaré.



Yo ya he aplicado lo que tu dices con resultados desastrosos.


Saludos
Alfredo
Respuesta Responder a este mensaje
#19 Daniel Ruzo
23/11/2006 - 21:30 | Informe spam
Alfredo:

Nadie habló de C#. Existen lenguajes de 4 y 5G.

Veo que tenemos enfoques totalmente opuestos.

Ha sido un placer.

¡Saludos!

*****************************************************
Daniel Ruzo
Miembro del GCU (Grupo Clarion Uruguay)
*****************************************************

"Alfredo Novoa" escribió en el mensaje
news:
On Thu, 23 Nov 2006 15:58:14 -0300, "Daniel Ruzo"
wrote:

Para obtener nuevos datos lo mejor son los SGBD.



Hasta cierto nivel de complejidad es aceptable encargar los cálculos al
SGBD, pero luego de ese nivel se tiene que encargar la aplicación.



Más bien es todo lo contrario. Cuanta mayor complejidad en los
cálculos más tienes que ganar utilizando un lenguaje declarativo de
alto nivel como SQL en lugar de uno procedimental de bajo nivel como
C#.

Es evidente que pasar de un lenguaje de alto nivel a otro de bajo
nivel es ir hacia atrás. La diferencia en nivel de abstracción entre
SQL y C# es mucho mayor que entre C# y ensamblador.

Si no
terminarías programando todo a través de stored procedures...



Los "stored procedures" son la peor forma de trabajar con los datos
con un SGBD, y se deben de usar solo como último recurso para lo que
no podamos hacer de forma declarativa. Pero aun así es mucho mejor
manejar los datos con stored procedures que con código de aplicación.

Además es posible crear stored procedures en C# e incorporarlos a SQL
Server. También podemos hacer lo mismo con Oracle y Java.

¿Calcular un total de un documento? Te lo acepto. ¿Procesar cientos de
facturas de venta de productos consignados para generar una deuda con el
proveedor? No, gracias.



Hacer eso con código de aplicación sería una locura. Lo que dices se
podría resolver con una consulta de un par de líneas, y además el SGBD
la optimizaría automáticamente en función de las características de
los datos almacenados. Algunos SGBD son capaces de aprender y
responden a las consultas cada vez más rápido.

¿Y por que no la muestras directamente el resultado de la consulta?




El resultado de la consulta sería lo que el método "leer" o "cargar"
tomaría
para hacer su trabajo. El objeto sería una forma de organizar la
información
en memoria.



El resultado de la consulta podría mostrarse directamente con muy poco
esfuerzo con lo que tu objeto no aportaría ningún valor. Sería
trabajar para nada aumentando las posibilidades de introducir errores.

Es mejor usar una clase que sirva para cualquier consulta en lugar de
tener que crear una clase para cada consulta.




No hablo de una clase por consulta. Hablo de una clase por entidad de
negocio.



Al final acaba siendo lo mismo. Al resultado de cada consulta se le
puede considerar una entidad de negocio.

¿Acaso una relación de deudas con proveedores no es una entidad de
negocio?

Entidad de negocio es un término basante difuso.

A partir de este objeto "transacción" yo puedo derivar un objeto
"factura
de
venta", otro "factura de compra", etc.



Mucho mejor hacer esto con vistas.




Estoy interactuando con el usuario que está ingresando un documento...
¿Cómo
organizo esa información en memoria antes de registrar e imprimir el
documento?



Precisamente para esto está la aplicación. Por ejemplo puedes usar
DataTables.

Lo mejor es usar una transacción por cada línea del documento. Así
cada línea te la valida el SGBD.

No creo estar desaprovechando nada. Ahora si me dices que quieres
programar
toda tu aplicación con stored procedures, entonces tú estarías
desaprovechando la potencia de los lenguajes de programación.



La potencia de C# para tratamiento de datos es minúscula comparada con
la de un SGBD. Por eso se crearon los SGBD, para liberar a las
aplicaciones del tratamiento de datos.

Si tienes una buena definición de objetos vas a llegar a la conclusión de
que un remito es igual al 90% de una factura. Y cuando tengas que
programar
el remito me dirás si tienes mayores costos de desarrollo.



Pero gestionar una factura por código de aplicación es un trabajo
inmensamente mayor al de hacerlo con un SGBD. Con un SGBD un remito
también será igual al 90% que una factura, solo que ese 10% que falta
será muchísimo menor, al igual que el 100% de la factura.

Lo que tu cuentas ya se ha probado y descartado hace décadas. Los SGBD
se crearon precisamente para poder dejar de trabajar así.

Lo que presento es apenas un esbozo de una arquitectura posible. Para
aceptarla hay que estar convencido de los beneficios de la POO.



En esto estoy de acuerdo, hay que estar muy convencido para no ver las
evidentes desventajas de trabajar así.

Yo por ahora lo tengo en la categoría de "aceptado". Tal vez un día lo
pase
a "aplicado". Ese días les contaré.



Yo ya he aplicado lo que tu dices con resultados desastrosos.


Saludos
Alfredo
Respuesta Responder a este mensaje
#20 Bingen
24/11/2006 - 11:07 | Informe spam
Hola Daniel:

Muchas Gracias. Como tu bien comentas me liaba con las restricciones de de
borrado. Con ello veo clara la separación de la gestión de la integridad de
los datos y la lógica empresarial, todos esto desde el punto de enfoque de
la POO.

Un Saludo
Bix

"Daniel Ruzo" escribió en el mensaje
news:
Todo eso que mencionas lo tiene que manejar el motor o tu diseño de la
base de datos. En este sentido, tenía razón Alfredo.


- Un día determinado, cambiamos el precio de un artículo. Las facturas
hasta ahora realizadas en el sistema se verán envueltas en el cambio
porque
sus líneas reflejarán el cambio, nos mostrarán el nuevo precio del
artículo.
Si bien en otros casos esto puede ser beneficioso, en este caso no lo es
porque por Ley, las facturas se deben de mantener invariables.




Esto es un tema de diseño. Hagamos un análisis de datos. Si bien en el
momento de facturar tomas el precio vigente de la lista de precios, ese
precio es un dato "diferente" del precio vigente. No es el "precio de
venta vigente" sino el "precio de venta vigente en el momento de la
venta". El precio vigente cambia con el tiempo y depende del producto; el
de la factura se mantiene constante y depende de la factura. Por lo tanto,
debes tener una columna para precio de venta en la tabla de lineas de
factura (y demás documentos).


- Lo mismo sucede si cambiamos otra información como puede ser la
descripción, el código, etc.




En cuanto a la descripción, si bien podría darse el caso de que cambien un
artículo por otro a través del nombre y sigan usando el mismo número de
artículo para un artículo diferente, sería un problema de "uso" de la
aplicación y no de la aplicación en sí. En la práctica no se da, y la
descripción del artículo no se registra en la tabla de lineas de factura.
Nuestra entidad "articulo" se mantiene constante a través de su
identificación, y si el usuario cambia la descripción no es un problema
nuestro. El artículo que ayer se llamaba "A" ahora se llama "B", pero para
la base de datos sigue siendo el mismo artículo que cambió un atributo. Si
ayer vendí el artículo 1 que se llamaba "A", hoy digo que vendí el
artículo 1 que se llama "B". Y siempre se puede recurrir al documento
impreso para ver la descripción de aquel momento. Si fuera una cuestión
fundamental tener en la base de datos el nombre exacto utilizado en
determinado momento se debería considerar en el diseño y tener una tabla
de cambios históricos, en la cual se establezca que hasta tal fecha/hora
el nombre del artículo tuvo tal valor.

Respecto al código, si es lo que se utiliza como identifiación del
artículo (clave primaria) para mi gusto no debería permitirse cambiar.
Pero reitero que es una cuestión de gusto. Si se decide que se permite
cambiar debería establecerse en el motor de base de datos que se propague
en cascada ese cambio a todas las tablas relacionadas mediante "UPDATE
CASCADE". Y si se decide que la clave primaria no se pueda modificar la
restricción debe ser del tipo "UPDATE RESTRICT".


- Borramos un artículo. Las líneas que hacían referencia a ese
artículo,
pierden dicha información.




Esto lo solucionas con una restricción de tipo "DELETE RESTRICT". Si la
clave primaria está referenciada en otra tabla no se puede eliminar.


Se ha comentado que la integridad de los datos debería de gestionarlos la
base de datos. Mi duda es la siguiente: Si bien podemos mantener el tipo
de
integridad referencial para actualizar los datos en cascada y podemos
eliminar en cascada los registros relacionados, creo que nada de esto es
aplicable a nuestro caso, es decir, el cambio de la clave foranea no se
daría, porque por cuestiones de mapeo de objetos en una bd relacionar,
pensaba utilizar un código Guid para cada objeto, invariable en toda su
vida. Tampoco es necesario (ni deseado) el borrado de las líneas por el
hecho de borrar un artículo (borrado en cascada), entonces, pregunto:

¿ es posible mediante la Base de datos evitar el borrado de un elemento
(en
nuestro caso un artículo) si sabemos que se utiliza en alguna línea?




Por lo que veo, tus dudas surgen de que conoces las restricciones
"CASCADE" pero no las "RESTRICT". Así que está respondido más arriba.

Las restricciones de tipo "CASCADE" se deberían usar en casos muy
delimitados, como por ejemplo para borrar un cabezal de factura y todas
sus lineas. Pero por lo general se utiliza "RESTRICT" para no perder
información. Pero depende de cada caso en particular.


¿ La forma de controlarlo se puede aplicar en la mayoría de las base de
datos ?. Es dificil portar esa "logica" de una a otra ?




Sí, las restricciones son un estándar. Algunos motores no soportan el
"CASCADE", pero la mayoría soporta ambos tipos de restricción.


y para los casos de cambio de precio, descripción, etc. ¿ Qué
planteamiento
optarían ?, ¿ Copiar estos valores en a línea?. Con ello duplicamos
información..., etc.




Esto ya lo comenté más arriba. No se duplica información cuando se trata
de datos diferentes. El precio de una factura es diferente al precio
vigente, pero la descripción del artículo es el mismo dato siempre, aunque
cambie.

¡Saludos!

*****************************************************
Daniel Ruzo
Miembro del GCU (Grupo Clarion Uruguay)
*****************************************************


Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaSiguiente AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida