Advertisement
kuroshan1104

SG KARDEX V2

Feb 17th, 2025 (edited)
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 36.09 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.  
  435. def registrar_salida(db):
  436.     print("\nREGISTRO DE SALIDA DE PRODUCTOS (0 para volver)")
  437.    
  438.     productos = Producto(db).listar()
  439.     if not productos:
  440.         print("No hay productos registrados")
  441.         return
  442.    
  443.     print("\nSeleccione un producto:")
  444.     header = ["N°", "CÓDIGO", "NOMBRE DEL PRODUCTO", "STOCK", "UNIDAD"]
  445.     rows = [(str(i+1), p['codigoProducto'], p['nombreProducto'], str(p['stockInicial']), p['nombreUnidad'])
  446.             for i, p in enumerate(productos)]
  447.     print_tabla(header, rows)
  448.    
  449.     try:
  450.         opcion = input("\nIngrese el número de producto (0 para volver): ").strip()
  451.         if opcion == "0":
  452.             return
  453.         opcion = int(opcion) - 1
  454.         producto = productos[opcion]
  455.     except (ValueError, IndexError):
  456.         print("Selección inválida")
  457.         return
  458.    
  459.     unidades_ids = {producto['idUnidadBase']}
  460.     equivalencias = db.execute_query(
  461.         "SELECT idUnidadSuperior, idUnidadInferior FROM equivalencias WHERE idProducto = %s",
  462.         (producto['idProducto'],)
  463.     )
  464.     for eq in equivalencias:
  465.         unidades_ids.add(eq['idUnidadSuperior'])
  466.         unidades_ids.add(eq['idUnidadInferior'])
  467.    
  468.     unidades = []
  469.     for uid in unidades_ids:
  470.         unidad = db.execute_query(
  471.             "SELECT * FROM unidadesproducto WHERE idUnidad = %s",
  472.             (uid,)
  473.         )
  474.         if unidad:
  475.             unidades.append(unidad[0])
  476.    
  477.     if not unidades:
  478.         print("No hay unidades asociadas al producto")
  479.         return
  480.    
  481.     print("\nUnidades disponibles para este producto:")
  482.     header = ["N°", "NOMBRE DE UNIDAD"]
  483.     rows = [(str(i+1), u['nombreUnidad']) for i, u in enumerate(unidades)]
  484.     print_tabla(header, rows)
  485.    
  486.     try:
  487.         opcion_unidad = int(input("\nIngrese el número de unidad: ")) - 1
  488.         unidad = unidades[opcion_unidad]
  489.     except (ValueError, IndexError):
  490.         print("Selección inválida")
  491.         return
  492.    
  493.     factor = 1
  494.     current_unit = unidad['idUnidad']
  495.     base_unit = producto['idUnidadBase']
  496.     equivalencias = db.execute_query(
  497.         "SELECT * FROM equivalencias WHERE idProducto = %s",
  498.         (producto['idProducto'],)
  499.     )
  500.    
  501.     while current_unit != base_unit:
  502.         encontrado = False
  503.         for eq in equivalencias:
  504.             if eq['idUnidadSuperior'] == current_unit:
  505.                 factor *= eq['cantidadEquivalente']
  506.                 current_unit = eq['idUnidadInferior']
  507.                 encontrado = True
  508.                 break
  509.         if not encontrado:
  510.             print("No se puede convertir a la unidad base")
  511.             return
  512.    
  513.     try:
  514.         stock = int(input("\nStock de salida: "))
  515.         if stock <= 0:
  516.             print("El stock debe ser mayor a 0")
  517.             return
  518.        
  519.         stock_base_total = producto['stockInicial'] + sum(
  520.             m['cantidad'] for m in db.execute_query(
  521.                 "SELECT cantidad FROM movimientos WHERE idProducto = %s AND tipoMovimiento = 'ENTRADA'",
  522.                 (producto['idProducto'],)
  523.             )
  524.         ) - sum(
  525.             m['cantidad'] for m in db.execute_query(
  526.                 "SELECT cantidad FROM movimientos WHERE idProducto = %s AND tipoMovimiento = 'SALIDA'",
  527.                 (producto['idProducto'],)
  528.             )
  529.         )
  530.        
  531.         if (stock * factor) > stock_base_total:
  532.             print("No hay suficiente stock disponible")
  533.             return
  534.            
  535.     except ValueError:
  536.         print("Valor inválido")
  537.         return
  538.    
  539.     # Seleccionar usuario
  540.     usuarios = db.execute_query(
  541.         "SELECT * FROM entidades WHERE tipoEntidad = 'USUARIO'"
  542.     )
  543.     if not usuarios:
  544.         print("\nNo hay usuarios registrados. Registre uno primero.")
  545.         return
  546.    
  547.     print("\nLISTADO DE USUARIOS REGISTRADOS")
  548.     header = ["N°", "TIPO", "DOCUMENTO", "NOMBRE"]
  549.     rows = [(str(i+1), u['tipoDocumento'], u['numeroDocumento'], u['nomEntidad'])
  550.             for i, u in enumerate(usuarios)]
  551.     print_tabla(header, rows)
  552.    
  553.     try:
  554.         opcion = int(input("\nSeleccione usuario (0 para cancelar): "))
  555.         if opcion == 0:
  556.             return
  557.         usuario = usuarios[opcion-1]['numeroDocumento']
  558.     except:
  559.         print("Selección inválida")
  560.         return
  561.  
  562.     fecha = input("Ingrese fecha (DD-MM-AA) o 0 para fecha actual: ").strip()
  563.     if fecha == '0':
  564.         fecha_movimiento = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  565.     else:
  566.         try:
  567.             fecha_dt = datetime.strptime(fecha, '%d-%m-%y')
  568.             fecha_movimiento = fecha_dt.strftime('%Y-%m-%d %H:%M:%S')
  569.         except ValueError:
  570.             print("Formato de fecha inválido, usando fecha actual")
  571.             fecha_movimiento = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  572.    
  573.     stock_base = stock * factor
  574.    
  575.     try:
  576.         db.execute_insert(
  577.             """INSERT INTO movimientos
  578.            (tipoMovimiento, idProducto, cantidad, proveedor, fechaMovimiento)
  579.            VALUES (%s, %s, %s, %s, %s)""",
  580.             ('SALIDA', producto['idProducto'], stock_base, usuario, fecha_movimiento)
  581.         )
  582.         print("\n¡Salida registrada exitosamente!")
  583.     except Exception as e:
  584.         print(f"Error al registrar salida: {str(e)}")
  585.  
  586. def reporte_movimientos(db):
  587.     productos = Producto(db).listar()
  588.     movimientos = Producto(db).obtener_movimientos()
  589.    
  590.     if not productos:
  591.         print("\nNo hay productos registrados")
  592.         return
  593.    
  594.     header = ["N°", "CÓDIGO", "NOMBRE DEL PRODUCTO", "STOCK BASE",
  595.               "STOCK INGRESO", "STOCK SALIDA", "STOCK REAL", "UNIDAD"]
  596.    
  597.     rows = []
  598.     for i, p in enumerate(productos, 1):
  599.         mov = next((m for m in movimientos if m['idProducto'] == p['idProducto']), None)
  600.         entradas = mov['entradas'] if mov else 0
  601.         salidas = mov['salidas'] if mov else 0
  602.         stock_real = p['stockInicial'] + entradas - salidas
  603.        
  604.         rows.append((
  605.             f"{i:02d}",
  606.             p['codigoProducto'],
  607.             p['nombreProducto'],
  608.             str(p['stockInicial']),
  609.             str(entradas),
  610.             str(salidas),
  611.             str(stock_real),
  612.             p['nombreUnidad']
  613.         ))
  614.    
  615.     print("\nREPORTE DE MOVIMIENTOS")
  616.     print_tabla(header, rows)
  617.  
  618. def reporte_ingresos(db, por_producto=False):
  619.     query = """
  620.        SELECT m.*, p.codigoProducto, p.nombreProducto,
  621.               u.nombreUnidad, e.nomEntidad
  622.        FROM movimientos m
  623.        JOIN productos p ON m.idProducto = p.idProducto
  624.        JOIN unidadesproducto u ON p.idUnidadBase = u.idUnidad
  625.        LEFT JOIN entidades e ON m.proveedor = e.numeroDocumento
  626.        WHERE m.tipoMovimiento = 'ENTRADA'
  627.    """
  628.    
  629.     if por_producto:
  630.         productos = db.execute_query("SELECT * FROM productos")
  631.         print("\nSeleccione un producto:")
  632.         header = ["N°", "CÓDIGO", "NOMBRE DEL PRODUCTO"]
  633.         rows = [(str(i+1), p['codigoProducto'], p['nombreProducto'])
  634.                 for i, p in enumerate(productos)]
  635.         print_tabla(header, rows)
  636.        
  637.         try:
  638.             opcion = int(input("\nIngrese el número de producto: ")) - 1
  639.             id_producto = productos[opcion]['idProducto']
  640.             query += f" AND m.idProducto = {id_producto}"
  641.         except:
  642.             print("Selección inválida")
  643.             return
  644.  
  645.     movimientos = db.execute_query(query)
  646.    
  647.     if not movimientos:
  648.         print("\nNo hay movimientos registrados")
  649.         return
  650.    
  651.     header = ["N°", "CÓDIGO", "PRODUCTO", "CANTIDAD", "UNIDAD", "PROVEEDOR", "FECHA"]
  652.     rows = []
  653.     for i, m in enumerate(movimientos, 1):
  654.         rows.append((
  655.             f"{i:02d}",
  656.             m['codigoProducto'],
  657.             m['nombreProducto'],
  658.             str(m['cantidad']),
  659.             m['nombreUnidad'],
  660.             m['nomEntidad'] or 'N/A',
  661.             m['fechaMovimiento'].strftime('%d/%m/%Y')
  662.         ))
  663.    
  664.     print("\nREPORTE DE INGRESOS" + (" POR PRODUCTO" if por_producto else ""))
  665.     print_tabla(header, rows)
  666.  
  667.  
  668.  
  669. def reporte_salidas(db, por_producto=False):
  670.     query = """
  671.        SELECT m.*, p.codigoProducto, p.nombreProducto,
  672.               u.nombreUnidad, e.nomEntidad
  673.        FROM movimientos m
  674.        JOIN productos p ON m.idProducto = p.idProducto
  675.        JOIN unidadesproducto u ON p.idUnidadBase = u.idUnidad
  676.        LEFT JOIN entidades e ON m.proveedor = e.numeroDocumento
  677.        WHERE m.tipoMovimiento = 'SALIDA'
  678.        ORDER BY m.fechaMovimiento DESC
  679.    """
  680.    
  681.     if por_producto:
  682.         productos = db.execute_query("SELECT * FROM productos")
  683.         print("\nSeleccione un producto:")
  684.         header = ["N°", "CÓDIGO", "NOMBRE DEL PRODUCTO"]
  685.         rows = [(str(i+1), p['codigoProducto'], p['nombreProducto'])
  686.                 for i, p in enumerate(productos)]
  687.         print_tabla(header, rows)
  688.        
  689.         try:
  690.             opcion = int(input("\nIngrese el número de producto: ")) - 1
  691.             id_producto = productos[opcion]['idProducto']
  692.             query += f" AND m.idProducto = {id_producto}"
  693.         except:
  694.             print("Selección inválida")
  695.             return
  696.  
  697.     movimientos = db.execute_query(query)
  698.    
  699.     if not movimientos:
  700.         print("\nNo hay movimientos registrados")
  701.         return
  702.    
  703.     header = ["N°", "CÓDIGO", "PRODUCTO", "CANTIDAD", "UNIDAD", "USUARIO", "FECHA"]
  704.     rows = []
  705.     for i, m in enumerate(movimientos, 1):
  706.         rows.append((
  707.             f"{i:02d}",
  708.             m['codigoProducto'],
  709.             m['nombreProducto'],
  710.             str(m['cantidad']),
  711.             m['nombreUnidad'],
  712.             m['nomEntidad'] or 'N/A',
  713.             m['fechaMovimiento'].strftime('%d/%m/%Y')
  714.         ))
  715.    
  716.     print("\nREPORTE DE SALIDAS" + (" POR PRODUCTO" if por_producto else ""))
  717.     print_tabla(header, rows)
  718.  
  719. def reporte_salidas_por_producto(db):
  720.     """
  721.    Genera un reporte de salidas agrupadas por producto.
  722.    """
  723.     print("\nSeleccione un producto:")
  724.     productos = db.execute_query("SELECT DISTINCT p.idProducto, p.codigoProducto, p.nombreProducto FROM movimientos m "
  725.                                  "JOIN productos p ON m.idProducto = p.idProducto "
  726.                                  "WHERE m.tipoMovimiento = 'SALIDA'")
  727.    
  728.     if not productos:
  729.         print("No hay registros de salidas por producto.")
  730.         return
  731.    
  732.     # Mostrar lista de productos
  733.     header = ["N°", "CÓDIGO", "NOMBRE DEL PRODUCTO"]
  734.     rows = [(str(i+1), p['codigoProducto'], p['nombreProducto']) for i, p in enumerate(productos)]
  735.     print_tabla(header, rows)
  736.    
  737.     try:
  738.         opcion = int(input("\nIngrese el número de producto: ")) - 1
  739.         if opcion < 0 or opcion >= len(productos):
  740.             print("Selección inválida")
  741.             return
  742.         producto_seleccionado = productos[opcion]['idProducto']
  743.     except ValueError:
  744.         print("Entrada inválida")
  745.         return
  746.    
  747.     # Obtener movimientos del producto seleccionado
  748.     query = """
  749.        SELECT m.*, p.codigoProducto, p.nombreProducto, u.nombreUnidad, e.nomEntidad, m.fechaMovimiento
  750.        FROM movimientos m
  751.        JOIN productos p ON m.idProducto = p.idProducto
  752.        JOIN unidadesproducto u ON p.idUnidadBase = u.idUnidad
  753.        LEFT JOIN entidades e ON m.proveedor = e.numeroDocumento
  754.        WHERE m.tipoMovimiento = 'SALIDA' AND m.idProducto = %s
  755.    """
  756.     movimientos = db.execute_query(query, (producto_seleccionado,))
  757.    
  758.     if not movimientos:
  759.         print("No hay salidas registradas para este producto.")
  760.         return
  761.    
  762.     # Ordenar los resultados por fecha de manera descendente
  763.     movimientos.sort(key=lambda x: x['fechaMovimiento'], reverse=True)
  764.    
  765.     # Mostrar resultados
  766.     header = ["N°", "CÓDIGO", "PRODUCTO", "CANTIDAD", "UNIDAD", "USUARIO", "FECHA"]
  767.     rows = [(str(i+1), m['codigoProducto'], m['nombreProducto'], str(m['cantidad']), m['nombreUnidad'],
  768.              m['nomEntidad'] if m['nomEntidad'] else "N/A", m['fechaMovimiento'].strftime('%d/%m/%Y')) for i, m in enumerate(movimientos)]
  769.     print("\nREPORTE DE SALIDAS POR PRODUCTO")
  770.     print_tabla(header, rows)
  771.  
  772.  
  773.  
  774. def reporte_salidas_por_usuario(db):
  775.     """
  776.    Genera un reporte de salidas agrupadas por usuario.
  777.    """
  778.     print("\nSeleccione un usuario:")
  779.     usuarios = db.execute_query("SELECT DISTINCT e.numeroDocumento, e.nomEntidad FROM movimientos m "
  780.                                 "JOIN entidades e ON m.proveedor = e.numeroDocumento "
  781.                                 "WHERE m.tipoMovimiento = 'SALIDA'")
  782.    
  783.     if not usuarios:
  784.         print("No hay registros de salidas por usuario.")
  785.         return
  786.    
  787.     # Mostrar lista de usuarios
  788.     header = ["N°", "DOCUMENTO", "NOMBRE"]
  789.     rows = [(str(i+1), u['numeroDocumento'], u['nomEntidad']) for i, u in enumerate(usuarios)]
  790.     print_tabla(header, rows)
  791.    
  792.     try:
  793.         opcion = int(input("\nIngrese el número de usuario: ")) - 1
  794.         if opcion < 0 or opcion >= len(usuarios):
  795.             print("Selección inválida")
  796.             return
  797.         usuario_seleccionado = usuarios[opcion]['numeroDocumento']
  798.     except ValueError:
  799.         print("Entrada inválida")
  800.         return
  801.    
  802.     # Obtener movimientos del usuario seleccionado
  803.     query = """
  804.        SELECT m.*, p.codigoProducto, p.nombreProducto, u.nombreUnidad, m.fechaMovimiento
  805.        FROM movimientos m
  806.        JOIN productos p ON m.idProducto = p.idProducto
  807.        JOIN unidadesproducto u ON p.idUnidadBase = u.idUnidad
  808.        WHERE m.tipoMovimiento = 'SALIDA' AND m.proveedor = %s
  809.        ORDER BY m.fechaMovimiento DESC
  810.    """
  811.     movimientos = db.execute_query(query, (usuario_seleccionado,))
  812.    
  813.     if not movimientos:
  814.         print("No hay salidas registradas para este usuario.")
  815.         return
  816.    
  817.     # Ordenar los resultados por fecha de manera descendente
  818.     movimientos.sort(key=lambda x: x['fechaMovimiento'], reverse=True)
  819.    
  820.     # Mostrar resultados
  821.     header = ["N°", "CÓDIGO", "PRODUCTO", "CANTIDAD", "UNIDAD", "FECHA"]
  822.     rows = [(str(i+1), m['codigoProducto'], m['nombreProducto'], str(m['cantidad']), m['nombreUnidad'],
  823.             m['fechaMovimiento'].strftime('%d/%m/%Y')) for i, m in enumerate(movimientos)]
  824.     print("\nREPORTE DE SALIDAS POR USUARIO")
  825.     print_tabla(header, rows)
  826.  
  827. def registrar_entidad(db):
  828.     print("\nREGISTRO DE ENTIDAD (0 para volver)")
  829.    
  830.     while True:
  831.         print("Tipo de entidad:")
  832.         print("1. USUARIO")
  833.         print("2. EMPRESA")
  834.         print("0. Volver")
  835.         opcion_tipo = input("Seleccione una opción: ").strip()
  836.        
  837.         if opcion_tipo == "0":
  838.             return
  839.         if opcion_tipo == '1':
  840.             tipo_entidad = 'USUARIO'
  841.             tipo_doc = 'DNI'
  842.             break
  843.         elif opcion_tipo == '2':
  844.             tipo_entidad = 'EMPRESA'
  845.             tipo_doc = 'RUC'
  846.             break
  847.         else:
  848.             print("Opción inválida")
  849.  
  850.     while True:
  851.         numero_doc = input(f"Ingrese {tipo_doc} (1 para generar DNI especial): ").strip()
  852.        
  853.         if tipo_doc == 'DNI':
  854.             if numero_doc == "1":
  855.                 # Se consulta el máximo DNI especial (los que comienzan con '999')
  856.                 resultado = db.execute_query(
  857.                     "SELECT MAX(numeroDocumento) AS maxDNI FROM entidades WHERE numeroDocumento LIKE '999%'"
  858.                 )
  859.                 if resultado and resultado[0]['maxDNI'] is not None:
  860.                     nuevo_dni = int(resultado[0]['maxDNI']) + 1
  861.                 else:
  862.                     nuevo_dni = 99900001  # Valor inicial si no existe ningún DNI especial
  863.                 numero_doc = str(nuevo_dni)
  864.             elif numero_doc == "0":
  865.                 return
  866.        
  867.         # Si el número ingresado NO es un DNI especial (no comienza con "999"),
  868.         # se verifica que no exista ya en la base de datos.
  869.         if not numero_doc.startswith("999"):
  870.             existe = db.execute_query(
  871.                 "SELECT idEntidad FROM entidades WHERE numeroDocumento = %s",
  872.                 (numero_doc,)
  873.             )
  874.             if existe:
  875.                 print(f"¡El {tipo_doc} ya existe en el sistema!")
  876.                 continue
  877.        
  878.         if tipo_doc == 'DNI' and len(numero_doc) == 8 and numero_doc.isdigit():
  879.             break
  880.         elif tipo_doc == 'RUC' and len(numero_doc) == 11 and numero_doc.isdigit():
  881.             break
  882.         print(f"{tipo_doc} inválido. Debe tener {8 if tipo_doc == 'DNI' else 11} dígitos")
  883.  
  884.     nombre_entidad = input("Nombre de la entidad: ").strip()
  885.  
  886.     try:
  887.         db.execute_insert(
  888.             """INSERT INTO entidades
  889.            (tipoEntidad, tipoDocumento, numeroDocumento, nomEntidad)
  890.            VALUES (%s, %s, %s, %s)""",
  891.             (tipo_entidad, tipo_doc, numero_doc, nombre_entidad)
  892.         )
  893.         print("\n¡Entidad registrada exitosamente!")
  894.        
  895.         entidad = db.execute_query(
  896.             "SELECT * FROM entidades ORDER BY idEntidad DESC LIMIT 1"
  897.         )[0]
  898.        
  899.         header = ["N°", "TIPOENTIDAD", "TIPODOCUMENTO", "NUMERODOCUMENTO", "NOMENTIDAD", "FECHAREGISTRO"]
  900.         rows = [(
  901.             "01",
  902.             entidad['tipoEntidad'],
  903.             entidad['tipoDocumento'],
  904.             entidad['numeroDocumento'],
  905.             entidad['nomEntidad'],
  906.             entidad['fechaRegistro'].strftime('%d/%m/%Y')
  907.         )]
  908.         print_tabla(header, rows)
  909.        
  910.     except mysql.connector.IntegrityError:
  911.         print("\nError: El número de documento ya existe en el sistema")
  912.     except Exception as e:
  913.         print(f"\nError al registrar entidad: {str(e)}")
  914.  
  915. def listar_entidades(db):
  916.     entidades = db.execute_query("SELECT * FROM entidades")
  917.     if not entidades:
  918.         print("\nNo hay entidades registradas")
  919.         return
  920.    
  921.     header = ["N°", "TIPOENTIDAD", "TIPODOCUMENTO", "NUMERODOCUMENTO", "NOMENTIDAD", "FECHAREGISTRO"]
  922.     rows = []
  923.     for i, entidad in enumerate(entidades, 1):
  924.         rows.append((
  925.             f"{i:02d}",
  926.             entidad['tipoEntidad'],
  927.             entidad['tipoDocumento'],
  928.             entidad['numeroDocumento'],
  929.             entidad['nomEntidad'],
  930.             entidad['fechaRegistro'].strftime('%d/%m/%Y')
  931.         ))
  932.    
  933.     print("\nLISTADO DE ENTIDADES REGISTRADAS")
  934.     print_tabla(header, rows)
  935.  
  936. def menu_reportes_ingresos(db):
  937.     while True:
  938.         print("\nREPORTES DE INGRESOS")
  939.         print("1. Reporte general de todos los ingresos")
  940.         print("2. Reporte de ingresos por producto")
  941.         print("3. Volver al menú principal")
  942.        
  943.         opcion = input("Seleccione una opción: ").strip()
  944.        
  945.         if opcion == '1':
  946.             reporte_ingresos(db)
  947.         elif opcion == '2':
  948.             reporte_ingresos(db, por_producto=True)
  949.         elif opcion == '3':
  950.             break
  951.         else:
  952.             print("Opción inválida")
  953.  
  954. def menu_reportes_salidas(db):
  955.     while True:
  956.         print("\nREPORTES DE SALIDAS")
  957.         print("1. Reporte general de todas las salidas")
  958.         print("2. Reporte de salidas por producto")
  959.         print("3. Reporte de salidas por usuario")  # Nueva opción
  960.         print("4. Volver al menú principal")
  961.        
  962.         opcion = input("Seleccione una opción: ").strip()
  963.        
  964.         if opcion == '1':
  965.             reporte_salidas(db)
  966.         elif opcion == '2':
  967.             reporte_salidas_por_producto(db)
  968.         elif opcion == '3':
  969.             reporte_salidas_por_usuario(db)
  970.         elif opcion == '4':
  971.             break
  972.         else:
  973.             print("Opción inválida")
  974. def main():
  975.     db = Database()
  976.     while True:
  977.         print("\n" + "=" * 40)
  978.         print("SISTEMA DE GESTIÓN DE PRODUCTOS")
  979.         print("=" * 40)
  980.         print("1. Registrar unidad de medida")
  981.         print("2. Listar unidades registradas")
  982.         print("3. Registrar nuevo producto")
  983.         print("4. Listar productos registrados")
  984.         print("5. Registrar entidad (proveedor/usuario)")
  985.         print("6. Listar entidades registradas")
  986.         print("7. Registrar entrada de productos")
  987.         print("8. Registrar salida de productos")
  988.         print("9. Reporte general de movimientos")
  989.         print("10. Reportes de ingresos")
  990.         print("11. Reportes de salidas")
  991.         print("12. Salir del sistema")
  992.        
  993.         opcion = input("\nSeleccione una opción: ").strip()
  994.        
  995.         if opcion == '1':
  996.             registrar_unidades(db)
  997.         elif opcion == '2':
  998.             listar_unidades(db)
  999.         elif opcion == '3':
  1000.             registrar_producto(db)
  1001.         elif opcion == '4':
  1002.             listar_productos(db)
  1003.         elif opcion == '5':
  1004.             registrar_entidad(db)
  1005.         elif opcion == '6':
  1006.             listar_entidades(db)
  1007.         elif opcion == '7':
  1008.             registrar_entrada(db)
  1009.         elif opcion == '8':
  1010.             registrar_salida(db)
  1011.         elif opcion == '9':
  1012.             reporte_movimientos(db)
  1013.         elif opcion == '10':
  1014.             menu_reportes_ingresos(db)
  1015.         elif opcion == '11':
  1016.             menu_reportes_salidas(db)
  1017.         elif opcion == '12':
  1018.             print("\n¡Gracias por usar el sistema!")
  1019.             break
  1020.         else:
  1021.             print("\nOpción inválida, intente nuevamente")
  1022.        
  1023.         input("\nPresione Enter para continuar...")
  1024.  
  1025. if __name__ == "__main__":
  1026.     main()
  1027.        
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement