Sie sind auf Seite 1von 15

Antecedentes En los primeros tiempos de mi experiencia como desarrollador, en la era del Fox Dos, me vi en la necesidad de desarrollar una forma

mas eficiente de hacer facturas, que la que venia utilizando hasta entonces. Lo que yo hacia era utilizar el SCROLL para hacer que la pantalla se mueva hacia arriba cada vez que se ingresaba un nuevo articulo. Cada vez que el usuario quera revisar la factura, especialmente si contena un gran nmero de lneas que desaparecan de la pequea superficie de dibujo de la pantalla, yo tenia que crear una matriz en forma dinmica, a partir de los registros guardados en una tabla local, y mostrarlos con un POPUP. Cuando era necesario hacer cambios (borrar una lnea, cambiar un cdigo, una cantidad o un precio unitario), yo elega un tem del popup, llamaba a una rutina especial, hacia los cambios necesarios, redibujaba la pantalla. Cunto trabajo..! Si mi cliente deseaba hacer algn cambio minsculo, me llevaba horas, debido a lo complicado de todos los procedimientos. Por eso, buscando una manera mejor de hacer las cosas, comenc a usar el BROWSE. Y con eso lo logre. El browse permita tanta facilidad de manipulacin, era tan flexible, que descarte todo el cdigo anterior y cambie todas las pantallas usando Browse. Ahora, en la era de la POO, todo eso paso a la historia. El browse puede ser reemplazado con mucha facilidad por una cuadricula, si se tiene cuidado de considerar todos los aspectos de uso que ella requiere. Qu tenemos que considerar al hacer facturas Puedo mencionar los siguientes puntos a considerar cuando se hacen facturas, especialmente si la aplicacin, como la mayora en estos das, va a funcionar en un entorno de red:

Use un cursor local para ingresar y modificar datos Despus que la factura se acepto y esta lista para imprimir, piense en usar transacciones para guardar los datos en las distintas tablas Use una tabla compartida para generar nmeros de facturas

Por qu aconsejo el uso de un cursor local para el ingreso de datos? Si se usa un cursor local, se puede agregar, modificar o borrar registros segn se necesite, sin comprometer los datos del servidor de ninguna manera. Adems, no utilizamos recursos de la red innecesariamente, ni tenemos que lidiar con el sndrome de "me fui a almorzar", que termina lockeando indefinidamente los registros. Por qu usar transacciones? Eso depende. Si el sistema se va a usar en una maquina sola, quizs el uso de transacciones no sea necesario. Sin embargo, un posible corte de luz o algn programa que cuelgue la maquina, puede hacer aconsejable su uso. En un sistema en red, por el contrario, pienso que las transacciones son lo ms aconsejable. Cuando se emite una factura, intervienen muchas tablas en el proceso: tablas de consulta, tales como las de clientes, artculos y stock, para obtener datos de los clientes, precios y descripciones de los artculos y cantidades en existencia; tablas de servicio, como por ejemplo la tabla de numeracin de las facturas o, en algunos pases, las tablas de tasas impositivas, y tambin tablas de grabacin, como las de stock, totales de la factura, detalles de las facturas, cuentas a cobrar, valores recibidos y otras mas, segn sea el caso. Dado que intervienen varias tablas, especialmente en el proceso de grabacin, y debido a que el mismo se efecta secuencialmente, tabla por tabla, lnea por lnea, en algn momento algo podra fallar (La ley de Murphy operando a pleno): un corte de luz, una tarjeta de red defectuosa, un ndice corrupto en una de las

