Advertisement
kuroshan1104

KARDEX

Feb 4th, 2025
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 31.57 KB | Source Code | 0 0
  1. import mysql.connector
  2. from datetime import datetime
  3.  
  4. class Database:
  5.     def __init__(self):
  6.         self.connection = mysql.connector.connect(
  7.             host="192.168.1.2",
  8.             user="root",
  9.             password="Perla17*+",
  10.             database="kardex"
  11.         )
  12.         self.cursor = self.connection.cursor(dictionary=True)
  13.    
  14.     def execute_query(self, query, params=None):
  15.         self.cursor.execute(query, params or ())
  16.         return self.cursor.fetchall()
  17.    
  18.     def execute_insert(self, query, params=None):
  19.         self.cursor.execute(query, params or ())
  20.         self.connection.commit()
  21.         return self.cursor.lastrowid
  22.    
  23.     def get_next_auto_increment(self, table_name):
  24.         self.cursor.execute(f"SHOW TABLE STATUS LIKE '{table_name}'")
  25.         result = self.cursor.fetchone()
  26.         return result['Auto_increment']
  27.  
  28. class UnidadProducto:
  29.     def __init__(self, db):
  30.         self.db = db
  31.    
  32.     def listar(self):
  33.         return self.db.execute_query("SELECT * FROM unidadesproducto")
  34.    
  35.     def obtener_por_id(self, id_unidad):
  36.         result = self.db.execute_query(
  37.             "SELECT * FROM unidadesproducto WHERE idUnidad = %s",
  38.             (id_unidad,)
  39.         )
  40.         return result[0] if result else None
  41.  
  42. class Producto:
  43.     def __init__(self, db):
  44.         self.db = db
  45.    
  46.     def listar(self):
  47.         return self.db.execute_query("""
  48.            SELECT p.*, u.nombreUnidad
  49.            FROM productos p
  50.            JOIN unidadesproducto u ON p.idUnidadBase = u.idUnidad
  51.        """)
  52.    
  53.     def obtener(self, id_producto):
  54.         result = self.db.execute_query(
  55.             "SELECT * FROM productos WHERE idProducto = %s",
  56.             (id_producto,)
  57.         )
  58.         return result[0] if result else None
  59.    
  60.     def obtener_equivalencias(self, id_producto):
  61.         return self.db.execute_query(
  62.             "SELECT * FROM equivalencias WHERE idProducto = %s",
  63.             (id_producto,)
  64.         )
  65.    
  66.     def existe_nombre(self, nombre):
  67.         result = self.db.execute_query(
  68.             "SELECT idProducto FROM productos WHERE nombreProducto = %s",
  69.             (nombre,)
  70.         )
  71.         return bool(result)
  72.    
  73.     def insertar(self, codigo, nombre, id_unidad_base, stock):
  74.         return self.db.execute_insert(
  75.             """INSERT INTO productos
  76.            (codigoProducto, nombreProducto, idUnidadBase, stockInicial)
  77.            VALUES (%s, %s, %s, %s)""",
  78.             (codigo, nombre, id_unidad_base, stock)
  79.         )
  80.    
  81.     def obtener_movimientos(self):
  82.         return self.db.execute_query("""
  83.            SELECT p.idProducto,
  84.                   SUM(CASE WHEN m.tipoMovimiento = 'ENTRADA' THEN m.cantidad ELSE 0 END) as entradas,
  85.                   SUM(CASE WHEN m.tipoMovimiento = 'SALIDA' THEN m.cantidad ELSE 0 END) as salidas
  86.            FROM productos p
  87.            LEFT JOIN movimientos m ON p.idProducto = m.idProducto
  88.            GROUP BY p.idProducto
  89.        """)
  90.  
  91. def print_tabla(header, rows):
  92.     if not rows:
  93.         print("No hay datos para mostrar")
  94.         return
  95.    
  96.     column_widths = [len(str(campo)) for campo in header]
  97.     for row in rows:
  98.         for i, campo in enumerate(row):
  99.             column_widths[i] = max(column_widths[i], len(str(campo)))
  100.    
  101.     border = "+" + "+".join(["-" * (w + 2) for w in column_widths]) + "+"
  102.     row_format = "| " + " | ".join(["{:<" + str(w) + "}" for w in column_widths]) + " |"
  103.    
  104.     print(border)
  105.     print(row_format.format(*header))
  106.     print(border)
  107.     for row in rows:
  108.         print(row_format.format(*row))
  109.     print(border)
  110.  
  111. def registrar_unidades(db):
  112.     print("\nREGISTRO DE UNIDADES (0 para volver)")
  113.     nombre = input("Nombre de la unidad: ").strip()
  114.     if nombre == "0":
  115.         return
  116.     if not nombre:
  117.         print("El nombre no puede estar vacío")
  118.         return
  119.    
  120.     try:
  121.         db.execute_insert(
  122.             "INSERT INTO unidadesproducto (nombreUnidad) VALUES (%s)",
  123.             (nombre,)
  124.         )
  125.         print("\n¡Unidad registrada exitosamente!")
  126.     except Exception as e:
  127.         print(f"\nError al registrar unidad: {str(e)}")
  128.  
  129. def listar_unidades(db):
  130.     unidades = UnidadProducto(db).listar()
  131.     if not unidades:
  132.         print("\nNo hay unidades registradas")
  133.         return
  134.    
  135.     header = ["N°", "NOMBRE DE UNIDAD"]
  136.     rows = [(str(i+1), u['nombreUnidad']) for i, u in enumerate(unidades)]
  137.    
  138.     print("\nLISTADO DE UNIDADES REGISTRADAS")
  139.     print_tabla(header, rows)
  140.  
  141. def listar_productos(db):
  142.     productos = Producto(db).listar()
  143.     if not productos:
  144.         print("\nNo hay productos registrados")
  145.         return
  146.    
  147.     header = ["N°", "CÓDIGO", "NOMBRE DEL PRODUCTOS", "UNIDAD BASE"]
  148.     rows = []
  149.     for i, p in enumerate(productos, 1):
  150.         rows.append((
  151.             f"{i:02d}",
  152.             p['codigoProducto'],
  153.             p['nombreProducto'],
  154.             p['nombreUnidad']
  155.         ))
  156.    
  157.     print("\nLISTADO DE PRODUCTOS REGISTRADOS")
  158.     print_tabla(header, rows)
  159.  
  160. def registrar_producto(db):
  161.     print("\nREGISTRO DE PRODUCTO (0 para volver)")
  162.     producto = Producto(db)
  163.     unidades = UnidadProducto(db)
  164.    
  165.     while True:
  166.         nombre = input("Nombre del producto: ").strip()
  167.         if nombre == "0":
  168.             return
  169.         if not nombre:
  170.             print("El nombre no puede estar vacío")
  171.             continue
  172.         if producto.existe_nombre(nombre):
  173.             print("¡El producto ya existe!")
  174.         else:
  175.             break
  176.  
  177.     # Continúa en la siguiente parte...
  178.  
  179.  
  180.     while True:
  181.         try:
  182.             num_medidas = int(input("\n¿Cuántas medidas para cuantificar el producto? (1-4): "))
  183.             if 1 <= num_medidas <= 4:
  184.                 break
  185.             print("Debe ser un número entre 1 y 4")
  186.         except ValueError:
  187.             print("Entrada inválida, debe ser un número")
  188.    
  189.     unidades_seleccionadas = []
  190.     for i in range(num_medidas):
  191.         while True:
  192.             unidades_disponibles = unidades.listar()
  193.             print(f"\nSelección de medida {i+1}:")
  194.             print("Unidades disponibles:")
  195.            
  196.             for idx, u in enumerate(unidades_disponibles, 1):
  197.                 print(f"{idx}. {u['nombreUnidad']}")
  198.             print(f"{len(unidades_disponibles)+1}. Agregar nueva unidad")
  199.            
  200.             try:
  201.                 opcion = int(input("Seleccione una opción: "))
  202.                 if 1 <= opcion <= len(unidades_disponibles):
  203.                     unidades_seleccionadas.append(unidades_disponibles[opcion-1])
  204.                     break
  205.                 elif opcion == len(unidades_disponibles)+1:
  206.                     nombre_unidad = input("Nombre de la nueva unidad: ").strip()
  207.                     if not nombre_unidad:
  208.                         print("El nombre no puede estar vacío")
  209.                         continue
  210.                     db.execute_insert(
  211.                         "INSERT INTO unidadesproducto (nombreUnidad) VALUES (%s)",
  212.                         (nombre_unidad,)
  213.                     )
  214.                     print("¡Nueva unidad registrada!")
  215.                 else:
  216.                     print("Opción inválida")
  217.             except ValueError:
  218.                 print("Entrada inválida, debe ser un número")
  219.    
  220.     equivalencias = []
  221.     for i in range(num_medidas-1):
  222.         while True:
  223.             try:
  224.                 cantidad = int(input(
  225.                     f"\n1 {unidades_seleccionadas[i+1]['nombreUnidad']} = ¿Cuántas {unidades_seleccionadas[i]['nombreUnidad']}? "
  226.                 ))
  227.                 if cantidad > 0:
  228.                     equivalencias.append((
  229.                         unidades_seleccionadas[i+1]['idUnidad'],
  230.                         unidades_seleccionadas[i]['idUnidad'],
  231.                         cantidad
  232.                     ))
  233.                     break
  234.                 print("La cantidad debe ser mayor a 0")
  235.             except ValueError:
  236.                 print("Entrada inválida, debe ser un número")
  237.    
  238.     while True:
  239.         print("\nSelección de unidad para stock inicial:")
  240.         for idx, u in enumerate(unidades_seleccionadas, 1):
  241.             print(f"{idx}. {u['nombreUnidad']}")
  242.         try:
  243.             opcion = int(input("Seleccione una opción: ")) - 1
  244.             if 0 <= opcion < len(unidades_seleccionadas):
  245.                 unidad_stock = unidades_seleccionadas[opcion]
  246.                 stock = int(input("Stock inicial: "))
  247.                 if stock < 0:
  248.                     print("El stock no puede ser negativo")
  249.                     continue
  250.                 break
  251.         except ValueError:
  252.             print("Entrada inválida")
  253.    
  254.     factor = 1
  255.     for i in range(opcion):
  256.         factor *= equivalencias[i][2]
  257.     stock_base = stock * factor
  258.    
  259.     next_id = db.get_next_auto_increment('productos')
  260.     codigo = f"ACU-{next_id:02d}"
  261.    
  262.     id_producto = producto.insertar(
  263.         codigo,
  264.         nombre,
  265.         unidades_seleccionadas[0]['idUnidad'],
  266.         stock_base
  267.     )
  268.    
  269.     for sup, inf, cant in equivalencias:
  270.         db.execute_insert(
  271.             """INSERT INTO equivalencias
  272.            (idProducto, idUnidadSuperior, idUnidadInferior, cantidadEquivalente)
  273.            VALUES (%s, %s, %s, %s)""",
  274.             (id_producto, sup, inf, cant)
  275.         )
  276.    
  277.     fecha_registro = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  278.     header = ["CÓDIGO", "NOMBRE DEL PRODUCTO", "STOCK", "UNIDAD", "F. REGISTRO"]
  279.     row = [codigo, nombre, str(stock), unidad_stock['nombreUnidad'], fecha_registro]
  280.    
  281.     print("\n¡PRODUCTO REGISTRADO EXITOSAMENTE!")
  282.     print_tabla(header, [row])
  283.  
  284. def registrar_entrada(db):
  285.     print("\nREGISTRO DE ENTRADA DE PRODUCTOS (0 para volver)")
  286.    
  287.     productos = Producto(db).listar()
  288.     if not productos:
  289.         print("No hay productos registrados")
  290.         return
  291.    
  292.     print("\nSeleccione un producto:")
  293.     header = ["N°", "CÓDIGO", "NOMBRE DEL PRODUCTO", "STOCK", "UNIDAD"]
  294.     rows = [(str(i+1), p['codigoProducto'], p['nombreProducto'], str(p['stockInicial']), p['nombreUnidad'])
  295.             for i, p in enumerate(productos)]
  296.     print_tabla(header, rows)
  297.    
  298.     try:
  299.         opcion = input("\nIngrese el número de producto (0 para volver): ").strip()
  300.         if opcion == "0":
  301.             return
  302.         opcion = int(opcion) - 1
  303.         producto = productos[opcion]
  304.     except (ValueError, IndexError):
  305.         print("Selección inválida")
  306.         return
  307.    
  308.     unidades_ids = {producto['idUnidadBase']}
  309.     equivalencias = db.execute_query(
  310.         "SELECT idUnidadSuperior, idUnidadInferior FROM equivalencias WHERE idProducto = %s",
  311.         (producto['idProducto'],)
  312.     )
  313.     for eq in equivalencias:
  314.         unidades_ids.add(eq['idUnidadSuperior'])
  315.         unidades_ids.add(eq['idUnidadInferior'])
  316.    
  317.     unidades = []
  318.     for uid in unidades_ids:
  319.         unidad = db.execute_query(
  320.             "SELECT * FROM unidadesproducto WHERE idUnidad = %s",
  321.             (uid,)
  322.         )
  323.         if unidad:
  324.             unidades.append(unidad[0])
  325.    
  326.     if not unidades:
  327.         print("No hay unidades asociadas al producto")
  328.         return
  329.    
  330.     print("\nUnidades disponibles para este producto:")
  331.     header = ["N°", "NOMBRE DE UNIDAD"]
  332.     rows = [(str(i+1), u['nombreUnidad']) for i, u in enumerate(unidades)]
  333.     print_tabla(header, rows)
  334.    
  335.     try:
  336.         opcion_unidad = int(input("\nIngrese el número de unidad: ")) - 1
  337.         unidad = unidades[opcion_unidad]
  338.     except (ValueError, IndexError):
  339.         print("Selección inválida")
  340.         return
  341.    
  342.     factor = 1
  343.     current_unit = unidad['idUnidad']
  344.     base_unit = producto['idUnidadBase']
  345.     equivalencias = db.execute_query(
  346.         "SELECT * FROM equivalencias WHERE idProducto = %s",
  347.         (producto['idProducto'],)
  348.     )
  349.    
  350.     while current_unit != base_unit:
  351.         encontrado = False
  352.         for eq in equivalencias:
  353.             if eq['idUnidadSuperior'] == current_unit:
  354.                 factor *= eq['cantidadEquivalente']
  355.                 current_unit = eq['idUnidadInferior']
  356.                 encontrado = True
  357.                 break
  358.         if not encontrado:
  359.             print("No se puede convertir a la unidad base")
  360.             return
  361.    
  362.     try:
  363.         stock = int(input("\nStock de ingreso: "))
  364.         if stock <= 0:
  365.             print("El stock debe ser mayor a 0")
  366.             return
  367.     except ValueError:
  368.         print("Valor inválido")
  369.         return
  370.    
  371.     documentos = db.execute_query("SELECT * FROM documentos")
  372.     print("\nSeleccione tipo de documento:")
  373.     for i, doc in enumerate(documentos, 1):
  374.         print(f"{i}. {doc['nombreDocumento']}")
  375.    
  376.     try:
  377.         doc_opcion = int(input("Opción: ")) - 1
  378.         documento = documentos[doc_opcion]
  379.     except (ValueError, IndexError):
  380.         print("Selección inválida")
  381.         return
  382.    
  383.     numero_doc = input("Número de documento: ").strip()
  384.    
  385.     # Seleccionar proveedor
  386.     proveedores = db.execute_query(
  387.         "SELECT * FROM entidades WHERE tipoEntidad = 'EMPRESA'"
  388.     )
  389.     if not proveedores:
  390.         print("\nNo hay proveedores registrados. Registre uno primero.")
  391.         return
  392.    
  393.     print("\nLISTADO DE PROVEEDORES REGISTRADOS")
  394.     header = ["N°", "TIPO", "DOCUMENTO", "NOMBRE"]
  395.     rows = [(str(i+1), p['tipoDocumento'], p['numeroDocumento'], p['nomEntidad'])
  396.             for i, p in enumerate(proveedores)]
  397.     print_tabla(header, rows)
  398.    
  399.     try:
  400.         opcion = int(input("\nSeleccione proveedor (0 para cancelar): "))
  401.         if opcion == 0:
  402.             return
  403.         proveedor = proveedores[opcion-1]['numeroDocumento']
  404.     except:
  405.         print("Selección inválida")
  406.         return
  407.  
  408.     fecha = input("Ingrese fecha (DD-MM-AA) o 0 para fecha actual: ").strip()
  409.     if fecha == '0':
  410.         fecha_movimiento = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  411.     else:
  412.         try:
  413.             fecha_dt = datetime.strptime(fecha, '%d-%m-%y')
  414.             fecha_movimiento = fecha_dt.strftime('%Y-%m-%d %H:%M:%S')
  415.         except ValueError:
  416.             print("Formato de fecha inválido, usando fecha actual")
  417.             fecha_movimiento = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  418.    
  419.     stock_base = stock * factor
  420.    
  421.     try:
  422.         db.execute_insert(
  423.             """INSERT INTO movimientos
  424.            (tipoMovimiento, idProducto, cantidad, idDocumento,
  425.             numeroDocumento, proveedor, fechaMovimiento)
  426.            VALUES (%s, %s, %s, %s, %s, %s, %s)""",
  427.             ('ENTRADA', producto['idProducto'], stock_base,
  428.              documento['idDocumento'], numero_doc, proveedor, fecha_movimiento)
  429.         )
  430.         print("\n¡Entrada registrada exitosamente!")
  431.     except Exception as e:
  432.         print(f"Error al registrar entrada: {str(e)}")
  433.  
  434. # Continúa en la siguiente parte...
  435.  
  436.  
  437.  
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446.  
  447. def registrar_salida(db):
  448.     print("\nREGISTRO DE SALIDA DE PRODUCTOS (0 para volver)")
  449.    
  450.     productos = Producto(db).listar()
  451.     if not productos:
  452.         print("No hay productos registrados")
  453.         return
  454.    
  455.     print("\nSeleccione un producto:")
  456.     header = ["N°", "CÓDIGO", "NOMBRE DEL PRODUCTO", "STOCK", "UNIDAD"]
  457.     rows = [(str(i+1), p['codigoProducto'], p['nombreProducto'], str(p['stockInicial']), p['nombreUnidad'])
  458.             for i, p in enumerate(productos)]
  459.     print_tabla(header, rows)
  460.    
  461.     try:
  462.         opcion = input("\nIngrese el número de producto (0 para volver): ").strip()
  463.         if opcion == "0":
  464.             return
  465.         opcion = int(opcion) - 1
  466.         producto = productos[opcion]
  467.     except (ValueError, IndexError):
  468.         print("Selección inválida")
  469.         return
  470.    
  471.     unidades_ids = {producto['idUnidadBase']}
  472.     equivalencias = db.execute_query(
  473.         "SELECT idUnidadSuperior, idUnidadInferior FROM equivalencias WHERE idProducto = %s",
  474.         (producto['idProducto'],)
  475.     )
  476.     for eq in equivalencias:
  477.         unidades_ids.add(eq['idUnidadSuperior'])
  478.         unidades_ids.add(eq['idUnidadInferior'])
  479.    
  480.     unidades = []
  481.     for uid in unidades_ids:
  482.         unidad = db.execute_query(
  483.             "SELECT * FROM unidadesproducto WHERE idUnidad = %s",
  484.             (uid,)
  485.         )
  486.         if unidad:
  487.             unidades.append(unidad[0])
  488.    
  489.     if not unidades:
  490.         print("No hay unidades asociadas al producto")
  491.         return
  492.    
  493.     print("\nUnidades disponibles para este producto:")
  494.     header = ["N°", "NOMBRE DE UNIDAD"]
  495.     rows = [(str(i+1), u['nombreUnidad']) for i, u in enumerate(unidades)]
  496.     print_tabla(header, rows)
  497.    
  498.     try:
  499.         opcion_unidad = int(input("\nIngrese el número de unidad: ")) - 1
  500.         unidad = unidades[opcion_unidad]
  501.     except (ValueError, IndexError):
  502.         print("Selección inválida")
  503.         return
  504.    
  505.     factor = 1
  506.     current_unit = unidad['idUnidad']
  507.     base_unit = producto['idUnidadBase']
  508.     equivalencias = db.execute_query(
  509.         "SELECT * FROM equivalencias WHERE idProducto = %s",
  510.         (producto['idProducto'],)
  511.     )
  512.    
  513.     while current_unit != base_unit:
  514.         encontrado = False
  515.         for eq in equivalencias:
  516.             if eq['idUnidadSuperior'] == current_unit:
  517.                 factor *= eq['cantidadEquivalente']
  518.                 current_unit = eq['idUnidadInferior']
  519.                 encontrado = True
  520.                 break
  521.         if not encontrado:
  522.             print("No se puede convertir a la unidad base")
  523.             return
  524.    
  525.     try:
  526.         stock = int(input("\nStock de salida: "))
  527.         if stock <= 0:
  528.             print("El stock debe ser mayor a 0")
  529.             return
  530.        
  531.         stock_base_total = producto['stockInicial'] + sum(
  532.             m['cantidad'] for m in db.execute_query(
  533.                 "SELECT cantidad FROM movimientos WHERE idProducto = %s AND tipoMovimiento = 'ENTRADA'",
  534.                 (producto['idProducto'],)
  535.             )
  536.         ) - sum(
  537.             m['cantidad'] for m in db.execute_query(
  538.                 "SELECT cantidad FROM movimientos WHERE idProducto = %s AND tipoMovimiento = 'SALIDA'",
  539.                 (producto['idProducto'],)
  540.             )
  541.         )
  542.        
  543.         if (stock * factor) > stock_base_total:
  544.             print("No hay suficiente stock disponible")
  545.             return
  546.            
  547.     except ValueError:
  548.         print("Valor inválido")
  549.         return
  550.    
  551.     # Seleccionar usuario
  552.     usuarios = db.execute_query(
  553.         "SELECT * FROM entidades WHERE tipoEntidad = 'USUARIO'"
  554.     )
  555.     if not usuarios:
  556.         print("\nNo hay usuarios registrados. Registre uno primero.")
  557.         return
  558.    
  559.     print("\nLISTADO DE USUARIOS REGISTRADOS")
  560.     header = ["N°", "TIPO", "DOCUMENTO", "NOMBRE"]
  561.     rows = [(str(i+1), u['tipoDocumento'], u['numeroDocumento'], u['nomEntidad'])
  562.             for i, u in enumerate(usuarios)]
  563.     print_tabla(header, rows)
  564.    
  565.     try:
  566.         opcion = int(input("\nSeleccione usuario (0 para cancelar): "))
  567.         if opcion == 0:
  568.             return
  569.         usuario = usuarios[opcion-1]['numeroDocumento']
  570.     except:
  571.         print("Selección inválida")
  572.         return
  573.  
  574.     fecha = input("Ingrese fecha (DD-MM-AA) o 0 para fecha actual: ").strip()
  575.     if fecha == '0':
  576.         fecha_movimiento = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  577.     else:
  578.         try:
  579.             fecha_dt = datetime.strptime(fecha, '%d-%m-%y')
  580.             fecha_movimiento = fecha_dt.strftime('%Y-%m-%d %H:%M:%S')
  581.         except ValueError:
  582.             print("Formato de fecha inválido, usando fecha actual")
  583.             fecha_movimiento = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  584.    
  585.     stock_base = stock * factor
  586.    
  587.     try:
  588.         db.execute_insert(
  589.             """INSERT INTO movimientos
  590.            (tipoMovimiento, idProducto, cantidad, proveedor, fechaMovimiento)
  591.            VALUES (%s, %s, %s, %s, %s)""",
  592.             ('SALIDA', producto['idProducto'], stock_base, usuario, fecha_movimiento)
  593.         )
  594.         print("\n¡Salida registrada exitosamente!")
  595.     except Exception as e:
  596.         print(f"Error al registrar salida: {str(e)}")
  597.  
  598. def reporte_movimientos(db):
  599.     productos = Producto(db).listar()
  600.     movimientos = Producto(db).obtener_movimientos()
  601.    
  602.     if not productos:
  603.         print("\nNo hay productos registrados")
  604.         return
  605.    
  606.     header = ["N°", "CÓDIGO", "NOMBRE DEL PRODUCTO", "STOCK BASE",
  607.               "STOCK INGRESO", "STOCK SALIDA", "STOCK REAL", "UNIDAD"]
  608.    
  609.     rows = []
  610.     for i, p in enumerate(productos, 1):
  611.         mov = next((m for m in movimientos if m['idProducto'] == p['idProducto']), None)
  612.         entradas = mov['entradas'] if mov else 0
  613.         salidas = mov['salidas'] if mov else 0
  614.         stock_real = p['stockInicial'] + entradas - salidas
  615.        
  616.         rows.append((
  617.             f"{i:02d}",
  618.             p['codigoProducto'],
  619.             p['nombreProducto'],
  620.             str(p['stockInicial']),
  621.             str(entradas),
  622.             str(salidas),
  623.             str(stock_real),
  624.             p['nombreUnidad']
  625.         ))
  626.    
  627.     print("\nREPORTE DE MOVIMIENTOS")
  628.     print_tabla(header, rows)
  629.  
  630. def reporte_ingresos(db, por_producto=False):
  631.     query = """
  632.        SELECT m.*, p.codigoProducto, p.nombreProducto,
  633.               u.nombreUnidad, e.nomEntidad
  634.        FROM movimientos m
  635.        JOIN productos p ON m.idProducto = p.idProducto
  636.        JOIN unidadesproducto u ON p.idUnidadBase = u.idUnidad
  637.        LEFT JOIN entidades e ON m.proveedor = e.numeroDocumento
  638.        WHERE m.tipoMovimiento = 'ENTRADA'
  639.    """
  640.    
  641.     if por_producto:
  642.         productos = db.execute_query("SELECT * FROM productos")
  643.         print("\nSeleccione un producto:")
  644.         header = ["N°", "CÓDIGO", "NOMBRE DEL PRODUCTO"]
  645.         rows = [(str(i+1), p['codigoProducto'], p['nombreProducto'])
  646.                 for i, p in enumerate(productos)]
  647.         print_tabla(header, rows)
  648.        
  649.         try:
  650.             opcion = int(input("\nIngrese el número de producto: ")) - 1
  651.             id_producto = productos[opcion]['idProducto']
  652.             query += f" AND m.idProducto = {id_producto}"
  653.         except:
  654.             print("Selección inválida")
  655.             return
  656.  
  657.     movimientos = db.execute_query(query)
  658.    
  659.     if not movimientos:
  660.         print("\nNo hay movimientos registrados")
  661.         return
  662.    
  663.     header = ["N°", "CÓDIGO", "PRODUCTO", "CANTIDAD", "UNIDAD", "PROVEEDOR", "FECHA"]
  664.     rows = []
  665.     for i, m in enumerate(movimientos, 1):
  666.         rows.append((
  667.             f"{i:02d}",
  668.             m['codigoProducto'],
  669.             m['nombreProducto'],
  670.             str(m['cantidad']),
  671.             m['nombreUnidad'],
  672.             m['nomEntidad'] or 'N/A',
  673.             m['fechaMovimiento'].strftime('%d/%m/%Y')
  674.         ))
  675.    
  676.     print("\nREPORTE DE INGRESOS" + (" POR PRODUCTO" if por_producto else ""))
  677.     print_tabla(header, rows)
  678.  
  679. def reporte_salidas(db, por_producto=False):
  680.     query = """
  681.        SELECT m.*, p.codigoProducto, p.nombreProducto,
  682.               u.nombreUnidad, e.nomEntidad
  683.        FROM movimientos m
  684.        JOIN productos p ON m.idProducto = p.idProducto
  685.        JOIN unidadesproducto u ON p.idUnidadBase = u.idUnidad
  686.        LEFT JOIN entidades e ON m.proveedor = e.numeroDocumento
  687.        WHERE m.tipoMovimiento = 'SALIDA'
  688.        ORDER BY m.fechaMovimiento DESC
  689.    """
  690.    
  691.     if por_producto:
  692.         productos = db.execute_query("SELECT * FROM productos")
  693.         print("\nSeleccione un producto:")
  694.         header = ["N°", "CÓDIGO", "NOMBRE DEL PRODUCTO"]
  695.         rows = [(str(i+1), p['codigoProducto'], p['nombreProducto'])
  696.                 for i, p in enumerate(productos)]
  697.         print_tabla(header, rows)
  698.        
  699.         try:
  700.             opcion = int(input("\nIngrese el número de producto: ")) - 1
  701.             id_producto = productos[opcion]['idProducto']
  702.             query += f" AND m.idProducto = {id_producto}"
  703.         except:
  704.             print("Selección inválida")
  705.             return
  706.  
  707.     movimientos = db.execute_query(query)
  708.    
  709.     if not movimientos:
  710.         print("\nNo hay movimientos registrados")
  711.         return
  712.    
  713.     header = ["N°", "CÓDIGO", "PRODUCTO", "CANTIDAD", "UNIDAD", "USUARIO", "FECHA"]
  714.     rows = []
  715.     for i, m in enumerate(movimientos, 1):
  716.         rows.append((
  717.             f"{i:02d}",
  718.             m['codigoProducto'],
  719.             m['nombreProducto'],
  720.             str(m['cantidad']),
  721.             m['nombreUnidad'],
  722.             m['nomEntidad'] or 'N/A',
  723.             m['fechaMovimiento'].strftime('%d/%m/%Y')
  724.         ))
  725.    
  726.     print("\nREPORTE DE SALIDAS" + (" POR PRODUCTO" if por_producto else ""))
  727.     print_tabla(header, rows)
  728.  
  729. def registrar_entidad(db):
  730.     print("\nREGISTRO DE ENTIDAD (0 para volver)")
  731.    
  732.     while True:
  733.         print("Tipo de entidad:")
  734.         print("1. USUARIO")
  735.         print("2. EMPRESA")
  736.         print("0. Volver")
  737.         opcion_tipo = input("Seleccione una opción: ").strip()
  738.        
  739.         if opcion_tipo == "0":
  740.             return
  741.         if opcion_tipo == '1':
  742.             tipo_entidad = 'USUARIO'
  743.             tipo_doc = 'DNI'
  744.             break
  745.         elif opcion_tipo == '2':
  746.             tipo_entidad = 'EMPRESA'
  747.             tipo_doc = 'RUC'
  748.             break
  749.         else:
  750.             print("Opción inválida")
  751.  
  752.     while True:
  753.         numero_doc = input(f"Ingrese {tipo_doc} (1 para generar DNI especial): ").strip()
  754.        
  755.         if tipo_doc == 'DNI':
  756.             if numero_doc == "1":
  757.                 # Se consulta el máximo DNI especial (los que comienzan con '999')
  758.                 resultado = db.execute_query(
  759.                     "SELECT MAX(numeroDocumento) AS maxDNI FROM entidades WHERE numeroDocumento LIKE '999%'"
  760.                 )
  761.                 if resultado and resultado[0]['maxDNI'] is not None:
  762.                     nuevo_dni = int(resultado[0]['maxDNI']) + 1
  763.                 else:
  764.                     nuevo_dni = 99900001  # Valor inicial si no existe ningún DNI especial
  765.                 numero_doc = str(nuevo_dni)
  766.             elif numero_doc == "0":
  767.                 return
  768.        
  769.         # Si el número ingresado NO es un DNI especial (no comienza con "999"),
  770.         # se verifica que no exista ya en la base de datos.
  771.         if not numero_doc.startswith("999"):
  772.             existe = db.execute_query(
  773.                 "SELECT idEntidad FROM entidades WHERE numeroDocumento = %s",
  774.                 (numero_doc,)
  775.             )
  776.             if existe:
  777.                 print(f"¡El {tipo_doc} ya existe en el sistema!")
  778.                 continue
  779.        
  780.         if tipo_doc == 'DNI' and len(numero_doc) == 8 and numero_doc.isdigit():
  781.             break
  782.         elif tipo_doc == 'RUC' and len(numero_doc) == 11 and numero_doc.isdigit():
  783.             break
  784.         print(f"{tipo_doc} inválido. Debe tener {8 if tipo_doc == 'DNI' else 11} dígitos")
  785.  
  786.     nombre_entidad = input("Nombre de la entidad: ").strip()
  787.  
  788.     try:
  789.         db.execute_insert(
  790.             """INSERT INTO entidades
  791.            (tipoEntidad, tipoDocumento, numeroDocumento, nomEntidad)
  792.            VALUES (%s, %s, %s, %s)""",
  793.             (tipo_entidad, tipo_doc, numero_doc, nombre_entidad)
  794.         )
  795.         print("\n¡Entidad registrada exitosamente!")
  796.        
  797.         entidad = db.execute_query(
  798.             "SELECT * FROM entidades ORDER BY idEntidad DESC LIMIT 1"
  799.         )[0]
  800.        
  801.         header = ["N°", "TIPOENTIDAD", "TIPODOCUMENTO", "NUMERODOCUMENTO", "NOMENTIDAD", "FECHAREGISTRO"]
  802.         rows = [(
  803.             "01",
  804.             entidad['tipoEntidad'],
  805.             entidad['tipoDocumento'],
  806.             entidad['numeroDocumento'],
  807.             entidad['nomEntidad'],
  808.             entidad['fechaRegistro'].strftime('%d/%m/%Y')
  809.         )]
  810.         print_tabla(header, rows)
  811.        
  812.     except mysql.connector.IntegrityError:
  813.         print("\nError: El número de documento ya existe en el sistema")
  814.     except Exception as e:
  815.         print(f"\nError al registrar entidad: {str(e)}")
  816.  
  817. def listar_entidades(db):
  818.     entidades = db.execute_query("SELECT * FROM entidades")
  819.     if not entidades:
  820.         print("\nNo hay entidades registradas")
  821.         return
  822.    
  823.     header = ["N°", "TIPOENTIDAD", "TIPODOCUMENTO", "NUMERODOCUMENTO", "NOMENTIDAD", "FECHAREGISTRO"]
  824.     rows = []
  825.     for i, entidad in enumerate(entidades, 1):
  826.         rows.append((
  827.             f"{i:02d}",
  828.             entidad['tipoEntidad'],
  829.             entidad['tipoDocumento'],
  830.             entidad['numeroDocumento'],
  831.             entidad['nomEntidad'],
  832.             entidad['fechaRegistro'].strftime('%d/%m/%Y')
  833.         ))
  834.    
  835.     print("\nLISTADO DE ENTIDADES REGISTRADAS")
  836.     print_tabla(header, rows)
  837.  
  838. def menu_reportes_ingresos(db):
  839.     while True:
  840.         print("\nREPORTES DE INGRESOS")
  841.         print("1. Reporte general de todos los ingresos")
  842.         print("2. Reporte de ingresos por producto")
  843.         print("3. Volver al menú principal")
  844.        
  845.         opcion = input("Seleccione una opción: ").strip()
  846.        
  847.         if opcion == '1':
  848.             reporte_ingresos(db)
  849.         elif opcion == '2':
  850.             reporte_ingresos(db, por_producto=True)
  851.         elif opcion == '3':
  852.             break
  853.         else:
  854.             print("Opción inválida")
  855.  
  856. def menu_reportes_salidas(db):
  857.     while True:
  858.         print("\nREPORTES DE SALIDAS")
  859.         print("1. Reporte general de todas las salidas")
  860.         print("2. Reporte de salidas por producto")
  861.         print("3. Volver al menú principal")
  862.        
  863.         opcion = input("Seleccione una opción: ").strip()
  864.        
  865.         if opcion == '1':
  866.             reporte_salidas(db)
  867.         elif opcion == '2':
  868.             reporte_salidas(db, por_producto=True)
  869.         elif opcion == '3':
  870.             break
  871.         else:
  872.             print("Opción inválida")
  873.  
  874. def main():
  875.     db = Database()
  876.     while True:
  877.         print("\n" + "=" * 40)
  878.         print("SISTEMA DE GESTIÓN DE PRODUCTOS")
  879.         print("=" * 40)
  880.         print("1. Registrar unidad de medida")
  881.         print("2. Listar unidades registradas")
  882.         print("3. Registrar nuevo producto")
  883.         print("4. Listar productos registrados")
  884.         print("5. Registrar entidad (proveedor/usuario)")
  885.         print("6. Listar entidades registradas")
  886.         print("7. Registrar entrada de productos")
  887.         print("8. Registrar salida de productos")
  888.         print("9. Reporte general de movimientos")
  889.         print("10. Reportes de ingresos")
  890.         print("11. Reportes de salidas")
  891.         print("12. Salir del sistema")
  892.        
  893.         opcion = input("\nSeleccione una opción: ").strip()
  894.        
  895.         if opcion == '1':
  896.             registrar_unidades(db)
  897.         elif opcion == '2':
  898.             listar_unidades(db)
  899.         elif opcion == '3':
  900.             registrar_producto(db)
  901.         elif opcion == '4':
  902.             listar_productos(db)
  903.         elif opcion == '5':
  904.             registrar_entidad(db)
  905.         elif opcion == '6':
  906.             listar_entidades(db)
  907.         elif opcion == '7':
  908.             registrar_entrada(db)
  909.         elif opcion == '8':
  910.             registrar_salida(db)
  911.         elif opcion == '9':
  912.             reporte_movimientos(db)
  913.         elif opcion == '10':
  914.             menu_reportes_ingresos(db)
  915.         elif opcion == '11':
  916.             menu_reportes_salidas(db)
  917.         elif opcion == '12':
  918.             print("\n¡Gracias por usar el sistema!")
  919.             break
  920.         else:
  921.             print("\nOpción inválida, intente nuevamente")
  922.        
  923.         input("\nPresione Enter para continuar...")
  924.  
  925. if __name__ == "__main__":
  926.     main()
  927.        
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement