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
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.
If (NumRegistros > 0) Then
Tu tienes esté código:
Código
Y para la misma función al final cambió a este:
Private Function CrearNuevaFacturacion(ByRef NombreFile As String) As Boolean Dim Ruta As String If (Abierto = True) Then Call Cerrar(Canal) Ruta = (App.Path & "\" & NombreFile) If (Abrir(Ruta, Canal, True) = True) Then Call UpdateHeader(0, 0) CrearNuevaFacturacion = True Else MsgBox "Parece que el fichero que intenta abrir ya existe, elija otro nombre (o bien ocurrio un error)..." End If End Function
Código
' La creacion de una NUEVA facturacion supone crear ambos ficheros: ' 1 - "Facturacion xxx.reg" ' 2 - "Facturacion xxx.regdata" Private Function CrearNuevaFacturacion(ByRef NombreFileLote As String, ByRef NombreFileProd As String, ByVal NFacturaInicial As Integer) As Boolean Dim Ruta As String Call CerrarFacturacion Ruta = (App.Path & "\" & NombreFileLote) If (Abrir(Ruta, CanalLote, True) = True) Then Ruta = (App.Path & "\" & NombreFileProd) If (Abrir(Ruta, CanalProducto, True) = True) Then Get #CanalLote, 1, NumRegsLotes Get #CanalLote, , AutoIncLote ' 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. 'If (NFacturaInicial > 1) Then ' AutoIncLote = (NFacturaInicial - 1) ' cuando se compre se incrementa en 1 AutoIncLote = 0 Put #CanalLote, 3, AutoIncLote 'End If Get #CanalProducto, 1, NumRegsProds Get #CanalProducto, , AutoIncProducto mnuLotes(0).Enabled = True CrearNuevaFacturacion = True Exit Function End If End If If (Err.Number = 0) Then 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...") Else Err.Clear Call MsgBox("Ocurrio un error inesperado al tratar de abrir la facturacion seleccionada..." & vbCrLf & Err.Description, vbExclamation, "Crear Nueva Facturacion: Error inesperado...") End If End Function
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
' Cierra los dos ficheros asociados a la misma facturacion. Private Function CerrarFacturacion() If (Abierto = True) Then Call CerrarCarrito Close #CanalLote Close #CanalProducto Call ActivarInterfaz(False) ' desactivar de la interfaz, lo que proceda... End If mnuLotes(0).Enabled = False CanalLote = 0: NumRegsLotes = 0: AutoIncLote = 0 CanalProducto = 0: NumRegsProds = 0: AutoIncProducto = 0 TotalContado = 0: TotalCredito = 0 Call ShowTotales End Function
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
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):
Public Function RegCompraToString(ByRef Registro As RegLote, Optional ByRef Separador As String = CHAR_SEP) As String Dim R As String, S As String, T As String With Registro R = (FillSizeStr(CStr(.IdPedido), 5, True) & Separador & FillSizeStr(CStr(.Cantidad), 5, True)) S = (FillSizeStr(CStr(.Descuento), 7, True, 3) & Separador & FillSizeStr(CStr(.Total), 7, True, 3)) T = GetMetodoPago(.MetodoDePago) & Separador & CStr(.FechaCompra) RegCompraToString = (R & Separador & S & Separador & T) End With End Function
Código
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.
' Ahora el registro de lote, va aparte de los registro de los articulos especificos comprados en el lote. Public Type RegLote ' 32 bytes por registro IdPedido As Integer ' 01 Cada lote, comprado tiene su id unico que se aplica a todos los articulos comprados en ese lote. Reservado1 As Integer ' 03 (Reservado: Por si se debe cambiar el Id a tipo long, sin alterar los ficheros). Reservado2 As Integer ' 05 Para futurible ampliacion Reservado3 As Long ' 07 Para futurible ampliacion 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). Total As Single ' 15 Coste total del lote comprado. FechaCompra As Date ' 19 Fecha de compra del lote (fecha y hora) MetodoDePago As Byte ' 27 Metodo de pago Cantidad As Byte ' 29 Cantidad de productos comprados en el lote. Index As Long ' 29 Puntero a un fichero que contiene los idCompra de cada articulo comprado en el lote. End Type
Tu tienes la función 'LeerFacturación', con el siguiente código:
Código
Private Function LeerFacturacion(ByRef Ruta As String) As Boolean Dim k As Integer If (Abierto = True) Then Call Cerrar(Canal) If (Abrir(Ruta, Canal) = True) Then Get #Canal, 1, NumRegistros Get #Canal, , AutoIncLote Get #Canal, , AutoIncProducto If (NumRegistros > 0) Then With List1 .Clear For k = 1 To NumRegistros Get #Canal, , RegX Call .AddItem(RegCompraToString(RegX, CHAR_SEP)) Next ' Ahora si se quiere puede leerse de nuevo el primer registro para transferirlo a los textbox... .ListIndex = 0 ' para ello delegamos en el codigo que pondremos al listbox... End With End If LeerFacturacion = True End If End Function
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
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.
' 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). ' NOTA: No establecer la propiedad SORTED a TRUE, en los listados afectados. Private Function ListarFacturacion(ByRef Ruta1 As String, ByRef Ruta2 As String) As Boolean Dim k As Integer Call CerrarFacturacion If ((Abrir(Ruta1, CanalLote) = True) And (Abrir(Ruta2, CanalProducto) = True)) Then Get #CanalLote, 1, NumRegsLotes Get #CanalLote, , AutoIncLote Get #CanalProducto, 1, NumRegsProds Get #CanalProducto, , AutoIncProducto If (NumRegsLotes > 0) Then With LisLotes .Clear Call PosicionarRegLote(1) ' alli se resta 1 For k = 0 To NumRegsLotes - 1 Get #CanalLote, , RegX Call .AddItem(RegCompraToString(RegX)) .ItemData(k) = RegX.IdPedido If (RegX.MetodoDePago = MetodosDePago.PAGO_AL_CONTADO) Then TotalContado = (TotalContado + RegX.Total) Else TotalCredito = (TotalCredito + RegX.Total) End If Next Call ShowTotales ' Ahora si se quiere puede leerse de nuevo el primer registro para transferirlo a los textbox... .ListIndex = 0 ' para ello delegamos en el codigo que pondremos al listbox... End With End If mnuLotes(0).Enabled = True ListarFacturacion = True End If End Function
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...