tablas o un encabezado de tabla desmadrado. En tales casos, algunas de las tablas se graban y otras no. El resultado es una pesadilla si tratamos de arreglarlo. Por eso recomiendo el uso de transacciones, advirtindole al programador que lo haga de la manera lo ms eficiente posible, para evitar el locking de las tablas y registros durante mucho tiempo. Y tambin, use una tabla compartida para generar nmeros de facturas. Esto es necesario porque, cuando dos o ms usuarios hacen facturas, nunca se sabe quien va a pulsar el botn Aceptar primero. Usando una tabla compartida que controle el numero secuencial de las facturas, se pueden emitir eficientemente centenares de facturas sin mezclar los datos grabados. Hay otras cosas a considerar, tales como formularios de facturas preimpresos atascados en algunas impresoras, diferentes mtodos de pago en la misma factura (cupones, tarjetas de crdito, efectivo, cheques, etc.), descuentos globales o individuales, diferentes tasas impositivas para diferentes tipos de clientes, como puede ser el caso en algunos pases, etc. En este articulo, sin embargo, solamente voy a enfocar el tema especifico de la confeccin de facturas con cuadriculas. Y tratare de hacerlo de manera simple, sin complicar las cosas con descuentos en cada lnea, ni controles agregados en las columnas de la cuadricula. Voy a presentar un ejemplo simple de cuadricula, como "viene de fabrica". El formulario Existen varias opciones para el tipo de formulario a utilizar. En algunos casos se podra usar un formulario para definir los datos del cliente (nombre, direccin, categora de impuestos en algunos pases, si la venta es a crdito o en efectivo, etc.) Se podran ingresar todos los datos necesarios en dicho formulario y luego llamar a otro formulario con una cuadricula para hacer la factura. O se podra usar un nico formulario con un page frame, en una de cuyas paginas se obtendran los datos necesarios del cliente y en la otra se podra poner la cuadricula. O se podra utilizar un nico formulario con el espacio suficiente como para poner los datos del cliente y de la factura. Cualquiera sea el caso, la eleccin es suya. Adems de la cuadricula, se necesitan algunas etiquetas para mostrar los totales de la factura, que se Irn actualizando y refrescando a medida que se hace un cambio en la cuadricula, como por ejemplo: agregar un nuevo registro, modificar un precio o una cantidad, o simplemente borrar una lnea no deseada. Si se ingresa un descuento global, como por ejemplo el 10% sobre el monto total, se necesitara una textbox para ingresar el porcentaje de descuento y otra etiqueta para mostrar el monto del descuento. De cualquier forma, cuando se hace cualquiera de los cambios indicados, se hace una llamada al mtodo INV_TOTALS, que ara todos los clculos, como se mostrara mas adelante. El cursor y su estructura Como se indico, se usa un cursor local para el ingreso de datos. Por supuesto, un cursor local, es de lectura/escritura. La estructura del cursor es la siguiente:

Campo Tipo Observaciones ItemCode C(10) o la longitud que tenga el cdigo del articulo Detail C (50) o mayor, dependiendo de la descripcin del articulo Quantity N (5) UnitPrice N (12,2) LineTotal N(12,2) Se puede generar este cursor local en el evento LOAD del formulario a utilizar, con el siguiente comando:
Create cursor INVOICE( ; ItemCode C(10), Detail C(50), Quantity N(5,0),; UnitPrice N(12,2),LineTotal N(12,2) ) Append blank

(hace falta al menos un registro para poder ingresar datos en el cursor) Las tablas Se puede usar el DATAENVIRONMENT para cargar todas las tablas necesarias. Solo mencionare aqu las tablas que necesita mi ejemplo. Su estructura, ndices y relaciones no vienen al caso aqu. Dado que este es un ejemplo de venta en mostrador, no necesitamos identificar al cliente, por lo que solamente voy a necesitar las siguientes tablas:

ITEMS.DBF contiene los datos de los artculos (cdigo, descripcin, precio) STOCK.DBF para actualizar las existencias INVTOTAL.DBF guarda un registro por cada factura con la fecha de la factura, el numero de factura, los impuestos aplicables, el numero del vendedor, el descuento global y el total de la factura DETAILS.DBF guarda las cantidades, precios unitarios y cdigo del articulo por cada lnea de la factura CASH.DBF para el numero de la factura, su fecha, total parcial o general y tipo de pago (efectivo, cheque, cupn, tarjeta de crdito) CREDCARD.DBF si se aceptan tarjetas de crdito para el pago, necesitamos una tabla de consulta con todas las tarjetas posibles.

Segn sea cada situacin en particular, se podran necesitar otras tablas, pero como mnimo, creo que la lista anterior es suficiente. La cuadrcula Si seguimos la estructura del cursor INVOICE, vemos que hacen falta cinco columnas en nuestra cuadricula. Para instanciar el formulario sin problemas, solamente mostramos la cuadricula, pero sin fijarle un recordsource o ninguna de sus propiedades, excepto quizs el ancho, numero de columnas, encabezados y ancho de las

