def __run_reporte(self): model_producto = DataModel('Producto') model_proveedor = DataModel('Proveedor') if self.__agotados: productos = model_producto.get_records_from_query('SELECT * FROM Producto WHERE existencia <= 0 ORDER BY nombre ASC') else: productos = model_producto.get_records(order='nombre ASC') c = canvas.Canvas('ReporteProductos.pdf', pagesize=landscape(letter)) self.__add_page_header(c) total = 0 if len(productos) > 0: y = 490 for producto in productos: c.drawString(20, y, str(producto['id'])) nombre = producto['nombre'] if len(producto['nombre']) <= 20 else producto['nombre'][:19] c.drawRightString(270, y, nombre) proveedor = model_proveedor.get_record(producto['proveedor']) if proveedor: prov_nombre = proveedor['nombre'] if len(proveedor['nombre']) <= 20 else proveedor['nombre'][:19] c.drawRightString(460, y, prov_nombre) try: c.drawRightString(550, y, '{:20,.2f}'.format(float(producto['precio_compra']))) c.drawRightString(660, y, '{:20,.2f}'.format(float(producto['precio_venta']))) c.drawRightString(760, y, str(producto['existencia'])) except: pass y -= 20 if y <= 80: self.__add_page_footer(c) y = 490 c.showPage() self.__add_page_header(c) total += 1 c.drawRightString(650, 60, 'T O T A L D E P R O D U C T O S: ' + str(total)) self.__add_page_footer(c) c.showPage() c.save() reader = get_pdf_reader() if reader and reader['valor'] != '': subprocess.Popen([reader['valor'], "ReporteProductos.pdf"])
class VentasFactory(gtk.Frame): __id_venta = 0 def __init__(self, main): super(VentasFactory, self).__init__() self.main = main self.builder = gtk.Builder() self.builder.add_from_file("ventas_frame.glade") self.builder.connect_signals(self) content = self.builder.get_object("vbox_content") content.reparent(self) content.show() self.form_builder = FormBuilder(self.builder, 'Producto') self.producto_model = self.form_builder.get_model() self.venta_model = DataModel('Venta') self.venta_detalle_model = DataModel('VentaDetalle') self.ventas_grid = self.builder.get_object('ventas_grid') self._load_ventas_grid() self.form_builder.load_widget_value('fecha_hora_label', datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")) self.idevent = gobject.timeout_add(1000, self._update_fecha_hora) def on_buscar_producto_button_clicked(self, widget): if self.__id_venta != 0: self._show_error_message('Esta visualizando el detalle de una venta realizada, de click en el boton nuevo para realizar una nueva venta') return busqueda = BusquedaWindow('Producto', self._load_producto, search_fields={'id': 'match', 'nombre': 'like'}, display_fields=['id', 'nombre', 'precio_venta', 'existencia']) def on_buscar_button_clicked(self, widget): busqueda = BusquedaWindow('Venta', self._load_venta, search_fields={'id': 'match', 'fecha_sistema': 'match'}, display_fields=['id', 'fecha_sistema', 'sub_total', 'impuesto', 'total']) def on_agregar_button_clicked(self, widget): if self.__id_venta != 0: self._show_error_message('Esta visualizando el detalle de una venta realizada, de click en el boton nuevo para realizar una nueva venta') return id_producto = self.form_builder.get_widget_value('id_producto') if id_producto == '' or id_producto == '0': self._show_error_message('Escriba un código de producto valido') return nombre_producto = self.form_builder.get_widget_value('nombre_producto') if nombre_producto.strip() == '': self._show_error_message('Escriba una descripción del producto') return precio_producto = self.form_builder.get_widget_value('precio_producto') try: precio_producto = Decimal(precio_producto) if precio_producto < 0: raise NameError('Precio no valido') except: self._show_error_message('Escriba un precio valido') return cantidad_producto = self.form_builder.get_widget_value('cantidad_producto') try: cantidad_producto = int(cantidad_producto) if cantidad_producto == 0: raise NameError('Cantidad no valida') except: self._show_error_message('Escriba una cantidad valida') return append = True producto = self.producto_model.get_record(id_producto) if producto: if producto['existencia'] < cantidad_producto: self._show_error_message('No existe la cantidad necesaria del producto en inventario') return for row in self.ventas_grid_model: if row[0] == id_producto: row[2] = int(row[2]) + cantidad_producto row[4] = str(round(int(row[2]) * Decimal(row[3]), 2)) append = False break if append: self.ventas_grid_model.append([str(id_producto), nombre_producto, str(cantidad_producto), str(round(precio_producto, 2)), str(round(cantidad_producto * precio_producto, 2))]) self._clear_producto(True) self._ensure_ventas_grid() self._calcular_totales() gobject.source_remove(self.idevent) else: self._show_error_message('El codigo de producto no existe') def on_eliminar_butto_clicked(self, widget): if self.__id_venta != 0: self._show_error_message('Esta visualizando el detalle de una venta realizada, de click en el boton nuevo para realizar una nueva venta') return selection = self.ventas_grid.get_selection() model, treeiter = selection.get_selection_selected() if treeiter: del model[treeiter] self._ensure_ventas_grid() self._calcular_totales() def on_iva_check_toggled(self, widget): self._calcular_totales() def _load_producto(self, value): self.form_builder.load_widget_value('id_producto', value) def id_producto_key_release_event_cb(self, widget, ev, data=None): if ev.keyval == 65293: producto_id = widget.get_text() producto = self.producto_model.get_record(producto_id) self._clear_producto() if producto: self._load_producto_information(producto) def on_nuevo_button_clicked(self, widget): self.__id_venta = 0 self._clear_producto(True) self._clear_venta() self.ventas_grid_model.clear() self._ensure_ventas_grid() self._update_fecha_hora() def on_guardar_button_clicked(self, widget, upsert=False): total = self.form_builder.get_widget_value('total_label').replace(',', '').strip() cambio = 0 pago_recibido = self.form_builder.get_widget_value('pago_recibido').replace(',', '').strip() try: pago_recibido = float(pago_recibido) total_numero = float(total) if pago_recibido <= 0 or pago_recibido < total_numero: raise NameError('Cantidad no valida') else: cambio = pago_recibido - total_numero except: self._show_error_message('La cantidad recibida de pago no es valida') return if self.__id_venta == 0: if self._show_save_continue() != -9: fecha_hora = datetime.datetime.now().strftime("%Y%m%d%H%M%S") fecha_sistema = datetime.datetime.now().strftime("%Y/%m/%d") sub_total = self.form_builder.get_widget_value('subtotal_label').replace(',', '') impuesto = self.form_builder.get_widget_value('iva_label').replace(',', '') id_venta = self.venta_model.create_record({'fecha_hora': fecha_hora, 'sub_total': sub_total, 'impuesto': impuesto, 'total': total, 'fecha_sistema': fecha_sistema, 'pago_recibido': str(pago_recibido).strip(), 'cambio': str(cambio).strip()}) if id_venta: for row in self.ventas_grid_model: producto = self.producto_model.get_record(row[0]) if producto: self.venta_detalle_model.create_record({'venta_id': str(id_venta), 'producto_id': row[0].strip(), 'producto_precio': row[3].strip(), 'producto_cantidad': row[2].strip(), 'subtotal': row[4].strip(), 'nombre': row[1].strip()}) self.producto_model.update_record({ 'existencia': str(self.normalizar_existencia(producto['existencia']) - int(row[2].strip()))}, row[0].strip()) self._show_error_message('El cambio es de %s' % '{:20,.2f}'.format(float(cambio))) if not upsert: self._clear_producto(True) self._clear_venta() self.ventas_grid_model.clear() self._ensure_ventas_grid() self.idevent = gobject.timeout_add(1000, self._update_fecha_hora) else: return id_venta else: return 0 else: self._show_error_message('Esta visualizando el detalle de una venta realizada, de click en el boton nuevo para realizar una nueva venta') def on_cancelar_button_clicked(self, widget): page = self.parent.get_current_page() self.parent.remove_page(page) del self.main.pages[page] def on_imprimir_ticket_button_clicked(self, widget): if self.__id_venta == 0: self.__id_venta = self.on_guardar_button_clicked(widget, True) ticket = Ticket(self.__id_venta) if not ticket.imprimir(): self._show_error_message('No se pudo imprimir ticket, asegurese de que la venta exista') def _calcular_totales(self): subtotal = 0.00 impuesto = 0.00 total = 0.00 for row in self.ventas_grid_model: precio = Decimal(row[3]) * int(row[2]) subtotal += round(precio, 2) if self.form_builder.get_widget_value('iva_check'): impuesto = round(subtotal * 0.16, 2) self.form_builder.load_widget_value('iva_label', '{:20,.2f}'.format(impuesto)) else: self.form_builder.load_widget_value('iva_label', '0.00') total = round(subtotal + impuesto, 2) self.form_builder.load_widget_value('subtotal_label', '{:20,.2f}'.format(subtotal)) self.form_builder.load_widget_value('total_label', '{:20,.2f}'.format(total)) def _load_ventas_grid(self): self.ventas_grid_model = gtk.ListStore(str, str, str, str, str) count = 0 columns = ['Id Producto', 'Producto', 'Cantidad', 'Precio', 'Subtotal'] sizes = [50, 200, 60, 100, 100] for column in columns: render = gtk.CellRendererText() column_instance = gtk.TreeViewColumn(column, render, text=count) column_instance.set_min_width(sizes[count]) self.ventas_grid.append_column(column_instance) count += 1 self._ensure_ventas_grid() def _ensure_ventas_grid(self): self.ventas_grid.set_model(self.ventas_grid_model) self.ventas_grid.show() def _load_producto_information(self, row): self.form_builder.load_widget_value('nombre_producto', row['nombre']) self.form_builder.load_widget_value('precio_producto', row['precio_venta']) self.form_builder.load_widget_value('cantidad_producto', '0') self.builder.get_object('cantidad_producto').grab_focus() def _clear_producto(self, clear_id=False): if clear_id: self.form_builder.load_widget_value('id_producto', '') self.form_builder.load_widget_value('nombre_producto', '') self.form_builder.load_widget_value('precio_producto', '0.00') self.form_builder.load_widget_value('cantidad_producto', '0') def _clear_venta(self): self.form_builder.load_widget_value('subtotal_label', '0.00') self.form_builder.load_widget_value('total_label', '0.00') self.form_builder.load_widget_value('iva_label', '0.00') self.form_builder.load_widget_value('pago_recibido', '0.00') def _show_error_message(self, message): dialog = gtk.MessageDialog(self.parent.parent.parent, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, message) dialog.run() dialog.destroy() def _show_save_continue(self): dialog = gtk.MessageDialog(self.parent.parent.parent, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, '¿Desea guardad la venta actual?') response = dialog.run() dialog.destroy() return response def _update_fecha_hora(self): self.form_builder.load_widget_value('fecha_hora_label', datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")) self.idevent = gobject.timeout_add(1000, self._update_fecha_hora) def _load_venta(self, value): venta = self.venta_model.get_record(int(value)) if venta: self._clear_producto(True) self._clear_venta() self.ventas_grid_model.clear() self._ensure_ventas_grid() self.__id_venta = venta['id'] self.form_builder.load_widget_value('subtotal_label', '{:20,.2f}'.format(float(venta['sub_total']))) self.form_builder.load_widget_value('iva_label', '{:20,.2f}'.format(float(venta['impuesto']))) self.form_builder.load_widget_value('total_label', '{:20,.2f}'.format(float(venta['total']))) self.form_builder.load_widget_value('pago_recibido', '{:20,.2f}'.format(float(venta['pago_recibido']))) gobject.source_remove(self.idevent) self.form_builder.load_widget_value('fecha_hora_label', self._parse_fecha(str(venta['fecha_hora']))) items = self.venta_detalle_model.get_records(venta_id=venta['id']) if len(items) > 0: for item in items: self.ventas_grid_model.append([str(item['id']), item['nombre'].strip(), str(item['producto_cantidad']).strip(), str(round(item['producto_precio'], 2)).strip(), str(round(item['producto_cantidad'] * item['producto_precio'], 2)).strip()]) else: self._show_error_message('La venta seleccionada no existe') def _parse_fecha(self, fecha): year = fecha[:4] month = fecha[4:6] day = fecha[6:8] hour = fecha[8:10] minutes = fecha[10:12] seconds = fecha[12:14] return "%s/%s/%s %s:%s:%s" % (year, month, day, hour, minutes, seconds) def normalizar_existencia(self, existencia): try: existencia = int(existencia) except: if isinstance(existencia, str): number = re.match(r"\d", existencia) if number: existencia = number.group(0) else: existencia = 0 else: existencia = 0 return existencia
class FormBuilder: __fields = [] def __init__(self, builder, entity): self.builder = builder self.entity = entity self.model = DataModel(entity) self.__fields = self.model.get_colums() def get_entity(self, entity_id): row = self.model.get_record(entity_id) if row is not None: for field in self.__fields: self.load_widget_value(field, row[field]) def save_entity(self, upsert=False, custom_id=False): id = self.__get_id() values = {} for field in self.__fields: if field != 'id' or (field == 'id' and custom_id == True): values[field] = self.get_widget_value(field) if id == 0 or id == '': self.model.create_record(values) else: self.model.update_record(values, id, upsert) self.clear_form() def delete_entity(self): id = self.__get_id() if id > 0 or id != '': dialog = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, "¿Desea eliminar el registro actual?") response = dialog.run() dialog.destroy() if response == gtk.RESPONSE_YES: self.model.delete_record(id) self.clear_form() def clear_form(self): for field in self.__fields: self.load_widget_value(field, '') def load_widget_value(self, widget_name, value): widget = self.builder.get_object(widget_name) if isinstance(widget, gtk.Entry) or isinstance(widget, gtk.Label): widget.set_text(str(value)) if isinstance(widget, gtk.ComboBox): model = widget.get_model() count = 0 for row in model: if row[0] == value: widget.set_active(count) count += 1 if isinstance(widget, gtk.CheckButton): widget.set_active(True if value else False) if isinstance(widget, gtk.Calendar): widget.select_month(value[1], value[0]) widget.select_day(value[2]) def get_widget_value(self, widget_name): value = None widget = self.builder.get_object(widget_name) if isinstance(widget, gtk.Entry) or isinstance(widget, gtk.Label): value = widget.get_text() if isinstance(widget, gtk.ComboBox): model = widget.get_model() tree_iter = widget.get_active_iter() if tree_iter != None: value = str(model[tree_iter][0]) if isinstance(widget, gtk.CheckButton): value = widget.get_active() if isinstance(widget, gtk.Calendar): value = widget.get_date() return value def get_model(self): return self.model def __get_id(self): id = 0 widget = self.builder.get_object('id') if isinstance(widget, gtk.Label) or isinstance(widget, gtk.Entry): id = widget.get_text() return id
class Ticket: __meses = {1: 'Enero', 2: 'Febrero', 3: 'Marzo', 4: 'Abril', 5: 'Mayo', 6: 'Junio', 7: 'Julio', 8: 'Agosto', 9: 'Septiembre', 10: 'Octubre', 11: 'Noviembre', 12: 'Diciembre'} def __init__(self, id_venta): self.c = canvas.Canvas('Ticket.pdf') self.venta_model = DataModel('Venta') self.venta_detalle_model = DataModel('VentaDetalle') self.producto_model = DataModel('Producto') self.id_venta = id_venta def imprimir(self): #1 cm = 28.346 puntos if self.id_venta > 0: x = get_margen('margen_izquierdo') print x x = 3.92 if x is None else float(x['valor']) y = get_margen('margen_superior') print y y = 692.0 if y is None else float(y['valor']) y_inicial = y venta = self.obtener_venta() if len(venta) == 0: return False self.c.setFont("Helvetica", 8) self.c.drawString(x + 79.08, y, str(self.fecha_parser(venta['fecha'], 'dia'))) self.c.drawString(x + 118.08, y, str(self.fecha_parser(venta['fecha'], 'mes'))) self.c.drawString(x + 264.08, y, str(self.fecha_parser(venta['fecha'], 'anyo'))) y -= 48.14 items = self.venta_detalle_model.get_records(venta_id=venta['id']) if len(items) > 0: for item in items: piezas = ' piezas' if int(item['producto_cantidad']) > 1 else ' pieza' self.c.drawString(x, y, str(item['producto_cantidad']) + piezas) self.c.drawString(x + 49.91, y, item['nombre'][0:30]) self.c.drawString(x + 165.70, y, '{:20,.2f}'.format(item['producto_precio'])) self.c.drawString(x + 214.70, y, '{:20,.2f}'.format(item['subtotal'])) y -= 18.06 self.c.drawString(x + 208.08, y_inicial - 284.0, '{:20,.2f}'.format(float(venta['total']))) self.c.drawString(x + 49.08, y_inicial - 308.0, self.total_a_cadena(venta['total'])) self.c.showPage() self.c.setPageSize((432, 544)) self.c.save() reader = get_pdf_reader() if reader and reader['valor'] != '': subprocess.Popen([reader['valor'], "Ticket.pdf"]) return True else: return False def obtener_venta(self): venta_info = {} venta = self.venta_model.get_record(int(self.id_venta)) if venta: total = float(venta['total'].strip()) if not isinstance(venta['total'], float) else venta['total'] venta_info = {'id': venta['id'], 'total': total, 'fecha': venta['fecha_sistema']} return venta_info def fecha_parser(self, fecha, dato): if dato is 'dia': return int(fecha[8:10]) if dato is 'mes': mes = int(fecha[5:7]) return self.__meses[mes] if dato is 'anyo': return fecha[3:4] def total_a_cadena(self, total): total_neto = int(float(total)) cadena = to_word(total_neto) + 'Pesos' decimales = self.obtener_decimales(total) cadena += ' %s/100 M.N' % decimales return cadena def obtener_decimales(self, total): cadena = '{:20,.2f}'.format(total) decimales = '' agregar = False index = 0 while index < len(cadena): if agregar: decimales += cadena[index] if cadena[index] == '.': agregar = True index += 1 if decimales == '': decimales = '00' return decimales