Foro de elhacker.net

Programación => Programación Visual Basic => Mensaje iniciado por: corlo en 15 Diciembre 2021, 17:59 pm



Título: Guardar list2 y leer list1
Publicado por: corlo en 15 Diciembre 2021, 17:59 pm
Hola soy corlo

ahora en pantalla principal hay list1 y list2

en el list2 es donde se va entrando los articulos desde el formulario y en el list1 es donde se guardan los datos del list2 al list1 para poder sumar el contado y tarjeta de credito

A la hora de entrar los datos al list2 desde el formulario lo hace bien, el problema es para guardar todos los datos del list2 a una fila del list1 asi sucesivamente con numero de ticket 1,2,3, etc del list1


a la hora de guardar seria:Command2_click()

N de ticket, fecha y hora, metodo de pago, total en el list1


en el metodo de pago esta en la pantalla principal no desde el formulario




a la hora de leer seria list1_click()
N ticket, Fecha y hora, Producto, Precio Unitario, cantidad, subtotal, total, en el list2



Gracias




Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 15 Diciembre 2021, 20:02 pm
Puedes poner alguna captura (o más de 1 si no queda visible todo en una sola) que sirva para orientarse mejor?. Y explicar desde lo que se ve en ella?

La redacción deja que desear y no termina de entenderse bien que tienes actualmente y a dónde quieres llegar, o sea, cuál es el problema que tienes...   