mismas. Esto es para que, al abrir el formulario para modificarlo, tengamos una idea de cmo se vera la cuadricula en tiempo de ejecucin. Pero podramos simplemente poner la cuadricula encima del formulario y configurar sus propiedades con una llamada al mtodo SET_GRID desde el mtodo INIT del formulario, como se muestra a continuacin: Cdigo del mtodo Init (aqu deberamos inicializar propiedades del formulario segn se haga necesario, antes de inicializar la cuadricula).
this.nPrice = 0.00 this.cDescrip = "" this.nMaxLinesAllowed = 30 this.cDocType = "FC" this.nFedTax = 7.00 this.nProvTax = 8.00 this.nPercent = 0.00 && estos valores se pueden obtener && de una tabla de impuestos

&& numero mximo de lneas que caben en el && formulario preimpreso de la factura

this.lblFTpctg.caption = "Fed tax "+ alltrim(transform( this.nFedTax ))+" %" this.lblPTpctg.caption = "Prov tax "+ alltrim(transform( this.nProvTax ))+" %" this.set_grid()

El mtodo Set_grid Como mi intencin es mostrar un ejemplo simple, voy a usar un nombre por defecto para la cuadricula:
With thisform.grid1 .fontbold = .t. .readonly = .f. .columncount = 5 .recordsource = "invoice" .allowaddnew = .f. && esto se explica mas adelante .columncount = 5 .deletemark = .f. .scrollbars = 2 .width = 642 with .column1 .controlsource="invoice.quantity" .width = 70 with .header1 .caption = "Quantity" .alignment=2 && centered endwith endwith with .column2 .width = 96 .controlsource="invoice.itemcode" with .header1 .caption = "Code" .alignment=2 endwith endwith

with .column3 .controlsource="invoice.detail" .width = 275 with .header1 .caption = "Description" .alignment=2 && centered endwith endwith with .column4 .controlsource="invoice.unitprice" .width = 70 with .header1 .caption = "Unit price" .alignment=2 && centered endwith endwith with .column5 .controlsource="invoice.linetotal" .width = 96 with .header1 .caption = "Totals" .alignment=2 && centered endwith endwith Endwith

Consideraciones adicionales

Si consideramos la lgica natural de la confeccin de una factura, vemos que el diseo de la cuadricula de la manera indicada se debe a que simplemente contestamos a la pregunta: cmo se hace una factura? La respuesta es muy simple: primero ingresamos las cantidades, luego ingresamos el cdigo del articulo, en cuyo momento el sistema consulta la tabla de artculos, trae la descripcin y su precio, pone dicha informacin en la lnea que estamos modificando, luego se efecta la multiplicacin del precio por la cantidad y, finalmente, se calcula el total de la lnea. El proceso termina cuando se agrega una nueva lnea vaca en la cuadricula y el cursor se enfoca en la primera columna, para recibir un nuevo articulo. Cmo hacemos que todo funcione? Dmosle una mirada a la columna de cantidades. Nos gustara que el usuario ingresara cantidades mayores que cero. En este ejemplo, solamente queremos valores enteros. As que tendramos que validar el input, no permitiendo cantidades con decimales o ceros. Sin embargo, deberamos permitir el ingreso de cantidades negativas, para el caso de que el formulario se use para confeccionar notas de crdito. O hacer el formulario "inteligente", convirtiendo todas las cantidades en negativas en el caso de que estemos confeccionando una nota de crdito. Por lo tanto, pondremos el siguiente cdigo en el mtodo INIT del textbox en la columna 1:
This.value This.InputMask This.MaxLength This.Format = = = = 0 "99999" 5 "Z"

Con este cdigo nos aseguramos que solamente se ingresen nmeros, de que el valor inicial de la textbox sea cero, de que no se muestre nada si no se ingreso nada y de que la cantidad no supere 99999. Pero aun as, el usuario podra ingresar un cero. As que tenemos que proporcionar el medio de, o bien avisarle al usuario que no se acepta un valor cero, o transformar el cero en un uno. En mi experiencia, es mas rpido dejar que el usuario simplemente apriete la tecla enter, cuando esta posicionado en esta columna, lo cual ara que se ingrese un cero automticamente. Pero el siguiente cdigo en el mtodo VALID de la textbox, har que el cero se transforme en un uno, saltando desde la columna de las cantidades a la siguiente columna.
this.value = iif(this.value = 0,1,this.value) this.refresh

