Lo primero que debes hacer es clarificar las ideas: debes separar lo que es interface de los soportes de datos (tablas, base de datos, etc) y a ambos del tratamiento de datos.
Entonces:
1) Definir cuáles son las tablas que necesitas y cuál es la estructura de cada una
2) Definir que tipo de movimiento o cambio en los datos se necesita realizar
3) En función de esto y teniendo en cuenta la posición del usuario, defines la interface.
Típicamente, para un sistema de facturación con control de inventarios:
1) Tabla de Cliente
2) Tabla de Productos
3) Tabla de cabecera de facturas
4) Tabla de detalle de productos/servicios vendidos (puede ser más de una)
5) Tabla de posiciones de inventario (algunos usan la tabla de productos, pero yo lo veo demasiado corto porque no contempla la existencia de depósitos múltples). En esta tabla va: Id de Depósito, Id de Producto. La combinación Id_deposito + Id_Producto debe ser única.
6) Tabla de pendientes de facturas a cobrar en cuenta corriente
7) Tabla de cuotas (venta en cuotas)
8) Tabla de proveedores
9) Tabla de cabecera de facturas de compras
10) Tabla de detalle de productos comprados
11) Tabla de pendientes de facturas a pagar
12) Tabla de registro de cobranzas (cabecera de recibos)
13) Tabla de registro de documentos cancelados (recibo detalles)
14) Tabla de registro de pagos (cabecer de ordenes de pago)
15) Tabla de registro de documentos cancelados (detalles de pago)
Además de esto te surgirá la necesidad de contemplar los siguientes temas:
a) Cobranza con valores (cheques, documentos a cobrar, tarjetas de crédito, etc)
b) Pagos con valores de terceros, endoso de documentos, etc y pagos con valores propios emitidos
c) Retenciones de impuestos efectuadas por los clientes
d) Percepciones de impuestos efectuadas por proveedores
e) Retenciones y percepciones de impuestos efectuadas por nosotros.
f) Tratamiento de valores de terceros y propios
Sobre tu consulta en particular, te digo:
1) No puedes tener un textbox (objeto) en una tabla, aunque si puedes tener las definiciones para crear ese objeto dentro de un campo memo. Generalmente colocamos un textbox en un formulario, o en un container (Container, Page de PageFrame ó Column de un Grid) dentro de un formulario.
2) Dices que tienes dos grid en un programa. Supongo que te refieres que tienes dos formularios con sendos grids que asocias a una tabla de productos y a una tabla de clientes. Bien, sera mejor que ya te prepares un solo formulario con un solo grid, que según los parámetros que pases sea capáz de mostrar y gestionar: Clientes, Proveedores, Productos, Empleados, Fleteros, etc. En todos los casos el problema es el mismo, aunque el movimiento de datos varíe un poco: Altas, Modificaciones y Bajas (que no significan borrar el dato si no, poner una marca en la tabla). Y en todos los casos, necesitarás un acceso de búsqueda y captura de datos.
3.1) Descuentas del inventario cuanto despachas la mercadería (por remito o por factura), lo cual significa que tienes que descontar de la tabla de inventario, en la posición de Depósito y Producto que corresponda.
3.2) Antes de ingresar la cantidad entregada, tienes que tener definido qué producto y de qué depósito sale. Luego ingresas la cantidad y confirmas la operación. Tienes que tener un cursor armado sobre la tabla de detalle de ventas. Supongamos que la tabla de detalle de productos vendidos se llama ProdFac.dbf, la inicio del formulario de ventas, creas un cursor vacío:
SELECT * FROM ProdFac WHERE .F. INTO CURSOR curProdFac
En el init del form, vas a asociar curProdFac a un control GRid (supone que se llama grdVentas) .
Suponemos además que tienes un método para buscar el producto y colocas el Id del producto en un textbox llamado txtidproducto. Ahí pones el TxtCantidad.enabled=.t. y permites que el usuario agregue la cantidad.
Cuando agregas un producto a la venta, se lo agregas al cursor en el botón de confirmar la operación.
Si modificas la cantidad de venta de un producto ya ingresado tienes dos maneras:
a) eliminar el registro del cursor curProdfac (reponiendo el stock)
b) Permitir modificar el registro, pero debes grabar como movimiento de stock la suma algebraica:
por ejemplo, creas una propiedad del form Addproperty(thisform,"restar",0) (esto en el diseñador de formularios o pones el ADdproperty en el Load del form.
En el gotFocus de TxtCantidad pones
Thisform.Restar = 0 - this.value
*<cmdConfirma.click>
lnIdProducto=thisform.txtIdProducto.value && surgió de la tabla de productos
lnIdDeposito=Thisform.txtIdDeposito.value && selector (generalmente se usa un combobox. Ajustar)
lnCantidad=thisform.txtCantidad.value && dato que ingresa el operador
lnPrecio=thisform.txtPrecio.value && sugió de la tabla de productos
lnImporte=Round(lnCantidad * lnPrecio,2)
lnImpuestos=Round(lnImporte * lnTasaIva,2) && adaptar a lo que se necesite
lnTotal = lnImporte + lnImpuestos
INSERT INTO curProdFac (IdProducto, IdDeposito, Cantidad ,Precio, Importe,Impuestos,total) ;
values (lnIdProducto , lnIdDeposito, lnCantidad ,lnPrecio , lnImpuetos, lnTotal)
SELECT (lcTablaInventario)
LOCATE FOR idProducto = curProdFac.idProducto AND idDeposito=curProdFac.idDeposito
IF FOUND()
REPLACE STOCK WITH STOCK - (curProdFac.Cantidad + thisform.restar)
ENDIF
Thisform.grdVentas.REfresh
* Limpieza del form para seleccionar otro producto con otra cantidad, etc.
*</cmdConfirma.click>
Si la venta/entraga se cancela, antes de limpiar el formulario DEBES REPONER EL INVENTARIO.
SELECT curProdFac
SCAN
LnIdProducto=idProducto
LnIdDeposito=IdDeposito
lnCantidad = Cantidad
SELECT (lcTablaInventario)
LOCATE FOR IdProducto = lnIdProducto AND IdDeposito = lnIdDeposito
IF FOUND()
REPLACE STOCK WITH STOCK + LnCantidad
ENDIF
ENDSCAN
* Si la Venta se confirma, entonces tienes que actualizar todas las tablas que correspondan (la de inventario no porque ya está actualizada).
SELECT curProdFac
ZAP
* Limpieza de controles