...pareciera que lo que tratas de hacer es el típico 'carrito de la compra', de ser así, al fnal hay que validar o anular la compra, es decir en ese caso son dos procesos, en un o se realiza la elección de los artículos y cuando se quiera se acepta o anula, si se acepta, se procede al pago (se elige la modalidad de pago (para todas las fácturas en el carrito de la compra), se acuña la fecha de ese momento y se asigna el Id de compra para cada artículo.



...en todo momento se supone un mismo y único usuario, si fueran varios, habría que añadir la identificación del usuario al registro (un id de usuario registrado y mantener también un fichero con el registro de los usuarios, cuyos campos podrían ser (a modo de ejemplo):
Id, nombre y Apellidos (3 campos), Alias, fecha de alta, y opcionalmente teléfono. Datos como: numero de documento de identidad y datos bancarios, no son adecuados si no se establece un sistema de seguridad, como se supone que es un ejercicio de prácticas y no una aplicación real, puede obviarse o crearse ficticiamente y por tanto saltarse las cuestiones relativas a la seguridad.

Debería poderse buscar un registro de usuario desde el fichero partiendo de su Alias e Id. Pueden existir nombres completos idénticos (se da en la realidad), pero no alias, por ello al intentar registrar un usuario debe asegurarse que no existe ya, de suceder debe soliicitarse otro alias, también debiera exigirse que los alias tenga un mínimo de caracteresy un máximo y determinar que caracteres se toleran para el alias (A-Z, a-z, 0-9, rechazando el resto, incluso espacios (son traicioneros al escribirse o al filtrar 'strings') para evitar problemas con determinadas funciones de tratamiento de texto).

Para que la búsqueda de Alias sea rápida los alias únicos deberían ir (también) a un fichero (nuevo). Así este fichero podría tener asociados pares Alias-Id, siendo los alias de tamaño prefijado (se rellena con espacios a su derecha si es más corto).  En el fichero se escriben de forma contínua, pero en memoria deben constar en una tabla hash... Como estás verde con tratamiento simple de ficheros y funciones de búsqueda, las tablas hash de momento quedan fuera de tu alcance, así que puedes obviar este fichero y hacer las búsquedas secuencialmente en el registro de usuarios (anteriormente ya te incluí dos ejemplos de búsqueda secuencial en un fichero de registros).

Lo principal es lo de arriba... al menos hasta que lo soluciones.


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 15 Diciembre 2021, 20:41 pm
Hola

asi es serapis, es para un carrito de la compra, que los datos introducidos desde el formulario, van  al list2, esto sale bien
pongo fecha a la hora de crear nueva factura , lo tengo que poner asi 14-12-2021, con la barra no me lo acepta.
el problema es:
 a la hora de guardar los datos vayan a una fila del list1, para luego leer desde el list1 y vayan toda la lista de la compra  los datos al list2
 de esta manera tendria todos los dias controlados
con una carpeta por mes


list1

N de ticket     fecha y hora           metodo de pago                                     total








                                                                                    total contado
                                                                      total tarjeta de credito



en el list2



N ticket            fecha y hora           producto        Precio por Unidad      cantidad    subtotal







                                                                    . contado                                 Total

Nuevo            Guardar            Imprimir           . tarjeta de credito




Todo esto es en un formulario

Te lo hago asi porque no se como hacerlo como crear una imagen de fichero y luego subirlo al foro

el tema de sumar el contado y la tarjeta de credito en el list1 , ya esta solucionado

Gracias



Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 16 Diciembre 2021, 15:37 pm
Al lado de la tecla F12, a su derecha, tienes la tecla para capturar la pantalla, luego te va a un programa de imagen y pegas la imagen desde el portapapeles (menú edición -> pegar), luego recortas la imagen si es muy pequeña respecto de la pantalla completa y la guardas en un formato con compresión preferenetemente en jpg (excepto si hay mucho texto que deba ser leído, en ese caso en png, que conserva mejor los detalles del texto), luego lo subes a una página d ealojamiento de imágenes, copias el enlace 'para foros' y lo pegas en tu mensaje, y cuando envíes el mensaje aparecerá la imagen... es algo muy básico y se tarda más en explicar que en hacerlo.


Cuando haces compras de varios artículos a la vez, se introduce el concepto de 'lotes- pedido', es decir una compra de uno o más artículos en el mismo pedido.

La importancia de esto radica en poder asociar todos esos artículos juntos con un único pago y una única transacción.
Esto requiere modificar profundamente el programa... exige un fichero 'pedidos', que se compone de 3 registros (como mínimo)
Código:
estructura Lote
    id pedido
    cantidad articulos
    id de la lista de articulos.
fin estructura
Como la lista es una cantidad variable, los registros no son de tamaño uniforme, como siempre pasa, hay varias soluciones, la rápida de programar y lenta de operar porque es recorrida secuencialmente o la lenta de programar pero más eficiente.
Entonces si optas por la opción rápida la estructura previa (type), te vale, si prefieres una más óptima, habrá dos ficheros, uno de pedidos, que aligera la estructura previa y hace los registros de tamaño uniforme:
Código:
estructura Lotes
   id pedido
   cantidad articulos
   posicion
fin estructura
El campo posición indica donde s elocaliza en otro fichero el comienzo de los articulos para esa lista...
...y por tanto otro fichero que contiene únicamente ids de artículos... puede optarse por mantener en la cabecera la cantidad de ids que contiene el fichero o simplemente calcularse toda vez que cada campo tiene el mismo tamaño en bytes (2 para vbInteger o 4 para vbLong).
Entonces cuando se lee un lote, se accede al registro en el fichero lotes:
Código:
 dim lote as lotes
 lote = getRegLote(index)
y se crea un array con la cantidad que señala lote.numArticulosLote para acto seguido leer desde el fichero articulos
Código:
  dim articulos() as integer ' long?
  redim articulos(0 to lote.NumArticulosLote -1)
  get #canalArticulos, (lote.posicion * 2)+1, articulos   ' x2 porque cada id es un vbInteger? y por tanto ocupa 2 bytes y +1 porque vb6 considera el primer byte del fichero como 1 y no 0).
   ' el tamaño del array instruye a cuantos valores debe leer... por eso hay que dimensionar el array antes.

Finalmente con el array de ids, se pueden localizar en el fichero que guardas los detalles de cada artículo...

Otra opción (la sencilla de implementar y más lenta para considerar lotes), es omitir estos ficheros y a cambio modificar la semántica (signoficado y comportamiento) del campo numTicket (en el único fichero de compras-mes.dat).
Justamente el id compra (numticket que llamas tú), pasa a ser considera el id lotes que sigue siendo único y autoincremental... pero ahora se asocia se asocia con cada artículo que se compra en un mismo lote, es decir todos los artículos comprados en un lote tienen el mismo idLote (numTicket), y conviene añadir un nuevo campo (también único e incremental) así cuando se localiza un pedido se localizan todos los artículos con el mismo idLote, aunque lo habitual es que como estarán contiguos en el fichero se limita a buscar el primero, y luego leer los siguientes registros mientras el idLote sea el mismo.
Es decir el reconocimiento del lote sigue ese patrón.
El idCompra identifica cada compra así se puede discriminar cada artículo de un lote y facilita poder buscar también un solo idCompra en todo el fichero.


La lógica tras un carrito de la compra es la siguiente (a la noche si veo que tengo tiempo suficiente, te hago un breve código de ejemplo, peor en vez de modificar lo actual, creo una nueva ventana, para no tocar lo previo).

En una ventana (como hasta ahora) se puede elegir el artículo a comprar (esa parte depende de tí enteramente poner a disposición dle 'cliente' los productos disponibles, así como su precio). Hay un botón añadir al carrito...
Cuando se pulsa ese botón es cuando ese artículo, la cantidad y el precio por unidad se pasan al listado del carrito de la compra (conviene una ventana flotante y no modal para esto).
En ese momento, no se les asigna ni número de ticket, ni fecha... solo cuando se pulsa 'aceptar' el carrito d ela compra.. es decir esa ventana debería tener al menos estos 3 botones:
Aceptar, Cancelar y eliminar el/los items seleccionados del carrito de la compra
- Si se pulsa cancelar: se pide confirmación y si se confirma se vacía el listado.
- Si se pulsa eliminar items: se pide confirmación para eliminar los 'selectedcount' items... y si se confirma, se borran empezando desde el final del listado hacia el primero cada item seleccionado.
- Si se pulsa aceptar, entonces se fija la fecha de 'ahora' y se toma el idLote, y se envía a guardar los articulos en el listado, cada idCompra se genera al guardar el registro, pero idLote se debe pasar ya el mismo para todos esos artículos.

Lo que resta, es (cuando se solicite) volver a cargar el lote comprado... a decir verdad, interesaría que el listadod e compras, fuera diferenciando cada lote con un color de fondo distinto, algo que un listbox no permite, por eso decía que para listas complejas, es preferible un control tipo 'grid' (flexGrid), que admeás contiene columnas y permite ordenar por columnas automáticamente.
Lo que cambia sobretodo en este listado,  es que el lote al tratarse de una compra 'atómica', y tener todos sus artículos comprados misma fecha, mismo idLote y mismo metodo de compra, no s epermitirá eliminar un solo artículo del lote, o se elimina todo el lote o nada, pero no artículos sueltos del lote.

Con todo es preferible el método para lotes de varios ficheros, pero empieza por modificar solo para usar un fichero único y más adelante haces copia del proyecto y lo modificas para tener varios ficheros...


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 17 Diciembre 2021, 22:02 pm
hola  serapis

es justo lo que necesito, guardar la informacion y leerla, si me pudiese hacer un ejemplo seria lo suyo, porque asi se ve la manera de trabajar con dos end type, el primero seria la entrada de los articulos, osea la grabacion, y el segundo end type seria leer la compra de la informacion, gracias.


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 18 Diciembre 2021, 01:43 am
Hola.
Ayer no tuve tiempo de hacer nada, hoy (viernes), si qué el justo para copiar el proyecto y empezar a modificar... es casi empezar desde cero. Mañana en otro ratito lo completo... no estará probado (al menos a fondo, seguramente si pruebe lo esencial), porque me llevaría más tiempo del que le quiero dedicar... así que correrá de tu cuenta corregir los errores que se me hubieren colado. Eso sí, si te surge un problema que no consigues localizar, detalla el problema y reviso la causa del problema.

Es muy, muy importante, antes de meterse en un proyecto (incluso aunque sea un ejercicio), tener una especificación (aunque sea en prosa y no en pseudocódigo) de lo que se va a hacer, precisamente para evitar eso... un cambio tan profundo, que todo lo anterior prácticamente no sirva para nada. Empezar de cero hubiera sido más corto que modificarlo todo, peor he preferido modificarlo para guardar consistencia dentro de lo posible con lo previo (mantener nombres, orden de cosas, etc...), para que sea más aseqible entenderlo conforme a lo ya tratado (la memoria ayudará en eso).

Siempre hay cambios que hacer, cosas de última hora o elecciones particualres por preferencias, conveniencias o inconvenientes, pero cuando los cambios adectan toda la estructura del programa, es más fácil empezar desde cero, y eso, sí hay que tratar de evitarlo, porque entonces es tiempo perdido todo lo que se hizo previamente.


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 19 Diciembre 2021, 19:25 pm
Ufff.... cuanta pereza me ha dado... Rehacer desde cero las cosas es aburrido cuando pudo evitarse pensando un par de minutos antes de ponerse a escribir ni una sola línea de código, que e slo que quiere hacerse...

No he probado todo, cosas como guardar el carrito a fichero y recuperarlo (ante un cierre inesperado), o eliminar un lote no lo he probado. Los errores que pudiera haber te toca corregirlo.

Descarga del ZIP con todo el proyecto:
https://workupload.com/file/CBPxfcwTLuE (148kb. aprox. el peso se debe sobre todo a las 3 capturas de imagen, que olvidé sacar de la carpeta.. como tampoco sobrna las dejo).

He dejado también el fichero de factura de ejemplo e el zip.
He aprovechado para poner los botones con colores.
Un vistazo de como se ve...
(https://i.ibb.co/b7jShhz/Facturaci-n-00.png)

Como se puede apreciar, la ventana de comprar ahora carece de ciertos textbox (como la fecha), que se pasan al carrito de la compra.
En el carrito de la compra se van recofgiendo los artículos comprados, juntos forman un mismo lote que se pagan de una única vez, por ello, campos como a fecha y método de pago y número de lote, se asocian con todos los artículos ahí comprados de una vez.
Puede seleccionarse algún artículo y elimarse de ahí, antes de pagar (no está probado ese botón).
(https://i.ibb.co/ZfSZ6zK/Facturaci-n-01.png)

La ventana principal, ahora dispone de más posiibilidades de sumar totales... puede solicitarse para todos los pedidos o solo para un pedido (el seleccionado), cuya suma se muestra a la derecha.
La suma total, además de mostrar las sumas de 'al contado' y 'con tarjeta de crédito', tambien suma el total de ambos.
Además se ha provisto una función para formatear los valores y así poder proporcionar más vistosidad...
(https://i.ibb.co/7v52gSG/Facturaci-n-02.png)

Tendrás que mirar a fondo el proyecto, modificar lo que quieras. Igualmente la opción de imprimir factura queda a tu esfuerzo, así como porbar o corregir cualquier detalle que no funcione como se espere... no me apetece repasar a fondo que todo funciona bien... algo tendrás que hacer tú también. Si me he asegurado al menos que  comprar artículos, añadirlos al carrito, y guardarloa fichero y leerlo de fichero, esté correcto.



Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 19 Diciembre 2021, 21:00 pm
Hola Serapis

lo mirare mas a fondo ya te digo que es lo que necesitaba muchisimas gracias

con aplicaciones asin , visual basic 6.0 no esta caido todavia, se pueden hacer muchas cosas.


muchas gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 19 Diciembre 2021, 23:58 pm
...es el 'patito feo' de la programación. El caso es que es el lenguaje que más adeptos ha tenido en el mundo... allá por el 200 eran muchos millones... probablemente pase mucho tiempo antes que otro lenguaje adquiera esas cifras (y que no sea metido con martillo en la Universidad, sino basado en el boca a boca entre sus usuarios).

Yo lo adoro con la misma intensidad que lo odio.
A favor tiene la virtud de lo rápido que puedes desarrollar casi cualquier cosa...
En contra tiene, las severas limitaciones que posee en determinadas áreas (muchos suelen suplirlas tirando de APIs, pero a mi me gusta usar solo cuando es imprescindible o cuando la solución en vb6 es enormemente más trabajosa).

Muchos lo han criticado incluso por cuestiones que son falsas (como que es un lenguaje interpretado, mal informados supongo que por la herencia del BASIC (de los 80 reflejado en los ordenadores Spectrum, Commodore, etc...), que en versiones previas si lo fue y al principio fue también compilado). Esos mismos que veían una enorme desventaja en los lenguajes interpretados y la lentitud asociada, ahora no lo tienen en cuenta cuando hablan de Python (por ejemplo).

En cualquier caso, un lenguaje muere cuando el último programador (que lo usaba) deja de usarlo...


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 22 Diciembre 2021, 13:38 pm
Hola serapis

se que me vas ha enviar al carajo

faltaria arreglar lo de buscar articulo y eliminar registro por lote.  he probado varias cosas y no me ha funcionado

gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 22 Diciembre 2021, 16:02 pm
Bueno... tengo vacaciones ya hasta después de año nuevo, aunque ya me han buscado tareas en casa  :-X para mantenerme 'ocupado'... miraré de echarle un ojo mañana, hoy ya lo tengo cubierto.


Título: Re: Guardar list2 y leer list1
Publicado por: BlackZeroX en 23 Diciembre 2021, 05:36 am
Esto quedaría mejor usando una capa de persistencia que implementara SQL Lite...

https://github.com/RobbiNespu/VB6-Sqlite3 (https://github.com/RobbiNespu/VB6-Sqlite3)

Me suena a mucho usar el patrón Command (Cada operación a SQLLite una entidad Command esto para ejecutar SQL y convertir los datos a Estructuras o viceversa) junto al Chain of responsibility [Opcional]...

Te recomiendo usar patrones de desarrollo para que este tipo de adaptaciones te resulten a futuro de fácil mantenimiento.

https://profile.es/blog/patrones-de-diseno-de-software/ (https://profile.es/blog/patrones-de-diseno-de-software/)

Las operaciones para guardar datos en archivos es siempre mejor SQL-Lite que usar archivos en formatos planos... a la larga es tedioso e imaginate antes cuando no existía el SSD la latencia era peor.

Saludos.


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 23 Diciembre 2021, 22:41 pm
Esto quedaría mejor usando una capa de persistencia que implementara SQL Lite...
Por supuesto...

Pero es un usuario que esta empezando, aprendiendo. Si no sabe usar ficheros, me temo que una base de datos mucho menos.
Antes de aprender a correr, debe uno aprender a andar (tropezarse, caer y levantarse)...

Más que nada, busca aprender, no tener un código optimizado. Pasar de un código espagueti a uno estructurado, es un paso que debe dar, fijándose, repitiendo y cuando adquiera un poco de soltura ya profundizará.


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 26 Diciembre 2021, 15:39 pm
He sacado un rato hoy para completar lo que faltaba...
...eran pequeños detalles, por ejemplo al buscar artículos, requería eliminar los espacios al ser una cadena de longitud fija los caracteres faltantes son espacios, y al ingresar el texto de búsqueda, uno nunca añade tales espacios... etc, etc...

He añadido de paso la posibilidad de búsqueda parcial usando patrones. En el código  como comentario he dejado algún ejemplo (si mal no recuerdo).

Y pequeños cambios, como añadir un 0 más a los decimales cuando totaliza (para que no redondeee a solo 2 decimales), etc...

Descarga (esta vez me acordé de apartar las imagenes):
https://workupload.com/file/mg4XLfn97CN  (aprox. 27kb)



Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 26 Diciembre 2021, 16:51 pm
muchas gracias serapis

ahora solo faltaria hacer el formulario de venta con list1 y con numero de factura, solo te pido si me pudieses hacer el control de numero de factura consecutivo desde 1 hasta  infinito con archivo guadar  ya seria mucho.

muchas gracias
 

 feliz navidad y un prospero año nuevo 2022


javascript:void(0);


Título: Re: Guardar list2 y leer list1
Publicado por: BlackZeroX en 27 Diciembre 2021, 05:46 am
Por supuesto...

Pero es un usuario que esta empezando, aprendiendo. Si no sabe usar ficheros, me temo que una base de datos mucho menos.
Antes de aprender a correr, debe uno aprender a andar (tropezarse, caer y levantarse)...

Más que nada, busca aprender, no tener un código optimizado. Pasar de un código espagueti a uno estructurado, es un paso que debe dar, fijándose, repitiendo y cuando adquiera un poco de soltura ya profundizará.

He sacado un rato hoy para completar lo que faltaba...

solo te pido si me pudieses hacer el control de numero de factura consecutivo desde 1 hasta  infinito con archivo guadar  ya seria mucho.

@Serapis
mmm... sin comentarios, yo antes hacia lo mismo que tu.

Solo algo que llegue ver de forma profesional:

Sea el lenguaje que sea note que mas del 80% de los desarrolladores con los que conocí (chavos/jóvenes/señores ya sea que tengan MAESTRIA/DOCTORADO o solo licenciatura), tienen en su mayoría bastante tiempo (Yo era uno de ellos) y no usan patrones es mas cuando tienen que cambiar una regla de negocio afectan a varios elementos pues no existe un patrón del mismo, sus pruebas unitarias son repetitivas, muchos de ellos le corren (detestan) a los patrones pues no los comprenden o no los conocen.

Si hay que Gatear/Pararse/Caminar/Correr que sea guiado.

Saludos.


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 27 Diciembre 2021, 11:46 am
@Serapis
mmm... sin comentarios, yo antes hacia lo mismo que tu.
:huh: No sé a qué te refieres exactamente... Si es por poner algo de código, no acostumbro a hacerlo, casi siempre pongo las explicaciones pertienentes y pseudocódigo. Peor cuando veo código espagueti, entiendo que el interesado no tiene la ayuda necesaria para avanzar...

Nadie discute que para viajar lejos, el avión el barco o un tren, lo hacen más barato.
Y para desplazamientos cercanos, un autobús o el metro también lo son.
...pero a pesar de todo eso, la gente sigue prefiriendo usar su propio vehículo, cuando puede incluso a pesar de que le salga algo más caro (viajar y manetener el vehículo), porque al final esos medios de transporte tienen 'paradas' y con tu vehículo, vas exactamente al punto donde necesitas (aunque luego en la práctica hay que aparcar donde haya espacio y por tanto toque andar lo mismo que si se hubiere usado el bus), y sobretodo con los horarios que quieras, sin depender de si, ya no hay buses o si el siguiente tardará 30 minutos en pasar...
Mira a tu alrededor y verás que al final sea con bici, monopatín, ciclomotor o coche (carro), la gente prefiere su propio vehículo casi siempre a un medio colectivo.

Hay un orden en las cosas... las bases de datos están al final del aprendizaje (de hecho jamás recomendaría SQLLite, sino SQLServer)... al comienzo los ficheros de texto, e incluso en ese punto, los de acceso secuencial y acceso aleatorio.
Cuando tenga la experiencia necesaria, es de esperar que avance. Saltar de la nada a las bases de datos, solo sirve para tener una nebulosa de como las cosas se hacen por debajo...

Me parece que lo interesante para Corlo, más incluso que resolver su problema con este ejercicio, es que acabe de entender la diferencia entre el código espagueti y un código organizado (ni siquiera le propongo utilizar clases), suele conseguirse con algo de paciencia, cuando comparan, acabarán por notar una diferencia por el contraste. Justo cuando hay un contraste entre el modo de hacer hasta ahora y el modo en que se ve algo (reciente o no), es cuando la gente tiene la oportunidad de avanzar (más rápido).

En cualquier caso, el hilo no va sobre filosofía del aprendizaje. Que cada cual se remita a lo que su interior le dicte, incluso creyendose en posesión de la verdad o del error, pues al final es sólo su tiempo (y no el de otro) lo que hay en juego.


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 27 Diciembre 2021, 13:13 pm
Hola serapis

solo seria un codigo para controlar el numero de factura para guardarlo en archivo

en un text1.text numero de factura y un list1 y guardarlo, solo el numero de factura

como toda la informacion esta guardado en un archivo, yo antes lo hacia en dos archivos, uno en guardar el indice y el otro guardaba los demas items.


Gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 27 Diciembre 2021, 13:22 pm
ahora solo faltaria hacer el formulario de venta con list1 y con numero de factura, solo te pido si me pudieses hacer el control de numero de factura consecutivo desde 1 hasta  infinito con archivo guadar  ya seria mucho.
Venía a decirte que como ejercició está bien y hasta ahí, y que resolverte cada addedum solicitado, al final, acaba pareciendo más una tarea que un ejercicio.

Nota que, una vez más la asuencia de una especificación inicila y clara, obliga a cambiar cosas que se daban por 'definitivas', más aún se observa en la nueva petición que hay cosas en el aire, detalles ambiguos que al resolverlos uno debe decidirse por un lado, sin saber si luego será por el otro, y por tanto trabajo en vano.

Te comento por encima para que entiendas la diferencia de cosas y el problema de tirar al vuelo código sin una especificación.
Como mínimo esta debe estar perfectamente clara en tu mente (pero es algo que solo se adquiere con el tiempo), si no te entretienes a detallarla en papel o en un fichero... La ventaja del papel es que puedes mezclar texto y garabatos de forma rápida, guardaro en el bolsillo y llevártelo donde sea, que al momento que surja otra idea, puedes añadirla o modificar la previa. Así y todo al final procede pasarlo a un fichero, dejándolo libre de polvo y paja (tachones e ideas rechazadas)...
Antes de ponerte a escribir una sola línea de código, debes tener clara la especificación del problema a atacar. Si es simple, como digo puedes mantenerlo completamente en tu mente y hacer un esqueleto del mismo (en pseudocódigo), analizar alternativas y decidir según los objetivos perseguidos...


Añadir una ventana de ventas, implica todo esto:
- Añadir artículos a la venta. La que ahora es la 'ventana de compra', pasaría a ser esa de 'ventana de entrada de artículos'.
- Comprar artículos. Ahora la ventana de compra en vez de la actual de compra, sería la 'ventana de ventas', donde el vendedor expone todos sus artículos a la venta. Que igualmente con cada compra se pasarían al 'carrito de la compra' donde finalmente se acepta o se rechazan.
- Comprar un artículo definitivamente, debería reducir el 'stock' en venta. Por lo que esa 'ventana de artículos', debe al mismo tiempo añadir un campo con el concepto de 'stock disponible', y la 'ventana de entrada de artículos', debe modificarse, la cantidad (que antes implicaba la cantidad comprada), ahora indicaría la cantidad en stock disponible... El subtotal en este caso también cambiaría pues vendría a indicar el precio total del coste al proveedor. Además en esa misma ventana habría que poner otro precio, el de 'precio al cliente', pués el precio que ahí consta podría bien reflejar el precio al que el vendedor lo compró al proveedor.
- Si hay una ventana de ventas, es claro que habrá más de un cliente, pues el proyecto ahora mismo se aproxima más a uno para llevar control de sus propias compras, es decir un solo comprador (tú), administrando tus compras de aquí y allá. Una ventana de ventas, se aproxima más a la vista dle vendedor. En este caso hay más de una opción... ----- Se trata de (por ejemplo) una tienda de ropa?. Donde aunque solo hay un único vendedor (la tienda en sí), se personifica en cada empleado que atiende en la caja registradora... luego pueden considerarse varios vendedores. si miras tus tickets de compra de supermercados típicamente al final en la  impresión de la factura verás el típico: "Le atendió Patricia".
----- Se trata de una plataforma de ventas (por ejemplo amazon, eBay). Donde cada venddor no tiene nada que ver con otro vendedor.
En ambos casos, interesa hacer constar la referencia del vendedor (el nombre o Id del vendedor en el caso del primeor y el Id o alias en e l caso del segundo). Sin embargo una diferencia entre ambos, modos es que el el primero no requiere una identificación (login) de usuario, ni por tanto una cuenta registrada a su nombre. El usuario accede a la tienda, compra, paga y se va con sus artículos comprados. En el segundo caso, el usuario para poder comprar debe estar registrado (aunque puede comprar y añadir compras al carrito, a la hora de pagar, se le exigirán las credenciales.

También una ventana de ventas, supone una factura por (lote), por cada comprador. Antes la ventana de compras, acuñaba el id de compras y artículo a medida que estos eran comprados... (por que es una facturación de 'compras' es decir para uso privado del comprador), ahora esos ids, cambian el momento de ser creados. El de artículo debe acuñarse cuando el vendedor añade sus artículos al stock y el de lote, cuando el comrador lo adquiere y deben acompañar.

Luego una 'ventana de ventas' (ventana de artículos en venta), exige otra 'ventana de artículos vendidos' para poder despachar las ventas. Si se trata del segundo caso, debe llevar el campo id o alias del comprador, que además estará asociado con un registor en otro fichero con sus datos (para el envio). Aquí además entra en conflicto la concurrencia de eventos... del tipo: qué pasa si mientras un comprador mete un artículo en su carrito, y le pulsa pagar pasa el tiempo suficiente tal que otro comprador haya adquirido el mismo artículo y por tanto ya no esté en stock, o lo esté pero no en la cantidad solicitada por el comprador?. Exige implementar un sistema eficaz de algún tipo de bloqueo, o bien comprobar en el momento exacto del pago artículo por artículo si aún están en stock. Sea el método elegido que sea, debe ser lo más flexible posible para que la experiencia del comprador no sea 'desagradable' y descarte comprar de nuevo en 'ese sitio' por su mala gestión del stock'.

Igualmente la que ahora es la ventana de compras, lo sería para cada comprador, pero debería adaptarse al caso concreto de cada tipo de 'venta' comentado (hay más opciones pero son los dos casos generales).

En segun que condiciones, puede interesar que cada lote comprado sea un fichero señalando en tal caso como nombre de fichero el id del lote. Al caso tales ficheros tendrían dos registros distintos. el primero es un resumen de la compra: Cantidad de artículos comprados, fecha, numero de lote (que coincidirá con el nombre dle fichero), e id o alias del comprador (si procede) y el monto total de la compra. Y le siguen los registros de compra de cada artículo.
Esto simplificaría enormemente la 'ventana de articulos vendidos', pues la lista, contendría (imprescindible tan solo) los IdLote y puede que cualquier otro campo más, como montototal de la venta del lote, o la fecha, etc.. y si es extenso, contendría justamente la linea completa del registor dle lote que ecabeza cada fichero (aunque lo veo excesivo)... al pulsar en una línea de esa lista, se leería el lote y se presentarían sus detalles debajo de esa lista o en una ventana aparte.

Hablando de ventas, también procede una búsqueda por 'comprador' (dando su Id, o alias). Igualmente si se trata de una plataforma de ventas, donde cada comprador puede hacer compras a distintos vendedores, procede hacer búsquedas por id o alias de vendedor. No en cambio si el tipo de ventas es de un solo vendedor y los 'vendedores' son solo los empelados capacitdo para manejar la terminal de ventas. Aunque incluso así, el propio vendedor (la tiemda), podría querer consultar la ventas que ha realizado al cabo del mes cada uno de sus empleados, en defintiva... con ventas las posibilidades se disparan y deben quedar previamente  definidas y acotadas.

Otra cuestión menor es por ejemplo, tratándose solamente de un facturación personal de compras (loq eu creía que tenías entre manos hasta ahora), usar Ids de tipo integer satisfacen la aplicación. Las compras en un mes para una persona a lo sumo serán unos pocos cientos...  pero para ventas, la cosa cambia... el número de compradores puede ser desconocido, luego un tipo 'integer' (2^15 en vb6), no es válido, debe ser al menos de tipo 'long' (2^31 en vb6).

Cuando el número de registors en un fichero es elevado (con compras por mes, no creo que suceda, peor sí con ventas por mes), los métodos de búsqueda secuencial, pierden todo interés por su ineficiencia (para unos cientos son válidos y más que aceptables a cambio de su simplicidad, pués una búsqueda representará en tiempo apenas un parpadeo), para más cantidades procede tirar de tablas hash, o ciertos tipos de árboles, pero son un tema más avanzado, para el que se precisa tener ciertos conocimientos mucho más sólidos en el lenguaje con que se opera.

En fin, tienes detalles suficientes para avanzar en cualquier dirección que quieras el proyecto (te aconsejo que lo guardes, copies y pegues y hagas las modificaciones en la nueva copia) y código en el que fijarte para construir lo que te falte y requieras. Como puedes leer son tantos detalles (solo he tomado algunos al vuelo, al pormenor son muchos más), que es inaceptable proceder sin una especificación bien detallada. El abanico de posibilidades se abre demasiado.

Cuando tomas un taxi, tu le dices a dónde vas, el taxista ya conoce la ruta más óptima sea en km. o en tiempo según el día de la semana, hora del día, etc... ahora si le dices... vamos al campo de fútbol y cuando llegas... ahora esa calle al final, luego cuando llega.. ahora gira a la izquierda y avanza hasta la segunda calle y luego... el taxista va a ciegas... a un taxista le dará igual si al final recorres 20km. o si tardas 30 minutos más, pues cobra por el tiempo, pero si desde un principio le explicas voy a tal sitio que está dentro de tal ciudad/barrio... a buen seguro sale más barato. Aquí pasa lo mismo, se va 'conduciendo a ciegas', pareces ir a un sitio, peor al llegar dices, 'No, ahora vamos a ese otro sitio'...

Lo que pretendo decirte, es que ...al final, no es la complejidad, pues se desgrana todo en un árbol de decisión y cada cosa con sus detalles queda recogida y puede ser adecuada y convenientemente implementada y además no se tarda tanto, es la falta de una especificación completa del sistema desde el punto uno... lo que impide dar una solución definitiva al tema.

Si un día llegas a vivir profesionalmente de esto, te darás cuenta que: los peores clientes, los que hay que evitar a toda costa, los que hay que reconocer desde un principio para decirles no o dejar claro todo desde un principio, es justamente el que opera de este modo, cambiando contínuamente cosas, que hacen que el tiempo empleado en parte de lo previo no sirva para nada, que los plazos se alargan y nunca se termina el proyecto y que en muchos casos intentarán mantener el precio inicial sin cambios, basado en su punto de vista porque 'son solo unos pequeños cambios'. Incluso aunque el presupuesto inicial fuera más que generoso, es fácil al final acabar perdiendo dinero, tiempo y puede que hasta la paciencia  :laugh: :laugh: :laugh:



Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 27 Diciembre 2021, 13:48 pm
Hola serapis

muchas gracias por todo he aprendido mucho contigo , gracias por la explicacion pero no quiero tantas cosas, ya iré avanzando poco a poco


de verdad muchas gracias


Título: Re: Guardar list2 y leer list1
Publicado por: BlackZeroX en 28 Diciembre 2021, 01:45 am
Venía a decirte que como ejercició está bien y hasta ahí, y que resolverte cada addedum solicitado, al final, acaba pareciendo más una tarea que un ejercicio.

Diste al clavo :)

Los siguiente ya es fuera del tema y es solo un consejo.

@Corlo

Te recomiendo antes de escribir código dibujarlo (boceto) y a un lado poner las acciones... que agrupes por tipo de elementos y acciones, posteriormente que las programes en modo micro, es decir solo ese fragmento de código después ya los unes y veras que es mas facil pensar en fragmentos que en un todo...

Cuando me refiero a tipo de acciones me refiero por ejemplo, tengo productos que acciones se puede hacer con los productos, tengo carritos que acciones se pueden hacer con estos... tengo clientes que acciones se pueden hacer con los clientes, etc... después cada uno de estos los metes a una cajita (llamese bas o clase cls) y posterior defines de todos estos cuales son los importantes y los plasmas en tu código (pero sin programarles todavía nada solo los declaras).

pj:

bas de productos
Código
  1.  
  2. public function cargarProductos() as productos()
  3.    rem sin código
  4. end function
  5.  
  6. public function buscarProducto(byval value as string) as Producto()
  7.    rem sin código
  8. end function
  9.  
  10. public function actualizarProducto(byval value as Producto) as boolean
  11.    rem sin código
  12. end function
  13.  
  14.  

bas de carritos
Código
  1.  
  2. public function crearCarrito() as Carrito
  3.    rem sin código
  4. end function
  5.  
  6. public function retomarCarrito(value as Long) as Carrito
  7.    rem sin código
  8. end function
  9.  
  10. public function cerrarCarrito(value as Carrito) as boolean
  11.    rem sin código
  12. end function
  13.  
  14. public function pagarCarrito(value as Carrito, totalPagado as Single, tipoPago as MetodoPago) as boolean
  15.    rem sin código
  16. end function
  17.  
  18.  

Después de que tengas estos pues ya se implementan en los Forms (frm).

Saludos.


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 13 Febrero 2022, 12:50 pm
Hola soy corlo

me faltaria pasar todos los articulos del archivo de compra compras.txt aumentar de precio por ejemplo 1.10  al archivo ventas,txt que seria el archivo de venta

necesito un ejemplo gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 13 Febrero 2022, 14:18 pm
No estoy seguro de habertye entendedido... enumero las preguntas:

1 - A productos ya comprados ¿quieres aumentarles el precio?. Que aumente el precio, solo tiene sentido para los nuevos artículos a la venta, nunca para los ya vendidos...
2 - ...y en tal caso, solo a x productos o a todos (a todos sería muy raro, a lo mejor lo dices solo por señalar un ejemplo sencillo de explicar).
3 - Y si son más de uno, no debería cada uno tener su propio precio de subida?
4 - O si es común no sería más acertado aplicar un porcentaje al precio actual de cada artículo que se quiera modificar?. en cualquier caso, es adecuado disponer las dos modalidades de actualización del precio. Incremento porcentual, incremento fijo.

También suele ser frecuente no solo el incremento, si no también la rebaja (ofertas) o descuento promocional.
La rebaja suele ser un valor porcentual aplicado a algunos artículos (cada uno el suyo), el descuento promocional suele ser un valor absoluto a descontar del total del monto al darse ciertas condiciones (por ejemplo, comprar cierto artículo, o superar cierto umbral mínimo de compra).
En la base de datos de los productos, suele ser útil por ello, disponer de un campo rebaja para cada campo, que en caso de no haber ofertas (las ofertas suelene limitarse a un plazo en el tiempo), su valor es 0%. en tanto que el descuento procional suele incluirse como campo en los registros de compra (y a veces también en los de artículos). Por lo mismo, ppprocede tener un campo en el registor de compra de 'descuentos totales', que se encarga de sumar los descuentos parciales.
Las cosas a veces se complican cuando hay descuentos no acumulables, o que se limitan de alguna manera (por ejemplo al comprar 3, pagar solo 2), etc, etc...

Es acertado mantener en un fichero aparte, los productos en stock, no solo sus cantidades, también sus precios vigentes y valores de rebaja, o porcentaje de impuestos aplicado al artículo)  de ese modo pueden ser editados en cualquier momento (creo recordar que hice una ventana para editar, pero no recuerdo ya que era exactamente lo que se podía editar). Lógicamente algo así (el precio de un artículo) que se puede editar, solo afecta a las nuevas compras, y jamás a las ya realizadas....

...hoy (después de comer) estaré el resto del día fuera, mañana saco un tiempito y reviso, pero mientras, responde y aclara esas preguntas.


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 13 Febrero 2022, 15:45 pm
Hola serapis

los productos si se aumentan por porcentaje en principio es para todos los productos y la rebaja lo mismo

y se pudiese hacer por incremento fijo, tanto por aumento como por rebaja

gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 17 Febrero 2022, 02:22 am
Guau... se me había olvidado por completo... Mañana a la tarde que llegue a casa saco un ratito.


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 19 Febrero 2022, 01:48 am
Hoy saqué un rato y pude dejar casi terminado, la parte que opera con el almacén y los artículos.

A ver si mañana o pasado saco otro ratito y hago la parte equivalente para las ofertas...

Sendas partes, requrirán de un fichero adicional que mantiene sus propios registros, también implica hacer cambios a alguna ventana. La ventana de compras, hasta ahora introducía artículos manualmente, luego tendrán que elegirse de un combo que contendrá todos los artículos del almacén.

Los cambios a posteriori, como ya te he dicho en varias ocasiones, fuerzan a modificar parte de lo ya hecho. Te recomiendo que consideres en adelante hacer un análisis de requisitos previo a escribir una sola línea de código, poder así diseñar como ha de ser la aplicación y que pártes se encargan de qué trabajos, so pena de estar modificandocontínuamente paertes que hacen un trabajo que en realidad pertenece a otra parte, cuando esa parte se integra, por que no se hizo en su momento.

Como siempre no está probado...


Aquí una captura (del IDE), de la ventana de edición de artículos...
(https://i.imgur.com/SAxyCPo.png)


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 21 Febrero 2022, 14:48 pm
perdon por tener que canviar tanto el codigo, el problema esta en que por el camino de la programacion hay algunas curvas bastante cerradas para poder ir solucionando las cosas. He
visto la captura que has puexto vas bien encaminado, recuerda que el precio por porcentaje va para todos los articulos, gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 22 Febrero 2022, 15:16 pm
El fin de semana al final recibí familia en casa y no me dejó tiempo libre, hoy seguramente pueda dedicarle una hora y con otra mañana será suficiente espero...

Los artículos pueden ser editados uno a uno en cualquiera de sus campos, pero también se ha previsto la opción de cambiar el precio a varios a la vez.

(https://i.imgur.com/K5xy8p0.png)


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 25 Febrero 2022, 17:28 pm
Hola serapis

¿como estas con la aplicacion?

necesito la aplicacion


gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 25 Febrero 2022, 23:16 pm
Me ha distraído la invasión de Ucrania y aparte, me he entretenido haciendo algunas cosas más... Al final son 7 ventanas más. 3 son principales, las otras son llamadas desde esas.

Me resta incluir la funcionalidad dentro de la aplicación, es decir su funcionalidad esta hecha aparte, ahora hay que integrarla en la aplicación para que sea plenamente funcional... no recuerdo si tendrá que remplazar a alguna parte o si puede convivir con el resto, sin cambios (toca repasar lo que había).

Aunque claramente la ventana de compra debe modificarse. Hasta ahora al comprar uno indicaba (se inventaba) el artículo a comprar y le ponía su precio, esa ventana ahora no podrá sino elegir un artículo de los que existen en el almacén y al elegirlo ya incorpora su precio y tal...

La ventana que no integraré en esa, es la de ofertas... requeriría dedicarle otro tiempito, quedará a tu esfuerzo.

...y probarlo, pero yo solo probaré lo básico... que el programa arranque y las diversas ventanas se abran sin fallos y se lean sus ficheros asociados... cualquier pequeño detalle erróneo te tocará buscarlo y corregirlo, incluído tooltips con texto que no corresponde (fruto de copiar y pegar sin adecuar el texto), etc..

(https://i.imgur.com/soGYgv8.png)


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 27 Febrero 2022, 22:17 pm
Hola serapis
como estas
perdona que sea tan pesado

necesito la aplicacion

gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 28 Febrero 2022, 03:07 am
Este fin de semana saque el tiempo justo para casi terminarlo.

A ver si entre mañana y pasado (lunes y martes) logro sacar 1-2 horas de tiempo para modificar la vieja ventana de compra de artículos... (integrar lo nuevo con lo viejo) y poder probar esa parte. Es todo lo que queda.

Así se ven, las ventanas de edición de ofertas y de artículos:

(https://i.imgur.com/5eRHN7F.png)


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 3 Marzo 2022, 19:44 pm
Hola Serapis

has podido acabar con la aplicacion

gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 4 Marzo 2022, 01:14 am
Sí, ya está terminado.

...pero he tenido que cambiar además todo lo previo, así que falta probarlo por encima al menos y corregir los pequeños errores que pueda haber. Cuando mezclas algo nuevo con algo previo, suele haber pequeños desajustes (sobre todo si son muchos cambios como es el caso) por cosas cuyos detalles no recuerdas con precisión... y que ahí acaban emergiendo.

Si tengo un rato mañana despues de comer y otro poco por la tarde, estará funcionando.


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 6 Marzo 2022, 01:36 am
Hola Corlo... lo terminé de probar el sábado por la mañana, pero he estaod todo el día fuera de casa...

Aquí la descarga, por si lo quieres ir probando:
https://workupload.com/file/9rRxdbcR2wv 76Kb. aprox. comprimido (incluye los ficheros  de ejemplo).

Mañana me edito y pongo algunas explicaciones con capturas, hoy ya es tarde por aquí.



Te explico por encima...
Al abrir la aplicación, ahora una ventana hace de la principal, desde ella se accede a las principales características de la aplicación. También muestra un resumen de las ofertas activas a modo de recordatorio.
Se puede aprovechar para poner un logo y personalizarlo más.

El menú muestra las 4 principales ventanas a las que acceder: cuando se pulsa se abre la ventana correcpondiente.
(https://i.imgur.com/nOrrIK4.png)

La aplicación funcionará correctamente cuando se introduzcan artículo al almacén.
La siguiente imagen muestra el listado de los artículos en el almacén.

(https://i.imgur.com/aNFoECm.png)

La columna 'stock', lleva la cuenta de la cantidad que queda de dicho artículo en el almacén, cuandos e compra, el stock se reduce en la cantidad comprada.
A la cantidad inicial que se establece como stock se le señala un porcentaje (columna umbral), tal que cuando en stock queda igual o menos de esa cantidad (columna pedido) ,  debería avisarse al departamento de compra-fabricación, para reponer el stock del almacén.

El menú precios tiene esa posibilidad que pedías de aumentar/reducir el precio a todos los artículos en una cantidad fija o porcentaje, pero a todos el mismo.
(https://i.imgur.com/IXEkbTO.png)
Desde el prpio menú, puede indicarse si se aplicará a todos o solo a los seleccionados.

Desde el menú 'Artículos' del almacén, puede crearse nuevo artículo o editar uno existente (clonar es crear uno nuevo partiendo de los datos del que actualmente tiene el foco).
También puede borrarse un artículo, pero esto solo debeiera usarse es circunstancias remotas, incluso introduciendo un artículo erróneo, puede luego ser editado, por lo que técnicamente no habría necesidad de eliminar ninguno.
Un modo de deshabilitar un artículo, por cualquier razón es poner su stock a 0, no aparecerá en los listados de compra noi oferta.
El almacén cuenta con un 'artículo vacío', que es el primero que se mostrará, para indicar al usuario que debe elegir uno de la lista.

Esta es la ventana de edición de los artículos:
(https://i.imgur.com/AXZqt4V.png)
En ella se establece el nombre del artículo, el precio de venta al público, el porcentaje de impuestos aplicados (se desglosa a la derecha), la cantidad en stock en el almacén y el porcentaje del mismo para su aviso (esto solo se establece cuando se crea el artículo pero también puede modificarse pulsando el checkbox), a su derecha señala la cantidad exacta mínima que una vez alcanzada o menor, debería dar aviso para el departamento de adquisiciones (compra, fabricación), también el valor en unidades, en el ejemplo siendo agua de 5 litros 5.000 cl, si es un paquete de yogures, 6, 8, si son huevos 6,12, etc... es decir la cantidad que trae lo que se compra.
Finalmente hay un aviso para señalas si el artículo está actualmente en oferta.

La sección de la derecha, no aparece cuando se crea un 'nuevo' artículo, solo al editar-clonar, por si se prefiere modificar ciertos precios en una cantidad igual a varios artículos, así se evitar la necesidad de calcular e introducir a mano el valor concreto.
Cuando se pulsa uno de los botones verde, se valida y cierra la ventana, tras lo que cual se reflejará en el lstado del almacén y en fichero.

La edición no debería utilizarse para cambiar el nombre del artículo, salvo un error tipográfico (es decir que refiera siempre al mismo artículo), de lo contrario al leer la facturación la próxima vez para el artículo con dicho código, reflejará el nuevo nombre que podría ser distinto a lo originalmente comprado. En cambio si puede modificarse el precio y descuentos, pués ambos valores son guardados a fichero cuando se compra, en tanto que para el artículo, en vez de guardar su nombre (20 caracteres), se guarda el código del artículo (2 bytes), que se rescata al leer la factura de compra.

Así se ve la ventana cuando se elige crear un nuevo artículo:
(https://i.imgur.com/UqZFcgk.png)

La siguiente ventana es para las 'promociones'.
Facilita crear ofertas. Establece una fecha y una duración vinculada a un nombre. Así cuando haya que crear ofertas para determinados artículos, bastará elegir la misma promoción para ellos, lo que ahorra por un lado escribir más dats y sobretodo elimina la posibilidad de errores, al poner fecha y/o duración de la oferta.
(https://i.imgur.com/OMuUnTt.png)

Nótese que estas se crean automáticamente al iniciar la aplicación (si no existe el fichero 'promociones...'), pero pueden ser editadas (para mantener la fecha y duración deseadas), así como poner el nombre que se considere más acorde, también pueden añadirse más promociones, que será la siguiente ventana a mostrar.

Aquí la ventana para crear una nueva promoción. No requiere más comentarios.
(https://i.imgur.com/EB4xOUO.png)

Aquí la ventana cuando se trata de editar la promoción. Como se ve, tampoco requiere más comentarios:
(https://i.imgur.com/QR7wwLy.png)

Esta, es la ventana del listado de ofertas. Como se ve, hay dos listados:
- El de ofertas activas (arriba)
- El de foertas inactivas (abajo)

(https://i.imgur.com/LFso18s.png)

Cuando se crean ofertas nuevas, van al listado de abajo (inactivas), igualmente para editar una oferta debe estar desactivada.
Las ofertas se activan o desactivan seleccionado en el listado las deseadas y yendo al menú elegir 'activar/desactivar', cada opción solo está activa en función del listado que se trate.

El objetivo de tener dos listados, es que no haya que crear nuevas ofertas ...cada vez... si no reutilizar las existentes, ya que lo que cambiará básicamente será la fecha, quizás la duración o tipos de ofertas.

Se ha diseñado 5 tipos de ofertas (aparte la inactiva), que cubre la mayoría de posibilidades. No obstante esto se explica mejor en la ventana de edición de las ofertas.
Algo importante es que no pueden activarse cualquier tipo de oferta, algunas son incompatibles con otras, las compatibles entre sí son los tipos 1,2 y 4, luego la 3 es aparte y  la 5 también aparte, es decir enel listado activo de ofertas solo puede haber ofertas compatibles... el programa se encarga de hacer la revisión y señalar el caso si no es posible.

Esta e sla ventana para crear nuevas ofertas (hay dos capturas, para mostrar el listado de combos, falta un tercero, que deja la imagen demasiado ancha y que se mostrará luego):
(https://i.imgur.com/JXXP2cJ.png)

Cada oferta se vincula a un artículo, como se ve en el combo a la derecha, debe elegirse un artículo de la lista deesplegable. La lista solo contendrá aquellos artículos cuyo stock no esté a 0.
Además cada oferta se vincula con un tipo de oferta... se han creado por defecto 5 (como son pocas y no hay posibilidad de que ese número aumente notablemente, no requiere fichero se cargan con la ventana por código).
Los tipos explicados someramente son:
0 - Inactiva: La oferta no está activa. Es lo nromal para ofertas que por ejemplo estén destinada a Navidad...
1 - Porcentural: Al artículo elegido se el aplica un porcentaje de descuento (que se indica).
2 - Sin impuestos: Como el anterior, pero el procentaje aplicado es exactamente el valor que tiene el artículo aplicado en impuestos.
3 - Sorteo: Esto no se aplica al artículo en sí, si no a toda la compra. Indica que al vencer las ofertas, se realizará un sorteo entre los que hayan comprado durante la vigencia de la oferta, 1 o más premiados se les devolverá íntegramente el valor de su compra. Se supone que podría haber una cantidad máxima, por ejemplo 500euros, si alguien hizo una compra por valor de 800 euros, solo se le devolverán 500, si el afortunado hizo una compra por valor de 63'87 euros esa es la cantidad que se le devuelve. La resolución de este tipo de oferta, no está implementada, ya que la forma de realizar el sorteo así como quienes participan y otros detalles, son demasiado amplios como para aventurar una solución que al final se vayaa descartar por completo.
4 - Gradual: El descuento aplicado es el típico '3x2', es decir esos donde dicen 'por cada x artículos que compres te regalamos 1', en el ejemplo compras 3 y pgas solo dos, ergo... e descuento es del 33'33%, lógicamente si uno compra 4, el descuento aplica a 3 de ellos luego paga 3, (el 4 no forma parte de ese descuento, precisaría comprar 6, para aplicar nuevamente ese desceunto).
5 - Abosluto: Este descuento, es por el total de la compra. Por ejemplo si se señala un valor de 50 euros, y se pone un descuento del 10%, aquellas compras cuyo valor total iguale o supere 50 euros se el aplica un 10% al total de la compra. Si compra vale menos de 50 euros, nos e aplica descuentos.

En la siguiente ventana termino de explicar el resto de la misma, pués se refiere a la edición de un registor de oferta ya creado (o clonado).
(https://i.imgur.com/l3SoaFR.png)

La edición de ofertas, como se ha dicho antes, solo se puede hacer desde el listaod de ofertas inactivas (ofertas que no están en vigor), para evitar trastocar ofertas que estén activas con las consecuencias de 'clientes finales con quejas'. Aún así si fuera preciso  por detectarse un error, puede desactivarse, editarse y volverse a activar.

Según el tipo de oferta elegido, el porcentaje así como el valor pueden estar o no activos.
En esta última ventana se puede ver desplegado el listado de la spromociones, la oferta se vincula con una promoción (el nombre), facilita elegir la asociación para más artículos de una fecha y duración. Ambos datos pueden ser cambiados individualmente para cada oferta, pero si no es deseable puede ser modificado para que muestren su valor como solo lectura. Recuerda que las promociones pueden modificarse desde la ventana del listado de promociones.

Cuando se elige desde el combo, el artículo, se rescata del alamcén sus valores y se señala su precio.
A la derecha d ela oferta, se mantiene el valor de la oferta previa que tenía esta oferta (el tipo de oferta al estar en el listado de inactivas, permanece siempre a 0, por tanto el valor elegido se mantiene en un campo que es copia, como si fuera temporal, cuando la oferta se activa, el tipo de oferta toma el valor que se retiene en este campo de copia.

Por su parte activar o desactivar una oferta, se refleja en el alamcén que mantiene un campo que lo vincula a una oferta. Solo puede ahber una oferta activa por cada artículo, pero puede haber diferentes ofertas inactivas para un mismo artículo siempre y cuando tengan distinta promoción (por ejemplo el vino puede estar en oferta inactiva para una promoción de Navidad y tener otra oferta inactiva para una oferta de verano y tener una oferta activa para la promoción de Semana Santa, en cambio no tiene sentido que ese vino (el artículo), tenga 2 ofertas activas distintas para 'Semana Santa'... el programa también se encarga de hacer tal revisión antes de activarlas...

En la imagen del almacén, puede verse a la derecha del todo que hay 3 artículos con ofertas activas.

Básicamente eso es todo lo nuevo en la aplicación, ahora los cambos a lo que había previamente (pues ha afectado a todo, ha sido finalmente necesario modificar absolutamente todo).

Esta que antes era la ventana principal ahora tiene el nombre de facturación:
(https://i.imgur.com/IWchzAF.png)

En un principio la aplicación suponía ser un ejemplo para ir aprendiendo, luego una aplicación real para mantener la propia compra de uno mismo, por lo que no hacía falta un almacén dada la inabarcable variedad de artículos que uno puede comprar, (libros, CDs, ordenador, teléfono, tablet, gasolina, manzanas, tabaco, etc...), luego en esa suposición lo pertienente era introducir manualmente el nombre del artículo comprado y el precio pagado y no mucho más... al final parece ser la aplicación real para una pequeña tienda de tipo familiar, puesto que ahora hay necesidad de hacer ofertas y tal, se hizo preciso un almacén que detalle cada artículo a la venta en sus valores esenciales (como tal, para mi sigue siendo un ejemplo del que puedas aprender).

Como se ve en la imagen, ahora la ventana de facturación se compone de dos listados... en el superior se muestran las compras únicas, y debajo se detallan los artículos asociados a una compra dada.

Cuando se pulsa en una compra (listado superior), se rescatan los registros de artículos asociados al lote de la compra. Ahora sí, cada compra mantiene el total de la compra, así como el descuento aplicaod a la compra (siempre 0, salvo esos casos de ofertas de tipo 'absoluto' (descuento al total de la compra si superan cierto volumen).

En la última compra se ha puesto exprofeso un ejemplo de ese caso, el valor debia ser superior a 50 euros para aplicar un descuento dle 10%.
A la derecha dle listado, la suma d elos totales de lo facturado.

Por suparte el listado inferior, como se ha indicado desglosa los artículos comprados en ese lote (ticket de compra).

El carrito de la compra, no tiene cambios sustanciales en la interfaz, pero sí internamente, el listado es básicamente lo mismo que el listado inferior, excepto los dos campos de códigos de la izquierda:
(https://i.imgur.com/j9kEqB1.png)

Como se ve, el cambio más importante (aunque aquí se muestre vacío), es el campo 'descuento' que que se actualiza (si procede) con cada artículo añadido al carrito.
El mayor cambio en esta ventana (así reseñable), en que justo antes de pagar, se vuelve de nuevo a revisar si el artículo tiene stock suficiente en el almacén para comprarlo en las cantidad requeridas... algo necesario, dado que el carrito d ela compra puede estar bastante tiempo abierto... y alguien podría haber comprado las existencias restantes. En tal caso avisa antes de proceder al pago, permite eliminar ese artículo o anular toda la compra...

Cuando se realiza el pedido (se ha validado que existen en stock las cantidades que se quierne comprar),  se reduce el stock en el almacén en tales cantidades... Se ha añadido a proposito el último artículo con poca cantidad en stock, para probar que cuando se quiera comprar más d elo que hay en stock, avisa y que si llega a 0, ya no se liste (cuando esto ocurre fuerza a recargar los listados que mantienen los artículos). Estas partes no han sido probadas, creo recordar...

El carrito de la compra, se abre tanto desde la ventana de facturación como desde la misma ventana de compra, que se presenta a continuación:
(https://i.imgur.com/I6tOOFw.png)

Esa es la ventana de compra, como se ve, la principal diferencia respecto de la previa es que ahora el artículo no se introduce manualmente, si no que es elegible entre el listado de artículos con existencias en el almacén. Y como ya en el alamcén se reflejan sus valore,s ahí simplemente se hace constar sus valores (previo, impuestos aplicados, etc..., tampoco hubiera sobrado indicar el remanente en stock, así sabe si está tratando de comprar mas de lo que puede venderse).

Desde luego la lista se carga con todos los artículos cuya existencia  sea superior a 1, ignorando los artículo cuyo stock sea 0.

Básicamente aunque la interfaz se ha simplificado al extremo (solo hay que elegir el artículo y la cantidad a comprar), el código ha requerido un cambio profundo.

Cuando se pulsa el botón añadir al carrito, verifica si la cantidad existe en stock, si no es el caso avisa para poder cambiar la cantidad... como ya dije esta comprobación se realiza de nuevo cuando se acepta pagar el lote desde el carrito de la compra.

La úlitma venta (la de elegir un fichero de facturación para abrir), a pesar de que solo tiene unas decenas de líneas también tuvo que ser ligeramente modificada, pués antes el programa solo mantenía un unico fichero (el de facturación.dat) y si procedía el caso el de 'carrito.'dat (si se cerraba la aplicación con un carrito sin procesar (comprar)), ahora el de facturación se ha desglosado en dos ficheros, el de los lotes comprados y de cada artículo comprado que se asocian con el lote comprado...
El almacén, ofertas y promociones tambié se mantienen en sus propio ficheros, al final son 6 (más el del carrito que es creado y eliminado, es decir es transitorio), entonces excepto de lote cuya extensión es *.dat', para los demás se ha elegido como extensión 'regdata', así esa ventana de selección del fichero de facturación no tiene posibilidad de elegir un fichero que no contiene los registros esperados y por tanto también evita malograrlos, toda vez que no se realiza ninguna comprbación sobre los ficheros mas que abrir el fichero de nombre elegido.


Sobre los ficheros hay que decir además, que los ficheros son creados y existe una única copia de ellos, excepto para el de facturación (que se crean 2 por cada facturación creada).

Una pequeña tienda familiar o de barrio, suele tener a lo smo unos pocos cientos de artículos a la venta, así una aplicación como esta puede ser perfectamente suficiente, aunque no sea óptima (se ha diseñado e implementado con el objetivo en mente de aprender a solucionar casos típicos), para eficiencia, como mínimo deberían usarse clases y tirar de colecciones basadas en hash, al final hay muchas búsquedas que pueden requerir un recorrido secuencial, que para unos pocos cientos es casi inmediato, peor  que basada en hashes, permitiria multplicar el tamaño de las colecciones por 1000 y ser aún 10-100 veces más rápido aún que esta solución.

La implementación con colecciones basada en hashes requiere conocimientos sólidos de programación y del lenguej usado, si no es el caso, entonces lo preferible es tirar de nases de datos que ya implementan tales colecciones por uno mismo... en ese caso se reqiere un conocimieto más o menos sólido de la base de datos usar... para VB6, las bases de datos Access, son bastante asequibles y su rendimeito adecuado, para algo más profesional recomiendo SQL-Server, Oracle, etc... Estas bases de datos son mucho más complejas y exigen más conocimientos del programador, aunque para aplicaciones de pequeñas empresas, no se requiere tanto.

La ventaja de una aplicación diseñada al 100% con código propio, es que es independiente de cambios a posteirori de versioes que con el tiempo arroja incompatibilidades, la otra ventaja es que contrlas al 100%, lo que quieres hacer, según lo que necesites sin apenas restricciones, si bien VB6, no arroja la adecuada capacidad de creación de tipos como por ejemplo oferce ADA o incluso Pascal... se podrá ver en el código como para poder operar con valores con 2-3 decimales hay que hacer 'tontarías' que con un acertado posiblidades de tipos, sería inecesario.

La otra gran desventaja de escribir todo el código es que es más lento al tener que escribir todo en vez de delgar en librerías quye ya hacen tal o cual cosa.
Por ejemplo, podría delegarse los textbox numéricos en controles de usuario diseñados específicamente para tener cierta funconalidad integrada (por ejemplo, porcentajes, donde muestran 3 textbox, el del valor sin el porcentaje, el del porcentaje y el dle valor una vez aplicado el procentaje y que modificando uno solo de ellos, los otros dos se actualicen en base a ello, u otro contro de usuario para mantener justo esa cantidad de dimales que uno quiere sin estar cada vez haciendoese parsing estúpido... o incluso un control con un calendario para elegir la fecha de las promociones y ofertas, forzando así a que las fechas sean siempre a presente o futuro, en vez de tirar de un simple 'now' o un textbox, donde existe la posibilidad de meter una fecha errónea, ahora bien aunque VB dispone de control de calendario, exige entonces instalar tal librería si el cliente no la tiene, la propia librería es de más tamaño que la propia aplicación... tengo por ahí algún control de usuario que es un calendario, pero igualmente es añadir 70kb. y si tuviera que quitarle funcionalidad para hacerlo más simple y ligero, llevaría bastante tiempo asegurarse que lo eliminado no trastoca la funcionalidad residente. ...igualmente por lo mismo abordar otros controles, no procede dado el tiempo disponible y las prisas que pueda tene rel cliente.

En cualquier caso, tienes ahí lo suficiente para modificar a tus necesidades y crear nueva funcionalidad basada en las soluciones dadas... por ejemplo, imagina que te solicitan que crees categorías de artículos y ahora todas las que son de la categoría de bebidas alcohólicas see les aplique un descuento del 10%, en vez de aplicar ofertas artículo por artículo...

...aunque por experiencia ya te digo que si ofreces la capacidad de hacer ofertas por categorías,  siempre habrá artículos que no quieran incluir (a pesar de estar en la categoría) y artículos que sin ser de esa categoría quieran incluir... ...lo que al final supone ser la capacidad para que cada artículo pueda tener su propia oferta (es la solución al aque finalmente 'por tanteo', con nuevas exisgencias se llega, pero sin dejarlo jamás así de claro descrito).

Así las categorías, podían ser simplemente colección de códigos de artículos, es decir un registro con un nombre de categoría al que se asocian x artículos (x códigos de artículos)... asociar un artículo a  una categoría implicaría eliminarlo de la previa, y en el almacén debería aparecer un codigo de categoría (en los registros se han previsto y dejado campos reservados para permitir cierta flexibilidad de ampliación sin cambiar los propios ficheros). La funcionalidad prevista para las categorías sería pues:
- Añadir-editar-clonar categoría
- Añadir artículos (existentes en el almacén), a dicha cetegoría (exige quitarlo d ela categoría previa si estuieran en otra que no fuera 0 (0=sin categoría definida).
- Ofertar los artículos enla categoría 'x'.
...etc...

Por último, como esto ya pasa de ser un mero ejemplo e incluso de un proyecto personal, cualquier cosa que requieras a futuro, irá solo en explicaciones, le habré dedicado unos 30 o 40 minutos de la mitad de estos días, lo que pueden ser unas 8-10 horas, que es más tiempo del que uno quiere ofrecer como ayuda, aunque 30 ó 40 minutos al día no sea mucho, es más de lo que uno espera cuando requiere varios días...

Saludos.


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 6 Marzo 2022, 20:03 pm
Hola Serapis

ante todo muchisimas gracias ya lo he mirado por encima en principio funciona bien ya mirare con mas calma los detalles, es genial, para una aplicacion pequeña ya es suficiente no hace falta trabajar con bases de datos, con bases de datos el codigo de programacion es bastante diferente al de los archivos directos secuenciales. y a veces hay fallos de conectar con la base de datos cuando cambias de carpeta y la ruta ya no es la misma. Tiene que canbiar la ruta de la base otra vez, en cambio en los archivos directos secuenciales no pasa.

muchisinas gracias Serapis


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 10 Marzo 2022, 19:05 pm
Hola Serapis

la aplicacion va muy bien solamente faltaria una cosa
en el formulario de facturacion poner una opcion de Guardar Factura con numero de facturacion y la opcion de leer con numero de factura

muchas gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 11 Marzo 2022, 22:09 pm
faltaria una cosa en el formulario de facturacion poner una opcion de Guardar Factura con numero de facturacion y la opcion de leer con numero de factura
No entiendo...

1 - Las facturas se pueden ver en el listado superior.
2 - El número de factura aparece en la columna 'Lote' (campo IdPedido de la estructura 'RegLote').
3 - Como las facturas una vez creadas, ni se modifican ni se eliminan, en el listado superior aparecen ordenadas por número de facturación (campo IdPedido de la estructura)-.
4 - Estando ordenadas por dicho valor, es relativamente fácil localizarla en la lista, seleccionarla y acto seguido se leen los artículos comprados con esa factura y en el listado de abajo se detalla.

Tomando la imagen de más arriba y pegándola de nuevo aquí, puedes ver que el número de factura es el 2. se compraron 7 artículos  en ese lote, que s elistan debajo que admeás tienen su propio número de compra (que no de factura), que van del 5 al 11 (columna compra, campo IdCompra de la estructura 'RegCarrito')...

(https://i.imgur.com/IWchzAF.png)

Quizás te refieras a otra cosa y por ello no termine de entenderte.


p.d.: El id de facturación aunque empieza en 1, pero es fácil de modificar...

Para ello, cuando se crea la nueva facturación, si es preciso puedes solicitar el número de facturación inicial, con un imputbox (lo mismo que se solicita el nombre del fichero), adjunto una imagen con el escaso código a añadir... en el ejemplo se supone que la primera factura en el fichero ha de tener el número 133 (en el código se resta 1, porque cuando se hace la compra se suma uno antes de guardarla a fichero).
He emarcado con un punto de pausa en las líneas nuevas o modificadas (al margen de la declaración de la variable arriba y la declaración del parámetrod e la función abajo).

(https://i.imgur.com/aNVaBMP.png)


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 11 Marzo 2022, 22:42 pm
Hola serapis

El listado superior tendria que ir a una pestaña del sub menu por ejemplo listado de compras esto ya estaria bien

la cosa esta en quitar el listado superior

poner numero de factura en pantalla en un textbox numero consecutivo 1,2,3,4,5,6,etc

en conjunto con  el listado de abajo listprods

entraria el numero consecutivo  se guardaria en un boton guardar


y despues con otro boton para leer la factura 1,2,3,4,etc

entraria en el numero textbox y se veria todo el listado de abajo listprods para cada numero de factura

seria guardar y leer.


Gracias




Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 12 Marzo 2022, 16:43 pm
No termino de entenderte del todo... te respondo tirando de intuición (a veces, un esquema, un croquis de lo que uno espera ayuda a aclarar las cosas).

El listado superior, puedes eliminarlo, o simplemente ocultarlo.
Si se elimina, esos totales  que tiempo atrás querías para diferenciar el volumen de compra con tarjeta de crédito y en efectivo, he de suponer que se sigue requiriendo, luego la función que carga el listado superior (ListarFacturacion), debe seguir existiendo (quizás deba cambiar el nombre para reflejar su funcionalidad actual "TotalizarFacturacion") ...
Si tampoco necesitas esos textbox, la función casi entera se puede eliminar y entonces se debiera llamar "Inicializar", pués todavía debe abrir los ficheros y leer la cantidad de registros y el valor autonumericod e incremento y mostrar la primera compra.

Eliminando ese listado, y poniendo un textbox y un botón para leer una factura, es simple.

Ahora mismo para leer el contenido de una compra, se debe:
- Leerse el registro de compra (por su numero de factura). ahora mismo el número de factura (IdLote se toma del valor almacenado en intemdata(listindex), y se invoca desde el click del listado: "sub LisLotes_Click"
- Una vez leído el registro de compra, sabremos cuantos ítems se compraron, el índice donde localizarlos en el fichero y el valor total de la compra.
- Con el indice y la cantidad a leer (están consecutivos), se leen igual que antes (esta función no cambia nada).

Luego el código es fácilmente modificable, tu estarías remplazando el rescate del numero de factura que en vez de tomarse del itemdata del ítem activo en el listado, lo tomes desde un textbox y en vez de llamarse cuando se pulse en el listado, se llama cuando se pulse en un botón:

Este es el código actual para hacer la llamada que lista los productos de dicha compra:
Código
  1. ' Lee los productos comprados que forman dicho lote y los muestra en el listado de productos.
  2. Private Sub LisLotes_Click()
  3.    If (LisLotes.ListCount > 0) Then
  4.        Call PosicionarRegLote(LisLotes.ListIndex + 1)          ' allí se resta 1.
  5.        Get #CanalLote, , RegX
  6.        IdLote = RegX.IdPedido
  7.        Call ListarCompraDelLote(RegX.Index, RegX.Cantidad)
  8.    End If
  9. End Sub
  10.  

Así el código a cambiar es relativamente sencillo, podría ser algo como:
Código
  1. ' Lee los productos comprados que forman dicho lote y los muestra en el listado de productos.
  2. Private Sub ComBuscar_Click() ' <---- al pulsar el botón
  3.    dim id as integer
  4.  
  5.    if (NumRegsLotes>0) then '  If (LisLotes.ListCount > 0) Then   ' si hay registros en la facturación...
  6.        if (isnumeric(txtNumeroFactura.text)) then    ' si el textbox tiene un número válido
  7.            id = cint(txtNumeorFactura.text)               ' el textbox es quien indica ahora el numero de factura
  8.            if (id <= NumRegsLotes) then
  9.                Call PosicionarRegLote(id +1)  ' Call PosicionarRegLote(LisLotes.ListIndex + 1)          ' allí se resta 1.
  10.                Get #CanalLote, , RegX
  11.                IdLote = RegX.IdPedido
  12.                Call ListarCompraDelLote(RegX.Index, RegX.Cantidad)
  13.                txtFactura.Text = RegCompraToString(Reg)
  14.                exit sub
  15.            end if
  16.        end if
  17.    End If
  18.  
  19.    ' Si el botón está siempre activado... lo ideal es que esté activo solo si el número de factura es válido.  
  20.    txtFactura.Text = ""
  21.    call msgbox ("Número de factura no reconocido. Debe haber facturas y el número de factura ser mayor que 0 y menor que el número de registros actuales")
  22. End Sub
  23.  

...y en el código pocos cambios más necesitas hacer, salvo comentar o eliminar las líneas que cargan dicho listado (el total se supone que todavía querrás hacerlo):
Código
  1. Private Function ListarFacturacion(ByRef Ruta1 As String, ByRef Ruta2 As String) As Boolean
  2.    '...
  3.    ' Remplazar/eliminar las líneas aqui comentadas:
  4.    If (NumRegsLotes > 0) Then
  5.            'With LisLotes
  6.             '   .Clear
  7.  
  8.                Call PosicionarRegLote(1)       ' allí se resta 1
  9.                For k = 0 To NumRegsLotes - 1
  10.                    Get #CanalLote, , RegX
  11.             '       Call .AddItem(RegCompraToString(RegX))
  12.              '      .ItemData(k) = RegX.IdPedido
  13.  
  14.                    If (RegX.MetodoDePago = MetodosDePago.PAGO_AL_CONTADO) Then
  15.                        TotalContado = (TotalContado + RegX.Total)
  16.                    Else
  17.                        TotalCredito = (TotalCredito + RegX.Total)
  18.                    End If
  19.                Next
  20.  
  21.                Call ShowTotales
  22.  
  23.                ' <---- Ahora si se quiere puede leerse de nuevo el primer registro para transferirlo a los textbox...
  24.             '   .ListIndex = 0 ' para ello delegamos en el código que pondremos al listbox...
  25.            'End With
  26.  
  27.    ' Y añadir estas dos en esta posición:  <---- Ahora si se quiere puede leerse de nuevo el primer registro para transferirlo
  28.             txtNumeroFactura.Text = "1"
  29.             call ComBuscar_click
  30.        End If
  31.    '...
  32. end sub
  33.  

Igualmente cuando se añade un registro de compra, que antes se añadía al listado, ahora se pone en el textbox:
Código
  1. Friend Sub GuardarCompra(ByRef Reg As RegLote, ByVal Productos As Integer)
  2.  '...
  3.  ' Remplazar (o comentar) estas líneas:
  4.  ' With LisLotes
  5.  '      Call .AddItem(RegCompraToString(Reg))               ' También lo añade al listado.
  6.  '      .ItemData(.ListCount - 1) = AutoIncLote
  7.  '  End With
  8.  ' ...
  9.  '  LisLotes.ListIndex = (LisLotes.ListCount - 1)           ' Fuerza a listar los productos comprados en este lote.
  10.  
  11.  ' con estas:
  12.     txtNumeroFactura.Text = cstr(reg.IdPedido)
  13.     txtFactura.Text = RegCompraToString(Reg)
  14.     call ComBuscar_Click
  15. end sub
  16.  


La interfaz, por su parte tampoco requiere mucha complicación: Se añaden 2 textbox y un botón y se elimina el listado superior, y se reordena la interfaz reubicando los controles. Hago cambios a la imagen previa, para reflejar como cambiaría la interfaz:
Nota que el listado superior desaparece, ahora es remplazado por un textbox (txtFactura), debajo ... que muestra los valores de dicha factura (en la imagen 'la factura desglosada' no se corresponde con la 'rescatada', es un copy paste, la que le correspondía estaba seleccionada y el textbox debe tener la propiedad locked a true (no es editable solo muestra valores), así esa selección podría inducir a error de interpretación).

Puede verse que se añade un textbox (TxtNumeroFactura) y un botón (ComBuscar) para buscar... los otros controles (de totales) se han colocado a la derecha y debajo del listado (igualmente pueden retirarse en dejarse sobre el menú pues son solo informativos, como ese nuevo textbox.
(https://i.imgur.com/0olQInA.png)

Ese textbox de la compra a añadir (que remplaza al listbox, lo sigo viendo necesario, porque contiene información importante como fecha, coste total de la factura, descuento aplicado por volumen de compra (los registros de artículos comprados solo incluyen los desceuntos que afectan a ese artículo en particular), tipo de pago efectuado...

También, es absurdo que teniendo ahora ambos ficheros ordenadamente cada uno con sus registros, requerir ahora cada vez totalizar la suma de compra (la provee el propio registro de compra), además el registro de compra incluye aparte el decuento que se aplica de forma individual a cada artículo (si procede).

En definitiva, los cambios a realizar son simples, no hay nueva funcionalidad que se deba añadir, existe , son solo pequeñas modificaciones que debes hacer tú... repasa todo el código de la ventana, en busca de posibles referencias  al listado 'lisLote', por si aparece en más sitios y ver si basta con eliminar dichas líneas o si deben ser remplazadas por otras...


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 12 Marzo 2022, 17:38 pm
Hola Serapis

la idea es buena pero en buscar me sale error

Compile error

ByRef argument type mismatch

en la variable Reg

Código
  1.  
  2. ' Lee los productos comprados que forman dicho lote y los muestra en el listado de productos.
  3. Private Sub ComBuscar_Click() ' <---- al pulsar el botón
  4.    dim id as integer
  5.  
  6.    if (NumRegsLotes>0) then '  If (LisLotes.ListCount > 0) Then   ' si hay registros en la facturación...
  7.        if (isnumeric(txtNumeroFactura.text)) then    ' si el textbox tiene un número válido
  8.            id = cint(txtNumeorFactura.text)               ' el textbox es quien indica ahora el numero de factura
  9.            if (id <= NumRegsLotes) then
  10.                Call PosicionarRegLote(id +1)  ' Call PosicionarRegLote(LisLotes.ListIndex + 1)          ' allí se resta 1.
  11.                Get #CanalLote, , RegX
  12.                IdLote = RegX.IdPedido
  13.                Call ListarCompraDelLote(RegX.Index, RegX.Cantidad)
  14.                txtFactura.Text = RegCompraToString(Reg)
  15.                exit sub
  16.            end if
  17.        end if
  18.    End If
  19.  
  20.    ' Si el botón está siempre activado... lo ideal es que esté activo solo si el número de factura es válido.  
  21.    txtFactura.Text = ""
  22.    call msgbox ("Número de factura no reconocido. Debe haber facturas y el número de factura ser mayor que 0 y menor que el número de registros actuales")
  23. End Sub
  24.  
  25.  
  26.  




Gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 12 Marzo 2022, 19:22 pm
me sale error
Compile error
ByRef argument type mismatch en la variable Reg
Ok...

Si te fijas en el código, tenemos declarado RegX (a nivel de módulo), que se usa en la función, pero no 'Reg' (ni siquiera dentro a la función), es culpa del copy-paste que hice de la línea 14 (la tomé tal cual de otro código que te puse antes y la pegué ahí, sin hacer la adaptación pertienente)... ¿ves que pone ...(Reg)?. remplázalo por RegX, que está declarada a nivel de módulo.

Aunque es un error fácil de reconocer... el propio error ya te da la pista "ByRef argument type mismatch en la variable Reg", la función lllamada exige una variable de un tipo determinado, ahí 'Reg' técnicamente es un variant (al no estar declarado).
argument type -- mismatch = El tipo del parámetro pasado a la función no coincide con el esperado.

Cuando tengas dudas con los errores, ve a la ayuda (que te ofrece) y te amplía los detalles de por qué se produce tal error (muy pocas veces (en VB6), está mal o imprecisamente explicado en la ayuda).

p.d.: nota también que escribí mal el nombre del textbox: txtNumeorFactura (línea 8), en la línea anterior está bien escrito. Me suele ocurrir con relativa frecuencia con el teclado que al escribir muy rápido escriba una letra con una mano antes que la que toca con la otra mano...


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 12 Marzo 2022, 19:38 pm
Hola Serapis


He conseguido buscar con el texbox pero tiene que ir con el listado de  listlotes

si carga con listlotes busca si no carga no busca


hay alguna manera de hacer la busqueda sin listlotes


Código
  1.  
  2. Private Sub Command1_Click()
  3. 'Buscar
  4. Dim Id As Integer
  5.  
  6.    If (NumRegsLotes > 0) Then '  If (LisLotes.ListCount > 0) Then   ' si hay registros en la facturación...
  7.        If (IsNumeric(txtNumeroFactura.Text)) Then    ' si el textbox tiene un número válido
  8.            Id = CInt(txtNumeroFactura.Text)               ' el textbox es quien indica ahora el numero de factura
  9.            If (Id <= NumRegsLotes) Then
  10.                Call PosicionarRegLote(Id)  ' Call PosicionarRegLote(LisLotes.ListIndex + 1)          ' allí se resta 1.
  11.                Get #CanalLote, , RegX
  12.                IdLote = RegX.IdPedido
  13.                Call ListarCompraDelLote(RegX.Index, RegX.Cantidad)
  14.                'txtFactura.Text = RegCompraToString(Reg)
  15.                Exit Sub
  16.            End If
  17.        End If
  18.    End If
  19.  
  20.    ' Si el botón está siempre activado... lo ideal es que esté activo solo si el número de factura es válido.
  21.    'txtFactura.Text = ""
  22.    Call MsgBox("Número de factura no reconocido. Debe haber facturas y el número de factura ser mayor que 0 y menor que el número de registros actuales")
  23. End Sub
  24.  
  25.  
  26.  
  27.  
  28.  
  29. ' Abre y carga el fichero de facturación. También abre el fichero de productos comprados (solo carga los productos asociados al primer lote en el listado).
  30. ' NOTA: No establecer la propiedad SORTED a TRUE, en los listados, ya que entonces el añadido sería ordenado y no al final.
  31. Private Function ListarFacturacion(ByRef Ruta1 As String, ByRef Ruta2 As String) As Boolean
  32.  '...
  33.    Dim k As Integer
  34.  
  35.    Call CerrarFacturacion
  36.  
  37.    If ((Abrir(Ruta1, CanalLote) = True) And (Abrir(Ruta2, CanalProducto) = True)) Then
  38.        Get #CanalLote, 1, NumRegsLotes
  39.        Get #CanalLote, , AutoIncLote
  40.  
  41.        Get #CanalProducto, 1, NumRegsProds
  42.        Get #CanalProducto, , AutoIncProducto
  43.  
  44.        If (NumRegsLotes > 0) Then
  45.            With LisLotes
  46.                .Clear
  47.  
  48.                Call PosicionarRegLote(1)       ' allí se resta 1
  49.                For k = 0 To NumRegsLotes - 1
  50.                    Get #CanalLote, , RegX
  51.                    Call .AddItem(RegCompraToString(RegX))
  52.                    .ItemData(k) = RegX.IdPedido
  53.  
  54.                    If (RegX.MetodoDePago = MetodosDePago.PAGO_AL_CONTADO) Then
  55.                        TotalContado = (TotalContado + RegX.Total)
  56.                    Else
  57.                        TotalCredito = (TotalCredito + RegX.Total)
  58.                    End If
  59.                Next
  60.  
  61.                Call ShowTotales
  62.  
  63.                ' Ahora si se quiere puede leerse de nuevo el primer registro para transferirlo a los textbox...
  64.                .ListIndex = 0 ' para ello delegamos en el código que pondremos al listbox...
  65.            End With
  66.        End If
  67.  
  68.        mnuLotes(0).Enabled = True
  69.        ListarFacturacion = True
  70.    End If
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77.    ' Remplazar/eliminar las líneas aqui comentadas:
  78.    If (NumRegsLotes > 0) Then
  79.            'With LisLotes
  80.             '   .Clear
  81.  
  82.                Call PosicionarRegLote(1)       ' allí se resta 1
  83.                For k = 0 To NumRegsLotes - 1
  84.                    Get #CanalLote, , RegX
  85.             '       Call .AddItem(RegCompraToString(RegX))
  86.              '      .ItemData(k) = RegX.IdPedido
  87.  
  88.                    If (RegX.MetodoDePago = MetodosDePago.PAGO_AL_CONTADO) Then
  89.                        TotalContado = (TotalContado + RegX.Total)
  90.                    Else
  91.                        TotalCredito = (TotalCredito + RegX.Total)
  92.                    End If
  93.                Next
  94.  
  95.                Call ShowTotales
  96.  
  97.                ' <---- Ahora si se quiere puede leerse de nuevo el primer registro para transferirlo a los textbox...
  98.             '   .ListIndex = 0 ' para ello delegamos en el código que pondremos al listbox...
  99.            'End With
  100.  
  101.    ' Y añadir estas dos en esta posición:  <---- Ahora si se quiere puede leerse de nuevo el primer registro para transferirlo
  102.             txtNumeroFactura.Text = "1"
  103.             Call Command1_Click
  104.   End If
  105. End Function
  106.  
  107.  
  108. ' Guarda el registro del lote. Cada lote puede componerse de varios registros de artículso comprados,
  109. Friend Sub GuardarCompra(ByRef Reg As RegLote, ByVal Productos As Integer)
  110.    NumRegsLotes = (NumRegsLotes + 1)
  111.    AutoIncLote = (AutoIncLote + 1)
  112.  
  113.    With Reg
  114.        .IdPedido = AutoIncLote                             ' Completa los datos del registro que (mejor) procede hacer aquí.
  115.        .Cantidad = Productos
  116.        .FechaCompra = DateTime.Now
  117.        .Index = (NumRegsProds - .Cantidad)
  118.  
  119.        If (.MetodoDePago = PAGO_AL_CONTADO) Then
  120.            TotalContado = (TotalContado + .Total)
  121.        Else
  122.            TotalCredito = (TotalCredito + .Total)
  123.        End If
  124.        Call ShowTotales                                    ' Actualiza los valores totales.
  125.    End With
  126.  
  127.    Call PosicionarRegLote(NumRegsLotes)                    ' Posiciona el cursor de escritura al final del fichero.
  128.    Put #CanalLote, , Reg                                   ' Guarda el registro.
  129.    'With LisLotes
  130.       ' Call .AddItem(RegCompraToString(Reg))               ' También lo añade al listado.
  131.        '.ItemData(.ListCount - 1) = AutoIncLote
  132.   ' End With
  133.  
  134.    txtNumeroFactura.Text = CStr(Reg.IdPedido)
  135.     txtFactura.Text = RegCompraToString(Reg)
  136.     Call Command1_Click
  137.  
  138.  
  139.    Put #CanalLote, 1, NumRegsLotes                         ' Guarda la cantidad de registros
  140.    Put #CanalLote, , AutoIncLote                           ' Guarda el valor de autoincrmeento (es un valor único).
  141.  
  142.    Put #CanalProducto, 1, NumRegsProds
  143.    Put #CanalProducto, , AutoIncProducto                   ' Guarda el valor de autoincrmeento (es un valor único).
  144.  
  145.   'LisLotes.ListIndex = (LisLotes.ListCount - 1)           ' Fuerza a listar los productos comprados en este lote.
  146.  
  147.  
  148.  
  149.  
  150.  
  151.  
  152.  
  153.  
  154.  
  155.  
  156.  






gracias




Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 12 Marzo 2022, 21:03 pm
Guau... de verdad no eres capaz de seguir las instrucciones (que en realidad ni siquiera tendría que explicarte, pues es demasiado sencillo)?.

El códigos que te he proporcionado, incluye comentarios (dentro del código): que ponen lo que hay que hacer:

Código
  1. 'Remplazar o eliminar ---x--- (líneas de código que he comentado, precedido por el caracter de comentario)
  2. '...
  3. 'Por esto esto otro ---y---
  4.  

Donde algo  como: '...
Representa código previo, intermedio o final que (pudiera haber y que) no tocamos... Es decir, indica que busques las líneas que te haya indicado, que las borres y que lo remplaza las líneas que puse, que también se señala y que el resto de código en la función no se altera.

Es decir... ¿No hay forma de indicarte lo que debes hacer, diciendo simplemente remplaza las líneas que te indico por las otras que también te indico?, ¿debo darte todo el código listo, solo para copiar y pegar?.  

Tómate la molestia de leerlo, entre el código he añadido los comentarios de qué debe ser remplazado/eliminado/comentado y qué lo remplaza.


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 12 Marzo 2022, 22:03 pm
Hola Serapis


ya lo he corregido funciona correctamente

me habia puesto un poco nervioso, pero depues con mas tranquilidad lo he podido solucionar


muchas gracias


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 14 Marzo 2022, 16:18 pm
Hola Serapis

se que soy muy pesado en esto de la programacion ahora son detalles

ahora me faltaria hacer la suma una vez que lees la compra, hacer el total de la suma


gracias


Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 14 Marzo 2022, 22:49 pm

ahora me faltaria hacer la suma una vez que lees la compra, hacer el total de la suma
La suma ya está hecha, se guardó en el registor de compra.


Código
  1. ' Lee los productos comprados que forman dicho lote y los muestra en el listado de productos.
  2. Private Sub Command1_Click() ' <---- al pulsar el botón
  3.    dim id as integer
  4.  
  5.    if (NumRegsLotes>0) then '  If (LisLotes.ListCount > 0) Then   ' si hay registros en la facturacion...
  6.        if (isnumeric(txtNumeroFactura.text)) then    ' si el textbox tiene un numero valido
  7.            id = cint(txtNumeorFactura.text)               ' el textbox es quien indica ahora el numero de factura
  8.            if (id <= NumRegsLotes) then
  9.                Call PosicionarRegLote(id +1)  ' Call PosicionarRegLote(LisLotes.ListIndex + 1)          ' alli se resta 1.
  10.                Get #CanalLote, , RegX     ' <------------ aqui se lee el registro
  11.                IdLote = RegX.IdPedido
  12.                Call ListarCompraDelLote(RegX.Index, RegX.Cantidad)
  13.                txtFactura.Text = RegCompraToString(Regx)   '<----------------- y aqui se lista el registro del lote
  14.               ' y si no:
  15.                txtTotalFactura.Text = cstr(regx.total)
  16.                exit sub
  17.            end if
  18.        end if
  19.    End If
  20.  
  21.    ' Si el botón está siempre activado... lo ideal es que esté activo solo si el número de factura es válido.  
  22.    txtFactura.Text = ""
  23.    call msgbox ("Número de factura no reconocido. Debe haber facturas y el número de factura ser mayor que 0 y menor que el número de registros actuales")
  24. End Sub

La línea 10, lee el registro de la compra.
La línea 12, lista los productos comprados... no hace falta sumarlos allí, ya se hizo al pagar la factura cuando se compró, y se guardó en el registro que se acaba de leer en la línea 10.
La línea 13, muestra en el textbox, el contenido de dicho registro... método de pago, fecha y total entre otros.
Si no quieres usar la línea 13 (parece que la ignoras y no entiendo por qué), entonces añade un textbox (txtTotalFactura) para contener el total ... línea 15 (esta línea la acabao de poner, es opcional, es decir o usas la 13 o la 15.

Con todo creo más útil usar la línea 13... para que se vea como te dibujé la interfaz en la siguiente imagen (a la izquierda abajo del todo):
(https://i.imgur.com/0olQInA.png)
El texto de la columna 'subtotal' que pone '51,273' (ya expliqué que ese total no es el de los productos de arriba, es una 'composición de otra imagen'. Por cierto mejor que 'subtotal  ahí debiera poner Total.


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 14 Marzo 2022, 23:13 pm
Hola Serapis

ahora si que suma

Código
  1.  
  2. txtTotalFactura.Text = cstr(regx.total)
  3.  
  4.  


muchas gracias


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 22 Abril 2022, 19:05 pm
Hola Serapis

Estoy intentando de hacer crear almacen nuevo y leer almacen del menu principal  lo he probado de hacerlo con el formulario frmfile pero no me lo hace

si no es asin no se como hacerlo

gracias


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 1 Mayo 2022, 14:18 pm
Ahora crea el nuevo almacen, pero no logro que me lea el almacen


Código
  1.  
  2. Private Sub mnualmacen_Click(Index As Integer)
  3. 'Crear Nuevo Almacen
  4. Dim File As String
  5.  
  6.    Select Case Index
  7.        Case 0  ' Nuevo Almacen
  8.             File = InputBox("Elija el nombre del fichero para una nuevo Almacen (no debe existir).", "Nuevo Almacen", "Nuevo Almacen.dat")
  9.            If (Len(File) > 0) Then
  10.                File = AsegurarExtension(File, FILE_EXTENSION_FACTURA)
  11.  
  12.                If (CrearNuevaFacturacion(File) = True) Then
  13.                    Call Activar(True)
  14.  
  15.                Else
  16.                    Call Activar(False)
  17.                End If
  18.            Else
  19.                Call MsgBox("Proceso de creación de nuevo Almacen abortado. No se proporcionó un nombre", vbInformation, "Nuevo Almacen")
  20.            End If
  21.        Case 1  ' Leer Nuevo Almacen
  22.            Frmfile1.Show 1
  23.            If (Len(Frmfile1.File) > 0) Then
  24.                If (LeerFacturacion(App.Path & "\" & Frmfile1.File) = True) Then
  25.                    Call Activar(True)
  26.                Else
  27.                    Call Activar(False)
  28.                End If
  29.            End If
  30.  
  31.    End Select
  32. End Sub
  33.  
  34.  
  35.  
  36. Private Function CrearNuevaFacturacion(ByRef NombreFile As String) As Boolean
  37. Dim Ruta As String
  38.  
  39.    If (Abierto = True) Then Call Cerrar(Canal)
  40.  
  41.    Ruta = (App.Path & "\" & NombreFile)
  42.    If (Abrir(Ruta, Canal, True) = True) Then
  43.        Call UpdateHeader(0, 0)
  44.        CrearNuevaFacturacion = True
  45.    Else
  46.        MsgBox "Parece que el fichero que intenta abrir ya existe, elija otro nombre (o bien ocurrió un error)..."
  47.    End If
  48. End Function
  49.  
  50.  
  51. Private Function LeerFacturacion(ByRef Ruta As String) As Boolean
  52.   Dim k As Integer
  53.  
  54.    If (Abierto = True) Then Call Cerrar(Canal)
  55.  
  56.    If (Abrir(Ruta, Canal) = True) Then
  57.        Get #Canal, 1, NumRegistros
  58.        Get #Canal, , AutoIncLote
  59.        Get #Canal, , AutoIncProducto
  60.  
  61.        If (NumRegistros > 0) Then
  62.            With List1
  63.                .Clear
  64.                For k = 1 To NumRegistros
  65.                    Get #Canal, , RegX
  66.                    Call .AddItem(RegCompraToString(RegX, CHAR_SEP))
  67.                Next
  68.  
  69.                ' Ahora si se quiere puede leerse de nuevo el primer registro para transferirlo a los textbox...
  70.                .ListIndex = 0 ' para ello delegamos en el código que pondremos al listbox...
  71.            End With
  72.        End If
  73.  
  74.        LeerFacturacion = True
  75.    End If
  76. End Function
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  




el problema esta en esta linea


Call .AddItem(RegCompraToString(RegX, CHAR_SEP))



error byref argument type mismatch en RegX

gracias






Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 1 Mayo 2022, 17:03 pm
El proyecto ha sido cambiado en profundidad en más de una vez... si de último te dí el proyecto completo y funcional, porqué ahora el código en tus funciones no vene a coincidir con el código que te pasé la última vez....?

Veamos, si tratas de crear una nueva facturación... se deben crear dos ficheros un fichero *.data y un fichero *.regdata (resultado de las últimas modificaciones), el caso es que siendo 'nueva' el número de registros será 0... porque se acaba de crear la facturación, el contenido de dichos ficheros será 0 registros...

Así que al invocar 'leer facturación' solo se ejecurtará esa parte del código si se da esta condición:
Código
  1. If (NumRegistros > 0) Then
Así que al crear la facturación no deberia acceder a esa zona... y por qué accede a esa zona si debiera haber 0 registros?. Porque o bien usas la versión vieja del código o bien lo has modificado eliminando código.... hasta probar que los cambios funcionan bien, mejor que eliminar es comentar código, si el cambio es bastante grande que no solo se borren alguna slíneas y tal, entonces es preferible copiar la función y dejarla comentada al completo, y por tanto hacer cambios sobre una copia... así, si algo falla (que antes funcionaba, esto es mismo código) puede verificarse la diferencia entre ambos códigos para reconocer que está sucediendo.

Tu tienes esté código:
Código
  1. Private Function CrearNuevaFacturacion(ByRef NombreFile As String) As Boolean
  2. Dim Ruta As String
  3.  
  4.    If (Abierto = True) Then Call Cerrar(Canal)
  5.  
  6.    Ruta = (App.Path & "\" & NombreFile)
  7.    If (Abrir(Ruta, Canal, True) = True) Then
  8.        Call UpdateHeader(0, 0)
  9.        CrearNuevaFacturacion = True
  10.    Else
  11.        MsgBox "Parece que el fichero que intenta abrir ya existe, elija otro nombre (o bien ocurrio un error)..."
  12.    End If
  13. End Function
Y para la misma función al final cambió a este:

Código
  1. ' La creacion de una NUEVA facturacion supone crear ambos ficheros:
  2. '   1 - "Facturacion xxx.reg"
  3. '   2 - "Facturacion xxx.regdata"
  4. Private Function CrearNuevaFacturacion(ByRef NombreFileLote As String, ByRef NombreFileProd As String, ByVal NFacturaInicial As Integer) As Boolean
  5.    Dim Ruta As String
  6.  
  7.    Call CerrarFacturacion
  8.  
  9.    Ruta = (App.Path & "\" & NombreFileLote)
  10.    If (Abrir(Ruta, CanalLote, True) = True) Then
  11.        Ruta = (App.Path & "\" & NombreFileProd)
  12.        If (Abrir(Ruta, CanalProducto, True) = True) Then
  13.            Get #CanalLote, 1, NumRegsLotes
  14.            Get #CanalLote, , AutoIncLote
  15.  
  16.            ' Usar el parámetro 'NFacturaInicial' (para que funcione correctamente), implica más cambios en el código que no se efectuaron, pues surgió como una sugerencia de una interpretación errónea de cierta petición que hiciste.
  17.            'If (NFacturaInicial > 1) Then
  18.            '    AutoIncLote = (NFacturaInicial - 1) ' cuando se compre se incrementa en 1
  19.                AutoIncLote = 0
  20.                Put #CanalLote, 3, AutoIncLote
  21.            'End If
  22.  
  23.            Get #CanalProducto, 1, NumRegsProds
  24.            Get #CanalProducto, , AutoIncProducto
  25.  
  26.            mnuLotes(0).Enabled = True
  27.            CrearNuevaFacturacion = True
  28.            Exit Function
  29.        End If
  30.    End If
  31.  
  32.    If (Err.Number = 0) Then
  33.        Call MsgBox("Parece que uno o ambos ficheros asociados a la facturacion que intenta abrir ya existe, elija otro nombre (o bien ocurrió un error)...", vbExclamation, "Crear Nueva Facturacion: Ya existe...")
  34.    Else
  35.        Err.Clear
  36.        Call MsgBox("Ocurrio un error inesperado al tratar de abrir la facturacion seleccionada..." & vbCrLf & Err.Description, vbExclamation, "Crear Nueva Facturacion: Error inesperado...")
  37.    End If
  38. End Function
  39.  

Como se ve, recibe dos parámetros para los ficheros, no solo uno, y observo que en tu código falta la llamada a la función 'CerrarFacturacion' que es la que pondrá a 0 todas las variables globales referidas a una facturación como es 'NumRegistros'. La función debe invocarse tanto si había abierta previamente una facturación como si no... allí mismo se verifica si estaba abierta y se cierra.

Además, según veo allí (y que de memoria ya no recordaba), la variable NumRegistros, fue cambiada de nombre al separar en dos ficheros la comprar de los productos de cada compra:
Código
  1. ' Cierra los dos ficheros asociados a la misma facturacion.
  2. Private Function CerrarFacturacion()
  3.    If (Abierto = True) Then
  4.        Call CerrarCarrito
  5.  
  6.        Close #CanalLote
  7.        Close #CanalProducto
  8.        Call ActivarInterfaz(False)  ' desactivar de la interfaz, lo que proceda...
  9.    End If
  10.  
  11.    mnuLotes(0).Enabled = False
  12.    CanalLote = 0: NumRegsLotes = 0: AutoIncLote = 0
  13.    CanalProducto = 0: NumRegsProds = 0: AutoIncProducto = 0
  14.    TotalContado = 0: TotalCredito = 0
  15.    Call ShowTotales
  16. End Function
  17.  

NumRegsLotes y NumRegsProds (creo recordar), remplazan a NumRegistros.


El error que te arroja el código, se produce simplemente porque el tipo de datos del parámetro que se pasa no coincide con el tipo de datos que la función invocada espera... y es razonable porque al separar la factura en 2 ficheros uno que contiene los datos estrictos de la compra y otro el detalle de cada artículo comprado, exigió crear un registro específico para cada fichero, quedando el registro que antes se usaba para el único fichero obsoleto...
si se revisa la función que da el fallo:
Código
  1. Public Function RegCompraToString(ByRef Registro As RegLote, Optional ByRef Separador As String = CHAR_SEP) As String
  2.    Dim R As String, S As String, T As String
  3.  
  4.    With Registro
  5.        R = (FillSizeStr(CStr(.IdPedido), 5, True) & Separador & FillSizeStr(CStr(.Cantidad), 5, True))
  6.        S = (FillSizeStr(CStr(.Descuento), 7, True, 3) & Separador & FillSizeStr(CStr(.Total), 7, True, 3))
  7.        T = GetMetodoPago(.MetodoDePago) & Separador & CStr(.FechaCompra)
  8.  
  9.        RegCompraToString = (R & Separador & S & Separador & T)
  10.    End With
  11. End Function
  12.  
Reclama un parámetro del tipo 'RegLote' (ByRef Registro As RegLote). Dicha función fue modificada, para adaptarse a los cambios de la separación de la compra en sendos ficheros. No recuerdo si además cambié el nombre de la estructura (probablemente):
Código
  1. ' Ahora el registro de lote, va aparte de los registro de los articulos especificos comprados en el lote.
  2. Public Type RegLote                                         ' 32 bytes por registro
  3.    IdPedido                            As Integer          ' 01  Cada lote, comprado tiene su id unico que se aplica a todos los articulos comprados en ese lote.
  4.      Reservado1                        As Integer          ' 03     (Reservado: Por si se debe cambiar el Id a tipo long, sin alterar los ficheros).
  5.      Reservado2                        As Integer          ' 05     Para futurible ampliacion
  6.      Reservado3                        As Long             ' 07     Para futurible ampliacion
  7.    Descuento                           As Single           ' 11  Descuento (Solo se aplica, para las ofertas de tipo: 1,2 y 4, en otro caso el valor es siempre 0).
  8.    Total                               As Single           ' 15  Coste total del lote comprado.
  9.    FechaCompra                         As Date             ' 19  Fecha de compra del lote (fecha y hora)
  10.    MetodoDePago                        As Byte             ' 27  Metodo de pago
  11.    Cantidad                            As Byte             ' 29  Cantidad de productos comprados en el lote.
  12.    Index                               As Long             ' 29  Puntero a un fichero que contiene los idCompra de cada articulo comprado en el lote.
  13. End Type
  14.  
Como se ve, el registro solo contiene datos informativos del lote comprado, entre los que incluye los necesarios para rescatar los registros asociados con los detalles de los artículos comprados (campos: 'Cantidad' e 'Index'). Los comentarios, no se ponen por poner... detallan que son o porque están.


Tu tienes la función 'LeerFacturación', con el siguiente código:
Código
  1. Private Function LeerFacturacion(ByRef Ruta As String) As Boolean
  2.   Dim k As Integer
  3.  
  4.    If (Abierto = True) Then Call Cerrar(Canal)
  5.  
  6.    If (Abrir(Ruta, Canal) = True) Then
  7.        Get #Canal, 1, NumRegistros
  8.        Get #Canal, , AutoIncLote
  9.        Get #Canal, , AutoIncProducto
  10.  
  11.        If (NumRegistros > 0) Then
  12.            With List1
  13.                .Clear
  14.                For k = 1 To NumRegistros
  15.                    Get #Canal, , RegX
  16.                    Call .AddItem(RegCompraToString(RegX, CHAR_SEP))
  17.                Next
  18.  
  19.                ' Ahora si se quiere puede leerse de nuevo el primer registro para transferirlo a los textbox...
  20.                .ListIndex = 0 ' para ello delegamos en el codigo que pondremos al listbox...
  21.            End With
  22.        End If
  23.  
  24.        LeerFacturacion = True
  25.    End If
  26. End Function
  27.  

Revisando, en el último proyecto que te pasé.., ni siquiera tengo una función con ese nombre, la que se encarga de la lectura de una facturación se llama 'ListarFacturacion', y tiene este código:
Código
  1. ' Abre y carga el fichero de facturacion. Tambien abre el fichero de productos comprados (solo carga los productos asociados al primer lote en el listado).
  2. ' NOTA: No establecer la propiedad SORTED a TRUE, en los listados afectados.
  3. Private Function ListarFacturacion(ByRef Ruta1 As String, ByRef Ruta2 As String) As Boolean
  4.    Dim k As Integer
  5.  
  6.    Call CerrarFacturacion
  7.  
  8.    If ((Abrir(Ruta1, CanalLote) = True) And (Abrir(Ruta2, CanalProducto) = True)) Then
  9.        Get #CanalLote, 1, NumRegsLotes
  10.        Get #CanalLote, , AutoIncLote
  11.  
  12.        Get #CanalProducto, 1, NumRegsProds
  13.        Get #CanalProducto, , AutoIncProducto
  14.  
  15.        If (NumRegsLotes > 0) Then
  16.            With LisLotes
  17.                .Clear
  18.  
  19.                Call PosicionarRegLote(1)       ' alli se resta 1
  20.                For k = 0 To NumRegsLotes - 1
  21.                    Get #CanalLote, , RegX
  22.                    Call .AddItem(RegCompraToString(RegX))
  23.                    .ItemData(k) = RegX.IdPedido
  24.  
  25.                    If (RegX.MetodoDePago = MetodosDePago.PAGO_AL_CONTADO) Then
  26.                        TotalContado = (TotalContado + RegX.Total)
  27.                    Else
  28.                        TotalCredito = (TotalCredito + RegX.Total)
  29.                    End If
  30.                Next
  31.  
  32.                Call ShowTotales
  33.  
  34.                ' Ahora si se quiere puede leerse de nuevo el primer registro para transferirlo a los textbox...
  35.                .ListIndex = 0 ' para ello delegamos en el codigo que pondremos al listbox...
  36.            End With
  37.        End If
  38.  
  39.        mnuLotes(0).Enabled = True
  40.        ListarFacturacion = True
  41.    End If
  42. End Function
  43.  
Como se puede ver, se abren 2 ficheros, el *.data y el *.regdata, e igualmente se lee de ambos, su cabecera y detrás los registros que tuviere el *.reg, si los tiene y en cuyo caso, se hace actual el primer registro (listindex =0) que exigirá leer los registros en *.regdata asociados al registro *.reg actual.

Lo siento, pero no tiene sentido que pidas cambios a un proyecto, y luego operes con código de alguna versión anterior que ahora no encaja con los cambios de la versión actual...
No puedes coger código de una versión anterior y remplazarlo alegremente por el código de una nueva versión y esperar que funcione así, sin más (si fue ampliamente cambiado, como sucede en este caso). Tampoco conservo el código de las versiones previas.


Tienes que proceder con cierto orden y no mezclar versiones sin empaparte a fondo de los cambios que tiene una versión nueva respecto de la anterior (y desde luego al hacer cambios, conservar siempre copia del original, esto es, de la versión que funciona) y por tanto si al hacer cambios afectan o no y a qué afectan.
Esos detalles no suelen estar todos en la cabeza a un tiempo, especialmente cuando transcurre tiempo de olvidan, pero deberían constar en las especificaciones que uno debe haciendo previo al proyecto y mantener actualizado con los cambios. Como es un proyecto pequeño (y ni siquiera es para mi), yo no tengo necesidad de hacer tal especificación por escrito (susbsiste en mi cabeza mientras lo hago), y en cualquier caso la profusión de comentarios a los largo del código debería bastar al interesado...


Título: Re: Guardar list2 y leer list1
Publicado por: corlo en 1 Mayo 2022, 18:07 pm
Hola serapis

he hecho los cambios y ahora me dice error en crearnuevafacturacion

Código
  1.  
  2. Private Sub mnualmacen_Click(Index As Integer)
  3. 'Crear Nuevo Almacen
  4. Dim File As String
  5.  
  6.    Select Case Index
  7.        Case 0  ' Nueva facturación
  8.             File = InputBox("Elija el nombre del fichero para una nueva facturacón (no debe existir).", "Nueva Facturacion", "Nueva facturacion.dat")
  9.            If (Len(File) > 0) Then
  10.                File = AsegurarExtension(File, FILE_EXTENSION_FACTURA)
  11.  
  12.                If (CrearNuevaFacturacion(File) = True) Then
  13.                    Call Activar(True)
  14.  
  15.                Else
  16.                    Call Activar(False)
  17.                End If
  18.            Else
  19.                Call MsgBox("Proceso de creación de nueva facturación abortado. No se proporcionó un nombre", vbInformation, "Nueva facturación")
  20.            End If
  21.        Case 1  ' Leer fichero de facturación
  22.            Frmfile1.Show 1
  23.            If (Len(Frmfile1.File) > 0) Then
  24.                If (LeerFacturacion(App.Path & "\" & Frmfile1.File) = True) Then
  25.                    Call Activar(True)
  26.                Else
  27.                    Call Activar(False)
  28.                End If
  29.            End If
  30.  
  31.    End Select
  32. End Sub
  33.  
  34.  
  35.  
  36.  

If (CrearNuevaFacturacion(File) = True) Then


error argument not opcional en CrearNuevaFacturacion(file)


gracias




Título: Re: Guardar list2 y leer list1
Publicado por: Serapis en 1 Mayo 2022, 23:25 pm
Sigues usando código de alguna versión anterior... Nuevamente estás usando una función vieja para llamar a la nueva. Te reclama el resto de parámetros que la llamada que expones no contemplaba en esa versión...

Así quedó el código de la última versión:
Código
  1. ' Crear nueva facturación,Abrir una existente.
  2. Private Sub mnuFile_Click(Index As Integer)
  3.    Dim File1 As String, File2 As String, NFacturaInicial As Integer
  4.  
  5.    Call CerrarCarrito
  6.  
  7.    Select Case Index
  8.        Case 0  ' Nueva facturación
  9.            File1 = InputBox("Elija el nombre del fichero para una nueva facturación (no debe existir).", "Nueva Facturacion", "Nueva facturacion" & FILE_EXTENSION_FACTURA)
  10.            NFacturaInicial = InputBox("Si la facturación debe empezar con un número específico, indique cual es a continuación:", "NuevaFacturación: Número de facturación inicial", "1")
  11.            If (Len(File1) > 0) Then
  12.                File1 = AsegurarExtension(File1, FILE_EXTENSION_FACTURA)
  13.                File2 = AsegurarExtension(File1, FILE_EXTENSION_FILES)
  14.                If (CrearNuevaFacturacion(File1, File2, NFacturaInicial) = True) Then
  15.                    Call ActivarInterfaz(True)
  16.                    Call FrmCarrito.Show(vbModeless)
  17.                Else
  18.                    Call ActivarInterfaz(False)
  19.                End If
  20.            Else
  21.                Call MsgBox("Proceso de creación de nueva facturación abortado. No se proporcionó un nombre", vbInformation, "Nueva facturación")
  22.            End If
  23.        Case 1  ' Leer fichero de facturación
  24.            FrmFile.Show 1
  25.            If (Len(FrmFile.File) > 0) Then
  26.                File2 = FrmFile.File
  27.                File1 = (App.Path & "\" & File2)
  28.                File2 = App.Path & "\" & AsegurarExtension(File2, FILE_EXTENSION_FILES)
  29.                If (ListarFacturacion(File1, File2) = True) Then
  30.                    Call ActivarInterfaz(True)
  31.                    Call FrmCarrito.Show(vbModeless)
  32.                Else
  33.                    Call ActivarInterfaz(False)
  34.                End If
  35.            End If
  36.    End Select
  37. End Sub
  38.  
Como se ve, la función (que ni se llama igual, porque procede del nombre de otro menú), cuando llama a la función CrearFacturación precisa más parámetros...
Diríase que no sabes usar el editor de código para siquiera consultar que parámetros requiere la función a invocar, ni que entiendas los errores que te está marcando sobre la marcha la ejecución del código...

Me pregunto si llegaste a descargar, utilizar o intentar comprender el código de la última versión que te puse hace ya casi dos meses (mensaje 34 del hilo).
...
Aquí la descarga, por si lo quieres ir probando:
https://workupload.com/file/9rRxdbcR2wv 76Kb. aprox. comprimido (incluye los ficheros  de ejemplo).
...


Por favor, no me insistas en que te solucione código que quedó solucionado. O usas enteramente una versión previa o enteramente la nueva versión. Los cambos (como te dije entonces), eran tan profundos que exigió retocar prácticamente todo, creo recordar que no quedó ninguna ventana sin que quedara afectada por los cambios. Yo me molesté en actualizar todas esas ventanas con su código para que los cambios que principalmente se solicitaban no dejarán cojo (sin funcionar o malfuncionando) el resto del programa que se vió afectado, además también me tomé la molestia de comentar los cambios que afectaron a cada uno de los módulos de código.

Yo no tengo ninguna forma de saber que cambios has hecho, ni que has tomado de una versión u otra, ni siquiera saber sobre qué versión estás trabajando... ni me siento obligado a resolver tu estulticia una y otra vez, si decides mezclar código de diferentes versiones sin pararte antes a considerar previamente qué implica hacer cambios... porque entonces esto nunca termina.

Es como si alguien comprara un vehículo, le cambia varias piezas de un motor por otro de un vehículo viejo que tenía y espera que el fabricante del nuevo le resuelva los problemas generados de dichos cambios, incluso aunque el fabricante fuera el mismo de ambos vehículos. Incluso aunque por cortesía el fabricante te diera indicaciones de los 'posibles' problemas, si tu sigues haciendo cambios de piezas.  Un fabricante vende su vehículo tal cual viene, cualquier cambio y que deje de funcionar, ahí el fabricante (además de anular su garantía) te dirá que los cambios que hagas serán bajo tu cuenta y riesgo...

Igualmente yo de digo que tú como programador debes ser capaz de resolver los problemas que te surjan cuando acometas cambios en un código que era plenamente funcional. Te solucionaría exclusivamente si algo no funcionara correctamente en el código de la última versión, solo porque aún lo conservo y no me costaría dar con cualquier posible error (en el caso de que no fueras capaz de solucionarlo), pero me desentiendo de resolver tus problemas por hacer cambios (y menos tirando de versiones anteriores, o pero mezcla de ellas) ni de acometer nueva funcionalidad.

Lo que es prestar ayuda en la compresnsión, explicación y/o dando código, creo que está más que satisfecho, el resto es dependiente de tus capacidades. Incluso el código que te he dado, aunque es plenamente funcional no es óptimo, pues te lo hice a modo de ejemplo mínimo para operar con ficheros, lo ideal era reconvertirlo para usar con clases y tablas hash, pero que dadas tus limitaciones entiendo que te quedases sin acometer tales cambios.