Suponiendo que tenemos una propiedad del formulario llamada cDocType, podramos usar el mtodo VALID para hacer dicha cantidad negativa, dejando de esa manera que el usuario ingrese cualquier numero, sin tener que preocuparse por hacerlo negativo.
this.value = iif(this.value = 0,1,this.value) if thisform.cDocType = 'CN' if abs(this.value) > 0 this.value = -this.value && CN significa nota de crdito

endif endif thisform.inv_totals() && este mtodo se explica mas adelante

(el valor de la propiedad del formulario cDocType lo determina el usuario, antes de empezar a ingresar datos en este formulario. Pero queda fuera del alcance de este articulo el mostrar como se logra esto) Tenemos que asegurar una forma de salir de la grid para poder, ya sea descartar la misma o grabarla e imprimirla. As que programamos el mtodo KEYPRESS con lo siguiente: Cdigo del mtodo Keypress
LPARAMETERS nKeyCode, nShiftAltCtrl If nKeyCode = 27 Thisform.WhatNow() Endif && apret la tecla escape

Se podra poner cdigo en el mtodo WhatNow preguntndole al usuario si desea descartar la factura o grabarla e imprimirla. El cdigo anterior nos llevara a esa etapa.

La columna del cdigo de artculo El cursor ya esta en la columna del cdigo de articulo. segn el tipo de cdigo del articulo, se utilizara una diferente rutina de validacin. Por ejemplo, podramos tener un cdigo alfanumrico como: DURACELL AA, PKJ/90-85, BAYER ASPIRINE o cualquier otro. Tambin podramos tener cdigos numricos, una combinacin de nmeros, guiones y barras, etc. La lista es enorme y no puedo mostrar aqu todas las posibilidades. Pero dije antes que quiero mantener las cosas simples, porque mi objetivo es mostrar como hacer facturas con cuadriculas, y no como se valida el input. Por lo tanto, voy a usar un simple cdigo numrico, con una longitud de no mas de 6 dgitos, almacenado en un campo de tipo carcter. En el mtodo INIT del textbox de esta columna ponemos el cdigo siguiente:
This.value = "" This.InputMask = "999999" This.MaxLength = 6

Este cdigo asegura que solamente se ingresan nmeros de no mas de 6 dgitos. En el mtodo VALID, el cdigo seria:
Local cCode cCode = str(val(this.value),6) select Items if seek( cCode , "Items", "artnum") this.value = cCode with thisform .nPrice = items.pesos .cDescrip = items.descrip endwith select invoice Replace invoice.detail with thisform.cDescrip ,; invoice.unitprice with thisform.nPrice ,; invoice.linetotal with (invoice.quantity * invoice.unitprice) thisform.inv_totals() return 1 else this.value = "" messagebox("CODIGO INVALIDO",48,"ATENCION") return 0 endif

Muy bien, pero por qu tenemos que reemplazar los campos del cursor subyacente con los valores obtenidos? Se podra argumentar que, dado que los controlsources de los textboxes estn ligados (bound) a los campos del cursor, esto no es necesario. Es verdad, pero a veces un poco de redundancia ayuda. En este caso, tengo la absoluta certeza de que, a pesar de la ley de Murphy, los datos recin hallados en la tabla ITEMS, que fueron asignados en las respectivas propiedades del formulario por el cdigo del mtodo valid, realmente se graben en el registro. Sin embargo, no hice lo mismo con las cantidades ingresadas. Por qu? Porque yo estaba interactuando directamente sobre el cursor cuando ingresaba un valor en el campo de cantidad, mientras que en el caso de los valores buscados en la tabla ITEMS, estaba manejando otra tabla, en otra arrea. Yo soy un tipo practico. Esto funciona as, por lo que un poco de redundancia no hace dao. Ya estamos listos para ingresar datos en la columna de detalle, pero, un momento, la descripcin del articulo la obtuvimos de la tabla ITEMS, su valor fue grabado en el cursor INVOICE y, como este campo esta ligado a la cuadricula, la descripcin del articulo ya esta en la cuadricula. Por lo tanto, no queremos que el usuario pueda entrar en esta columna y cambiar nada. Cmo podemos hacer esto? Es muy fcil: ponemos este cdigo en el mtodo WHEN de la textbox de la columna detalle:
Return .f.

As de simple! El mtodo when se dispara antes que el mtodo valid, aun antes de que se pueda entrar en la columna. Al devolver un falso, simplemente se pasa por alto esta columna y se posiciona en la prxima, la columna de los precios unitarios. An cuando el precio lo sacamos de la tabla ITEMS, es posible que la lista de precios no haya sido actualizada antes de hacer la factura, y que tengamos que cambiar el precio all mismo. As que permitimos el ingreso en dicha columna para que el usuario pueda cambiar el precio. Pero aqu podemos tener un problema potencial. Dado que una de las principales razones para el uso de una cuadricula era el poder navegar de arriba abajo y de izquierda a derecha entre las distintas lneas y columnas, pudiendo cambiar los valores, si modificamos el precio unitario, ser aceptado y, como mostramos mas adelante, se harn los clculos de multiplicacin del precio por la cantidad. Sin embargo, si el usuario aprieta la tecla enter en la columna del artculo, se dispara el evento valid del textbox, se busca nuevamente el precio en la tabla de artculos, y se reemplaza el valor que el usuario hubiera ingresado manualmente en dicha columna. Este comportamiento es muy molesto y hara completamente intil nuestra rutina de hacer facturas. Entonces, cmo lo resolvemos? Medite sobre esto durante muchas horas, o en realidad, muchos das. Recurdese que cuando se programa, hay un 10% de tiempo de inspiracin y un 90% de tiempo de transpiracin. Por lo menos, a mi me pasa as. As que, en algn momento de mi 10% de inspiracin, tuve una idea: usar una propiedad del textbox para habilitar o deshabilitar un cambio de precios cuando el usuario aprieta la tecla enter en la columna del cdigo del articulo, o cuando, al usar las teclas de flecha, navega hacia ella. Por ello, hice los siguientes cambios en la columna de artculos: Evento Init

This.value = "" This.InputMask = "999999" This.MaxLength = 6 This.addproperty("cOldCode","")

Evento When
this.cOldCode = str(val(invoice.itemcode),6) return .t.

Antes de entrar en la columna de artculos, leemos el valor almacenado en la tabla (cursor) Evento Valid Cambie el cdigo as:
Local cCode cCode = str(val(this.value),6) If cCode = this.cOldCode Return 1 Else && ya pasamos por aqu

&& no hacemos nada, sino que salimos

select tems if seek( cCode , "tems", "artnum") this.value = cCode with thisform .nPrice = items.pesos .cDescrip = items.descrip endwith select invoice Replace invoice.detail with thisform.cDescrip ,; invoice.unitprice with thisform.nPrice ,; invoice.linetotal with (invoice.quantity * invoice.unitprice) thisform.inv_totals() return 1 else this.value = "" messagebox("CODIGO INVALIDO",48,"ATENCION") return 0 endif endif

(La llamada al mtodo inv_totals se hace para asegurar que se recalculan los totales de la factura cada vez que cambiamos un articulo que se haba ingresado anteriormente. Ver ms adelante una explicacin de este mtodo) La columna de precios unitarios Si bien el precio unitario lo tenemos en la tabla ITEMS, es posible que la misma no este actualizada, o que se quiera poner un precio distinto al de la tabla para una factura determinada. Por esa razn permitimos el ingreso de otro precio en esta columna, cuyo cdigo INIT es el siguiente:

this.addproperty("nLastPrice",0.00) this.value = 0.00

Por que inicializamos aqu la propiedad nLastPrice ? Pues por la misma razn que al navegar hacia cualquiera de las cuatro direcciones, al dar enter sobre la columna de artculos, el evento VALID se disparaba y nos volva a traer el precio de la tabla, en lugar de respetar el precio recin ingresado en la columna de precios unitarios, tenemos que asegurarnos que esto ocurra efectivamente. Por eso, antes de entrar en esta columna leemos el valor que tenia, mediante el cdigo del evento WHEN:
this.nLastPrice = this.value return .t.

y validamos el input en el evento VALID con:


if not inlist( lastkey() , 19 , 4 , 5 , 24 ) && izq, der, arr, abajo

if this.value <> this.nLastPrice Replace invoice.unitprice with this.value ,; invoice.linetotal with (invoice.quantity * invoice.unitprice) endif endif thisform.inv_totals()

Lo que estamos haciendo aqu es una ultra redundancia: primero nos aseguramos de que, si estamos pulsando cualquiera de las 4 flechas de direccin, solamente se recalculen los totales al pie de la factura. Pero adems, si ninguna de esas flechas se pulso, sino que se apret la tecla enter, solamente se cambia el precio en el cursor subyacente y se recalcula el total de ese registro, siempre y cuando el valor que tenemos en la columna es distinto al que haba antes de ingresar en ella. De esta manera, se evita el problema indicado de que se cambie el precio si nosotros no lo queremos as. La ltima columna a la derecha El textbox de la columna de totales debe ser de solo lectura, porque simplemente va a mostrar el valor calculado por el mtodo inv_totals. Sin embargo, hay que permitir el ingreso en esta columna, para que el usuario pueda apretar la tecla enter. Al hacer esto, se lograra que se agregue un nuevo registro al cursor INVOICE, y el foco quedara en la primera columna, a la espera del ingreso de mas datos. Cmo se hace? Cuando establecimos las propiedades de la cuadricula, pusimos la propiedad AllowAddNew en falso. Estuve jugando con esta propiedad durante algn tiempo, pero pronto la deje de lado porque, en mi opinin, es intil para hacer facturas. Esta propiedad, cuando la ponemos en verdadero, hace que se agregue un nuevo registro, cuando el usuario aprieta la tecla flecha abajo. Como nosotros navegamos por la cuadricula en las cuatro direcciones, estaramos agregando registros que no queremos cada vez que vamos hacia abajo. Por lo tanto, para nuestros fines, esta propiedad la dejamos en falso.

Usamos el mtodo KEYPRESS otra vez para agregar un nuevo registro y establecemos el foco en la primera columna de la lnea siguiente, con este cdigo:
LPARAMETERS nKeyCode, nShiftAltCtrl local N if nKeyCode = 13 && se apret la tecla enter

replace invoice.linetotal with (invoice.quantity * invoice.unitprice) go top in invoice count to N for not deleted() if N < thisform.nMaxLinesAllowed go bottom in invoice if not empty( invoice.itemcode ) append blank go bottom in invoice keyboard '{dnarrow}' endif else delete next 1 messagebox('LA CANTIDAD MAXIMA DE LINEAS PERMITIDA'+CHR(13)+'PARA UNA FACTURA ES:'; + str(thisform.nMaxLinesAllowed),16,'ERROR') endif endif This.Parent.Parent.refresh && refrescamos la cuadricula

Analicemos este cdigo en detalle: Cuando el usuario aprieta la tecla enter, esta rutina cuenta el numero de registros no borrados en el cursor y lo compare con la cantidad mxima de lneas que puede tener una factura. Esto es importante si utilizamos formularios preimpresos de facturas, cuyo espacio de impresin de lneas de detalle es limitado. Si se excede el mximo permitido, un mensaje de error le avisa al usuario y se borra el registro recientemente aadido. Si el limite anterior no se alcanzo, se agrega un nuevo registro al cursor INVOICE. Forzamos el foco en la ultima lnea de la cuadricula con la combinacin de los comandos GO BOTTOM y KEYBOARD '{DNARROW}' Tome nota de la prueba adicional: si no hay ningn cdigo de articulo en la primera columna, entonces se agrega un registro nuevo, de lo contrario, no pasa nada. Esto evita que se agreguen lneas intiles en la cuadricula. El mtodo Inv_totals Cada vez que agregamos una nueva lnea, borramos una existente, cambiamos un precio, reemplazamos un articulo por otro o cambiamos las cantidades, las cifras al pie de la factura deben cambiar.

Esta ultima lnea, o conjunto de lneas, segn sea el caso, esta formada por el subtotal de la factura (la suma total que se obtiene de multiplicar las cantidades por los precios unitarios en todas las lneas), y todos los impuestos, descuentos globales o tems adicionales que correspondan (fletes, intereses o lo que fuera). La ultima lnea debe ser el total que el cliente debe pagar. Ahora, dependiendo de cuanto espacio haya en la pantalla, todos estos valores se pueden colocar en una sola lnea, abajo de todo, o en forma encolumnada, una encima de otra. En realidad, esto es una eleccin del programador y no va a afectar los clculos de ningn modo. Los resultados de los clculos se mostraran en etiquetas o en textboxes, a eleccin del programador. En mi caso, yo prefiero usar etiquetas. Por ejemplo, si el subtotal de la factura fuera de 2,000.00 dlares y la etiqueta para mostrar esta cifra tuviera el muy imaginativo nombre de lblSubTotal, utilizaramos la siguiente lnea para mostrarlo:
Thisform.lblSubTotal.caption = transform(thisform.nSubTotal,"9,999.99")

Para que las cifras que pongamos en estas etiquetas se alineen a la derecha, se debe configurar su propiedad alignment a 1. Habiendo dicho esto, veamos ahora como funciona el mtodo INV_TOTALS
With thisform Store 0.00 to .nSubTotal,.nTotal,.nTax1,.nTax2,.nST2 , .nDiscount Select invoice Go top sum (invoice.quantity * invoice.unitprice) to .nSubTotal for not deleted() .nDiscount = .nSubTotal * -.nPercent / 100 .nST2 = .nSubTotal + .nDiscount .nTax1 = .nST2 * .nFedTax / 100 .nTax2 = .nST2 * .nProvTax / 100 .nTotal = .nST2 + .nTax1 + .nTax2 .show_labels() .refresh endwith

Suponiendo que tenemos una propiedad para el descuento global llamada nDiscount y otra propiedad para el porcentaje, con el nombre de nPercent, y adems, que el usuario ingreso un 5% de descuento global, calcularamos el monto del descuento as:
Thisform.nDiscount = thisform.nSubTotal* -thisform.nPercent / 100

(La propiedad nPercent es el controlsource de un textbox usado para ingresar el descuento de 5% deseado) Lo anterior nos da un valor de descuento negativo. Luego recalculamos el subtotal de la factura, para mostrar el valor neto, as:
Thisform.nST2 = thisform.nSubTotal + thisform.nDiscount

(Nota: tenemos que restar el descuento global del subtotal, pero, como ya es negativo, lo sumamos. Guardamos este nuevo subtotal, neto de descuento, en otra propiedad, nST2)

Y ahora estamos listos para calcular los impuestos que se apliquen en su pas. Supongamos que tenemos un impuesto federal a las ventas del 7% y un impuesto provincial del 8% Entonces tendramos que aplicar estos porcentajes al subtotal neto.
Thisform.nTax1 = Thisform.nST2 * thisform.nFedTax / 100 Thisform.nTax2 = thisform.nST2 * thisform.nProvTax / 100

Por ultimo, podemos mostrar el total de la factura, sumando el subtotal neto mas los dos impuestos:
Thisform.nTotal = thisform.nST2 + thisform.Tax1 + thisform.Tax2

Y completamos este mtodo con una llamada al mtodo que mostrara todos estos valores calculados en sus respectivas etiquetas al pie de la factura.
Thisform.show_labels()

El mtodo Show_labels Como se preanuncio en la seccin anterior, utilizamos una serie de funciones TRANSFORM para colocar los valores calculados en sus respectivas etiquetas al pie de la factura.
local cPic cPic = "99,999.99" with thisform .lblST1.caption .lblDisc.caption .lblST2.caption .lblFT.caption .lblPT.caption .lblTotal.caption endwith = = = = = = transform( transform( transform( transform( transform( transform( .nSubTotal .nDiscount .nST2 .nTax1 .nTax2 .nTotal , , , , , , cPic cPic cPic cPic cPic cPic ) ) ) ) ) )

El mtodo Grabar No voy a mostrar aqu como grabar la factura usando transacciones, porque tomara bastante mas espacio del que dispongo y, adems, excedera el alcance de este articulo. Pero puedo decir que la grabacin consiste en usar un loop scan - endscan sobre el cursor INVOICE, grabando todas sus lneas en las tablas correspondientes. Conclusin He mostrado la forma de hacer facturas y otras pantallas complicadas de ingreso de datos, usando cuadriculas. En mis aplicaciones reales agrego mucha mas funcionalidad que la simple metodologa indicada: llamo a una tabla de consulta para la bsqueda de artculos, apretando una tecla de funcin cuando el foco esta en la columna de artculos (esto se hace programando el evento keypress del textbox), o muestro la cuenta del cliente, si la venta es a crdito, por medio de un right click en el formulario y haciendo una llamada al formulario de cuentas corrientes, o ingreso un nuevo cliente mientras hago la factura, o consulto una tabla de descuentos, o muestro una foto del tem que estoy facturando, etc., etc. Las cuadriculas nos permiten mejorar muchsimo nuestras pantallas de ingreso de datos. Con un poco de trabajo y mucha fe, podemos hacerlo. As que, buena suerte en su tarea!

Das könnte Ihnen auch gefallen