From 543385d0fa9248a4980c55b1bed25c3101564c27 Mon Sep 17 00:00:00 2001 From: Wilson Gomez Date: Fri, 20 Oct 2023 16:43:40 -0500 Subject: [PATCH] new release version add option debug --- .gitignore | 1 + app/buttonpad.py | 7 +- app/commons/dblogin.py | 10 +- app/commons/dialogs.py | 3 +- app/dialogs.py | 40 +++---- app/frontwindow.py | 49 +++------ app/main.py | 238 ++++++++++++++++++++++++----------------- app/models.py | 1 - app/reporting.py | 134 ++++++++++------------- app/tools.py | 14 +++ app/version.py | 2 +- logger_config.py | 20 ++++ 12 files changed, 281 insertions(+), 238 deletions(-) create mode 100644 logger_config.py diff --git a/.gitignore b/.gitignore index 66fee04..716a4f7 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +*.log* package-lock* diff --git a/app/buttonpad.py b/app/buttonpad.py index 3b518a5..5fd5363 100644 --- a/app/buttonpad.py +++ b/app/buttonpad.py @@ -63,12 +63,15 @@ class StartButtons(QVBoxLayout): values_extend([ ['button_control_panel', 'PANEL DE CONTROL', 'action_control_panel', 'settings'], ['button_reports', 'REPORTES', 'action_reports', 'reports'], - ['button_historic_sales', 'HISTORIAL', 'action_historic_sales', 'sales_history'], ]) if parent.environment == 'retail': values_extend([ ['button_collection', 'RECAUDO', 'action_collection', 'collection'] ]) + else: + values_extend([ + ['button_historic_sales', 'HISTORIAL', 'action_historic_sales', 'sales_history'], + ]) values_extend([ ['button_help', 'AYUDA', 'action_help', 'help'], @@ -156,7 +159,7 @@ class ButtonsFunction(QGridLayout): ['button_change_salesman', 'CAMBIO VENDEDOR', 'action_change_salesman'], ]) pos_user = self.parent.type_pos_user - if pos_user in ('order' ,'salesman'): + if pos_user in ('order', 'salesman'): self.values.extend([ ['button_to_draft', 'BORRADOR', 'button_to_draft_pressed'], ['button_to_quote', 'COTIZAR', 'button_to_quote_pressed'], diff --git a/app/commons/dblogin.py b/app/commons/dblogin.py index 56df60f..65f6bb1 100644 --- a/app/commons/dblogin.py +++ b/app/commons/dblogin.py @@ -6,9 +6,8 @@ import gettext import logging import time import ssl -from collections import OrderedDict from pathlib import Path -from PySide6.QtWidgets import (QMainWindow, QDialog) +from PySide6.QtWidgets import QDialog from PySide6.QtCore import Qt, QTimer from PySide6.QtGui import QPixmap from http.client import HTTPConnection, HTTPSConnection @@ -16,6 +15,7 @@ import orjson as json from app.threads import VerifyConn from app.commons.config import Params from app.commons.ui_login import Ui_Login +from logger_config import logger context_http = ssl._create_unverified_context() _ = gettext.gettext @@ -57,8 +57,7 @@ class Login(QDialog): conn.close() option = u"online" icon_conn = path_circle_green - except Exception as e: - print(e, 'error') + except Exception: icon_conn = path_circle_red option = u"offline" self.ui.label_conn.setText(option) @@ -135,7 +134,8 @@ class Login(QDialog): msg = 'Error: conexion del servidor' elif result['status'] == 500: msg = 'Error: interno del servidor \n' + result['message'] - print(msg, 'msg ,,,,', result['status']) + logger.error(result) + logger.info(msg) self.ui.label_error.setText(msg) self.error_message() else: diff --git a/app/commons/dialogs.py b/app/commons/dialogs.py index 2b4caaf..fb1ce7a 100644 --- a/app/commons/dialogs.py +++ b/app/commons/dialogs.py @@ -7,7 +7,6 @@ from collections import OrderedDict # ) # from PyQt5.QtGui import QStandardItem, QStandardItemModel, QPixmap # from PyQt5.QtCore import Qt, pyqtSlot, QModelIndex -from operator import methodcaller from PySide6.QtWidgets import ( QDialog, QAbstractItemView, QVBoxLayout, QHBoxLayout, QLabel, QWidget, QTreeView, QLineEdit, QTableView, QCompleter @@ -179,7 +178,7 @@ class QuickDialog(QDialog): print('cancell quitdialog') try: self.parent.label_input.setFocus() - except: + except Exception: pass self.setResult(0) self.hide() diff --git a/app/dialogs.py b/app/dialogs.py index 1e3b27d..f05aa65 100644 --- a/app/dialogs.py +++ b/app/dialogs.py @@ -1,16 +1,16 @@ from decimal import Decimal from datetime import datetime -from operator import itemgetter, attrgetter +from operator import itemgetter from .commons.dialogs import HelpDialog, QuickDialog # from PyQt5.QtCore import Qt, QSize # from PyQt5.QtWidgets import ( # QCheckBox, QTextEdit, QVBoxLayout, QGridLayout, QLineEdit, QPlainTextEdit, # QScrollArea, QHBoxLayout, QDoubleSpinBox, QLabel, QMessageBox # ) -from PySide6.QtCore import Qt, QSize +from PySide6.QtCore import Qt from PySide6.QtWidgets import ( QCheckBox, QTextEdit, QVBoxLayout, QGridLayout, QLineEdit, QPlainTextEdit, - QScrollArea, QHBoxLayout, QDoubleSpinBox, QLabel, QMessageBox, QWidget + QScrollArea, QHBoxLayout, QDoubleSpinBox, QLabel, QWidget ) from .proxy import Report @@ -287,8 +287,8 @@ class SearchParty(SearchWindow): # 'street': parent.on_selected_street_party } super(SearchParty, self).__init__(parent, headers, None, methods, - filter_column=[], cols_width=[60, 120, 270, 190, 90], - title=title, fill=True) + filter_column=[], cols_width=[60, 120, 270, 190, 90], + title=title, fill=True) class SearchProduct(SearchWindow): @@ -350,7 +350,7 @@ class SearchProduct(SearchWindow): fields_names = list(headers.keys()) try: fields_names.remove('image') - except: + except Exception: pass self.fields_names = fields_names super(SearchProduct, self).__init__(parent, headers, None, methods, @@ -594,7 +594,7 @@ class DialogSaleForm(QuickDialog): elements = ( 'id', 'party.', 'number', 'sale_date', 'total_amount_cache', 'invoice_number', 'lines.' - ) + ) id, party, number, sale_date, total_amount_cache, invoice_number, lines = itemgetter(*elements)(data) self.sale_customer_selected = id self.field_party.setText(party['name']) @@ -887,7 +887,7 @@ class DialogTableDeliveryParty(QuickDialog): method_selected_row=parent.delivery_party_selected ) width, height = get_screen() - table.setFixedSize(int(width/2.2), int(height/2.2)) + table.setFixedSize(int(width / 2.2), int(height / 2.2)) vbox_ = QVBoxLayout() grid = QGridLayout() @@ -923,7 +923,7 @@ class DialogMoneyCount(QuickDialog): grid = QGridLayout() _sizes = (160, 120, 240) fields = ( - {'label': 'MONEDA', 'type': 'integer', 'readonly': True}, + {'label': 'MONEDA', 'type': 'integer', 'readonly': True}, {'label': 'CANTIDAD', 'type': 'integer', 'change': 'set_total'}, {'label': 'SUBTOTAL', 'type': 'integer', 'readonly': True}, ) @@ -1029,8 +1029,8 @@ class DialogExpenses(QuickDialog): _sizes = (140, 290, 210, 150) fields = ( - {'name': 'id', 'label': 'ID', 'type': 'integer', 'invisible': True}, - {'name': 'invoice_number', 'label': 'FACTURA', 'type': 'char'}, + {'name': 'id', 'label': 'ID', 'type': 'integer', 'invisible': True}, + {'name': 'invoice_number', 'label': 'FACTURA', 'type': 'char'}, {'name': 'description', 'label': 'DESCRIPCION', 'type': 'char'}, {'name': 'reference', 'label': 'REFERENCIA', 'type': 'char'}, {'name': 'amount', 'label': 'VALOR', 'type': 'float', 'change': 'set_total'}, @@ -1126,7 +1126,7 @@ class DialogTaxes(QuickDialog): 'heads': ['ID', 'VALOR'], } string = 'ESCOJA EL IMPUESTO' - super(DialogTaxes, self).__init__(parent, 'selection', string, data) + super(DialogTaxes, self).__init__(parent, 'selection', string, data) class DialogSource(QuickDialog): @@ -1485,7 +1485,7 @@ class DialogComboProduct(QuickDialog): self.label_qty_min = QLabel('CANT. MIN.') self.label_qty_min.setObjectName('label_qty_min') self.hbox.addWidget(self.label_qty_min) - + self.label_qty_min_req = QLabel("") self.label_qty_min_req.setObjectName('label_qty_min_req') self.hbox.addWidget(self.label_qty_min_req) @@ -1609,7 +1609,8 @@ class Help(HelpDialog): ('DOMICILIARIO', 'F12'), ('POSICION', 'Insert'), ('FACTURAR', 'End'), - ('COMENTARIO', 'Quotation Marks'), + ('COMENTARIO', 'COMILLAS DOBLE (")'), + ('AGENTE', 'PUNTO Y COMA (;)'), ) self.set_shortcuts(shortcuts) @@ -1618,7 +1619,6 @@ class Help(HelpDialog): class DialogListProduct(QuickDialog): def __init__(self, parent): self._parent = parent - vbox = QVBoxLayout() grid = QGridLayout() label_code = QLabel('CODIGO:') label_code.setObjectName('label_info_product_code') @@ -1806,7 +1806,7 @@ class DialogCollection(QuickDialog): self.input_filter.setObjectName('input_collection_filter') self.input_filter.editingFinished.connect(lambda: self.search()) self.input_filter.returnPressed.connect(lambda: self.search()) - + grid.addWidget(self.input_filter, 1, 2) label_id_number = QLabel('DOCUMENTO:') @@ -1836,8 +1836,8 @@ class DialogCollection(QuickDialog): label_payment_method.setObjectName('label_collection_payment_method') grid.addWidget(label_payment_method, 5, 1) self.combobox_payment_method = ComboBox( - parent, 'payment_method_collection', {'values': self.get_payment_methods()} - ) + parent, 'payment_method_collection', {'values': self.get_payment_methods()} + ) grid.addWidget(self.combobox_payment_method, 5, 2) label_voucher_number = QLabel('NUMERO COMPROBANTE:') @@ -1862,8 +1862,8 @@ class DialogCollection(QuickDialog): def get_payment_methods(self): domain = [ - ["sale_device", "=", self._parent.device['id']], - ["state", "=", "draft"] + ["sale_device", "=", self._parent.device['id']], + ["state", "=", "draft"] ] statements = self._parent.Statement.find(domain, fields=['rec_name', 'journal.require_voucher']) diff --git a/app/frontwindow.py b/app/frontwindow.py index 46c700e..7387cc1 100644 --- a/app/frontwindow.py +++ b/app/frontwindow.py @@ -3,10 +3,7 @@ import time from datetime import date import logging from pathlib import Path -# from PyQt5.QtWidgets import QMainWindow, QDesktopWidget, QLineEdit -# from PyQt5.QtCore import QTimer, QThread, pyqtSignal from PySide6.QtWidgets import QMainWindow, QLineEdit -from PySide6.QtCore import QTimer, QThread, Signal from PySide6.QtGui import QGuiApplication from .commons.dialogs import QuickDialog # from .commons.dblogin import safe_reconnect @@ -29,11 +26,12 @@ from .constants import DIALOG_REPLY_YES from .version import __version__ -__all__ = ['FrontWindow', 'ClearUi'] +__all__ = ['FrontWindow'] parent = Path(__file__).parent file_base_css = os.path.join(str(parent), 'css', 'base.css') _DEFAULT_TIMEOUT = 60000 # on ms (100 minutes) +logger = logging.getLogger(__name__) class FrontWindow(QMainWindow): @@ -50,7 +48,6 @@ class FrontWindow(QMainWindow): # self.conn = connection self.version = __version__ self.set_params(params) - self.logger = logging.getLogger('app_logger') """ We need get the size of screen (display) @@ -201,6 +198,14 @@ class FrontWindow(QMainWindow): self._sale_pos_restaurant = None time1 = time.time() self.Module = Model('ir.module', self.ctx, main_window=self) + module_names = [ + 'sale_pos_frontend_rest', 'sale_pos', + 'sale_pos_frontend', 'account_credit_limit'] + modules = self.Module.find([ + ('name', 'in', module_names), + ('state', '=', 'activated'), + ]) + self.modules = {m['name']: m for m in modules} print(time.time() - time1, 'final') self.Config = Model('sale.configuration', self.ctx, main_window=self) self.Sale = Model('sale.sale', self.ctx, main_window=self) @@ -228,10 +233,7 @@ class FrontWindow(QMainWindow): self.sale_automatic = True res = self.Sale.fields_get(['commission']) self._commission_activated = True if res.get('commission') else False - self._credit_limit_activated = self.Module.find([ - ('name', '=', 'account_credit_limit'), - ('state', '=', 'activated'), - ]) + self._credit_limit_activated = 'account_credit_limit' in self.modules # _product = { # 'name': 'product.product', @@ -340,20 +342,13 @@ class FrontWindow(QMainWindow): self._password_admin = self._config.get('password_admin_pos') self._password_force_assign = self._config.get('password_force_assign') if self.environment == 'restaurant': - self._sale_pos_restaurant = self.Module.find([ - ('name', '=', 'sale_pos_frontend_rest'), - ('state', '=', 'activated'), - ]) + self._sale_pos_restaurant = 'sale_pos_frontend_rest' in self.modules + print(self._sale_pos_restaurant, 'validate rest') if self._sale_pos_restaurant: self.RestTables = Model('sale.shop.table', self.ctx, main_window=self) self.Consumer = Model('party.consumer', self.ctx, main_window=self) - # TODO get product and printers - self.printers_shop, self.products_printers = None, None - try: - self.printers_shop, self.products_printers = self.Sale.get_product_printers( - self.shop['id']) - except Exception: - pass + self.printers_shop, self.products_printers = self.Sale.get_product_printers( + self.shop['id']) self._action_report_invoice, = self.ActionReport.find([ ('report_name', '=', 'account.invoice'), @@ -374,17 +369,3 @@ class FrontWindow(QMainWindow): self.Source = Model('sale.source', self.ctx, main_window=self) self.Pricelist = Model('product.price_list', self.ctx, main_window=self) return True - - -class ClearUi(QThread): - # sigActionClear = pyqtSignal() - sigActionClear = Signal() - state = None - - def __init__(self, wait_time): - QThread.__init__(self) - self.wait_time = wait_time - - def run(self): - time.sleep(self.wait_time) - self.sigActionClear.emit() diff --git a/app/main.py b/app/main.py index 8bde38b..ec19505 100644 --- a/app/main.py +++ b/app/main.py @@ -7,7 +7,7 @@ import base64 import time import traceback from decimal import Decimal -from datetime import datetime, timedelta, date +from datetime import datetime, timedelta from collections import OrderedDict from PySide6 import QtGui from PySide6.QtCore import Qt, QTimer @@ -16,7 +16,7 @@ from PySide6.QtWidgets import ( QWidget) from app.commons.image import Image from .frontwindow import FrontWindow -from .tools import get_icon, to_float, to_numeric +from .tools import get_icon, to_float, to_numeric, compare_versions from .status_bar import StatusBar from .stack_messages import StackMessages # from app.commons.action import Action @@ -31,7 +31,7 @@ from .proxy import Report from .buttonpad import ButtonsStacked, ButtonsFunction, StartButtons from .states import STATES, RE_SIGN from .commons.custom_button import CustomButton -from .threads import DoInvoice, VerifyOrderCommand +from .threads import DoInvoice from .store import StoreView from .constants import ( PATH_PRINTERS, DELTA_LOCALE, STRETCH, alignRight, alignLeft, alignCenter, @@ -76,7 +76,8 @@ class AppWindow(FrontWindow): return self.setup_sale_line() self.setup_delivery_party() - self.setup_sale_consumer() + if self.environment == 'restaurant': + self.setup_sale_consumer() self.setup_payment() # self.set_domains() print(time.time() - time1, 'set domains') @@ -106,19 +107,16 @@ class AppWindow(FrontWindow): self.reader_thread = ScaleReader() self.reader_thread.sigSetWeight.connect(self.set_weight_readed) - if self.server_printer: - self.verify_command_order_th = VerifyOrderCommand(self) - self.verify_command_order_th.sigVerifyOrderCommand.connect(self.verify_print_order_automatic) - self.verify_command_order_th.start() + if self.server_printer and self.environment == 'restaurant': + timer = QTimer() + timer.timeout.connect(self.verify_print_order_automatic) + timer.start(30000) self.do_invoice = DoInvoice(self, self.ctx) self.do_invoice.sigDoInvoice.connect(self.__do_invoice_thread) self.set_state('disabled') self.change_view_to('start_front') - # if self.cache_local: - # self.set_cache_company() - # self.set_cache_products() matching_journal = next((j for j in self._journals if j['id'] == self.default_journal['id']), None) if matching_journal: self.default_journal = matching_journal @@ -136,24 +134,45 @@ class AppWindow(FrontWindow): self.field_agent = None def verify_print_order_automatic(self): - records = self.Sale.get_orders_to_command({'shop': self.shop['id']}) - for record in records: - orders = record['orders'] - tasks = record['tasks'] - try: - result = self.receipt_order.print_orders(orders.values()) - if result: - self.Sale.mark_commanded({'sale_id': record['id'], 'lines_ids': result}) - receipt = Receipt(context={}, environment='restaurant') - receipt.print_tasks(tasks) - except Exception as e: - print(e) - traceback.print_exc() + args = {'shop': self.shop['id']} + orders = [] + tasks = [] + version = compare_versions(self.modules['sale_pos_frontend_rest']['version'], '6.0.7') + if version in ('equal', 'higher'): + print('pasa por esta new query') + if not self.tasks_station: + orders = self.SaleLine.get_data_command(args) + else: + result = self.SaleLine.get_data_command_and_task(args) + orders = result['orders'] + tasks = result['tasks'] - timer = QTimer() - timer.timeout.connect(self.verify_print_order_automatic) - timer.start(30000) - self.verify_command_order_th.exit(0) + # TODO: for remove this option + else: + records = self.Sale.get_orders_to_command(args) + for record in records: + orders += record['orders'].values() + tasks += record['tasks'].values() + print('ingresa a impresion', orders) + print('ingresa a impresion tasks', tasks) + try: + result = self.receipt_order.print_orders(orders) + if result: + self.Sale.mark_commanded({'lines_ids': result}) + except Exception: + traceback.print_exc() + + try: + receipt = Receipt(context={}, environment='restaurant') + result_print = receipt.print_tasks(tasks) + if any(result_print): + print(result_print, 'validate print') + self.SaleLine.mark_tasks_printed({'task_ids': result_print}) + except Exception: + traceback.print_exc() + # timer = QTimer() + # timer.singleShot(30000, self.verify_print_order_automatic) + # self.verify_command_order_th.exit(0) # def set_domains(self): # self.domain_search_product = [ @@ -1745,7 +1764,7 @@ class AppWindow(FrontWindow): } orders, sale_number = self.Sale.get_reversion(args) self.receipt_order.print_orders(orders.values(), reversion=True) - except Exception as e: + except Exception: print(self.print_order, 'validar variable en opcion print_order=True en config_pos.ini') logging.error('Printing order reversion fail!') @@ -1823,10 +1842,11 @@ class AppWindow(FrontWindow): if res == DIALOG_REPLY_NO: return False result = None - if not sale.get('number'): - result_set = self.Sale.set_sale_number({'sale_id': sale_id}) - self.store.set({'number': result_set}) - self.order_number.setText(result_set) + number = sale.get('number') + if not number: + number = self.Sale.set_sale_number({'sale_id': sale_id}) + self.store.set({'number': number}) + self.order_number.setText(number) if self.environment == 'restaurant': if self.print_order: result = self.print_command(sale) @@ -1842,6 +1862,7 @@ class AppWindow(FrontWindow): def get_header_sale(self, sale): order = { + 'id': self.sale_id, 'sale_number': sale['number'], 'number': sale.get('invoice_number'), 'turn': sale.get('turn'), @@ -1875,65 +1896,87 @@ class AppWindow(FrontWindow): return result def print_command(self, sale, line_reversion=None): - order = self.get_header_sale(sale) + version = compare_versions(self.modules['sale_pos_frontend_rest']['version'], '6.0.7') reversion = False if not line_reversion else True - lines = [line_reversion] if reversion else self.model_sale_lines._data orders = {} lines_ids = [] - for ln in lines: - if not reversion and ln['order_sended'] in (True, '✔'): - continue - pd_id = ln['product.']['id'] - try: - printers, cat_id = self.products_printers.get(str(pd_id)) - cat_id = str(cat_id[0]) - except Exception: - traceback.print_exc() - printers, cat_id = None, None - if printers: - for printer_id in printers: - printer = self.printers_shop.get(str(printer_id)) - if printer_id not in orders.keys(): - orders[printer_id] = { - **order, - **printer, - 'lines_ids': [] + lines = [line_reversion] if reversion else self.model_sale_lines._data + if version in ('equal', 'higher'): + order = self.get_header_sale(sale) + for ln in lines: + if not reversion and ln['order_sended'] in (True, '✔'): + continue + pd_id = ln['product.']['id'] + try: + printers, cat_id = self.products_printers.get(str(pd_id)) + cat_id = str(cat_id[0]) + except Exception: + traceback.print_exc() + printers, cat_id = None, None + if printers: + for printer_id in printers: + printer = self.printers_shop.get(str(printer_id)) + if printer_id not in orders.keys(): + orders[printer_id] = { + **order, + **printer, + 'lines_ids': [] + } + if printer.get('categories'): + orders[printer_id]['lines'] = {**printer['lines']} + orders[printer_id]['categories'] = {**printer['categories']} + else: + orders[printer_id]['lines'] = [] + value_line = { + 'name': ln['product.']['name'], + 'quantity': str(ln['quantity']), + 'sale_price_taxed': '', + 'amount_w_tax': ln['amount_w_tax'], + 'note': ln['note'] } - if printer.get('categories'): - orders[printer_id]['lines'] = {**printer['lines']} - orders[printer_id]['categories'] = {**printer['categories']} + if isinstance(orders[printer_id]['lines'], list): + orders[printer_id]['lines'].append(value_line) + orders[printer_id]['lines_ids'].append(ln['id']) else: - orders[printer_id]['lines'] = [] - value_line = { - 'name': ln['product.']['name'], - 'quantity': str(ln['quantity']), - 'sale_price_taxed': '', - 'amount_w_tax': ln['amount_w_tax'], - 'note': ln['note'] - } - if isinstance(orders[printer_id]['lines'], list): - orders[printer_id]['lines'].append(value_line) - orders[printer_id]['lines_ids'].append(ln['id']) - else: - try: - key_id = orders[printer_id]['categories'][cat_id] - except Exception: - if 'others' not in orders[printer_id]['lines'].keys(): - orders[printer_id]['lines']['others'] = {'name': 'OTROS', 'lines':[]} - key_id = 'others' - try: - orders[printer_id]['lines'][key_id]['lines'].append(value_line) - orders[printer_id]['lines_ids'].append(ln['id']) - except Exception: - orders[printer_id]['lines'][key_id]['lines'] = [value_line] - orders[printer_id]['lines_ids'].append(ln['id']) + try: + key_id = orders[printer_id]['categories'][cat_id] + except Exception: + if 'others' not in orders[printer_id]['lines'].keys(): + orders[printer_id]['lines']['others'] = {'name': 'OTROS', 'lines': []} + key_id = 'others' + try: + orders[printer_id]['lines'][key_id]['lines'].append(value_line) + orders[printer_id]['lines_ids'].append(ln['id']) + except Exception: + orders[printer_id]['lines'][key_id]['lines'] = [value_line] + orders[printer_id]['lines_ids'].append(ln['id']) + else: + lines_ids.append(ln['id']) + else: + # for remove this code + if reversion: + args = {'sale_id': self.sale_id, 'sale_line_id': line_reversion['id']} + orders, sale_number = self.Sale.get_reversion(args) else: - lines_ids.append(ln['id']) + args = {'sale_id': self.sale_id} + orders, sale_number = self.Sale.get_order2print(args) if self.environment == 'restaurant' and self.tasks_station: - data_station = self.Sale.method_instance('get_data_for_stations', self.sale_id) - receipt = Receipt(context={}, environment='restaurant') - receipt.print_tasks(data_station) + if version in ('equal', 'higher'): + args = { + 'shop': self.shop['id'], + 'sale_id': self.sale_id + } + tasks = self.SaleLine.get_data_tasks(args) + receipt = Receipt(context={}, environment='restaurant') + result_print = receipt.print_tasks(tasks) + if any(result_print): + self.SaleLine.mark_tasks_printed(result_print) + else: + data_station = self.Sale.method_instance('get_data_for_stations', self.sale_id) + receipt = Receipt(context={}, environment='restaurant') + receipt.print_tasks(data_station.values()) + result = self.receipt_order.print_orders(orders.values(), reversion) lines_sended = result + lines_ids if not reversion and lines_sended: @@ -1960,11 +2003,12 @@ class AppWindow(FrontWindow): if self._ask_new_sale(): self.create_new_sale() - def numpad_price_clicked(self): - code = self.label_input.text() - product = self._search_product(code) - if not product: - return + # for remove + # def numpad_price_clicked(self): + # code = self.label_input.text() + # product = self._search_product(code) + # if not product: + # return def _ask_new_sale(self): dialog = self.dialog('new_sale', response=True) @@ -2235,7 +2279,7 @@ class AppWindow(FrontWindow): if sale.get('payments'): for payment in sale['payments']: # FIXME - #self.table_payment_lines.record_add(payment) + # self.table_payment_lines.record_add(payment) pass self.party_id = sale['party.']['id'] @@ -2431,7 +2475,7 @@ class AppWindow(FrontWindow): qty_text = self.dialog_combo_product.label_qty_add.text() try: qty = int(qty_text) + 1 - except: + except Exception: qty = 1 self.dialog_combo_product.label_qty_add.setText(str(qty)) self.on_selected_item(record, list_price) @@ -2557,7 +2601,7 @@ class AppWindow(FrontWindow): ctx = self.stock_context if not self.stock_context: - ctx = {'price_list': self.shop['price_list.']['id']} + ctx = {'price_list': self.shop['price_list.']['id']} else: ctx['price_list'] = self.shop['price_list.']['id'] fields = self.dialog_search_products.fields_names @@ -2795,14 +2839,14 @@ class AppWindow(FrontWindow): ('barcode', '=', code), ('code', '=', code) ]) + # 'image', 'image_icon', 'write_date' fields remove from domain products = self.Product.find( domain, fields=[ 'name', 'code', 'categories', 'description', - 'id', 'image', 'image_icon', 'list_price', - 'quantity', 'rec_name', 'template', + 'id', 'list_price', 'quantity', 'rec_name', 'template', 'extra_tax', 'template.sale_price_w_tax', - 'template.default_uom', 'write_date']) + 'template.default_uom']) if not products or len(products) > 1: self.message_bar.set('product_not_found') @@ -2856,6 +2900,7 @@ class AppWindow(FrontWindow): product_id = record['id'] if record else None if not product_id and code: # REMOVE ME THIS OPTION IS FOR BARCODE + # product = self._search_product(code) product = self._search_product(code) if product: product_id = product['id'] @@ -3282,7 +3327,8 @@ class AppWindow(FrontWindow): if note: self.SaleLine.write([removed_item['id']], {'note': note}) prd_code = removed_item['product.']['code'] - if prd_code and self._config['tip_product.']['code'] == prd_code: + tip_product = self._config.get('tip_product.') + if prd_code and tip_product and tip_product['code'] == prd_code: self.Sale.write([self.sale_id], {'tip': None}) self.SaleLine.delete([removed_item['id']]) self.set_amounts() diff --git a/app/models.py b/app/models.py index 862505c..76203d9 100644 --- a/app/models.py +++ b/app/models.py @@ -388,7 +388,6 @@ MODELS_RETAIL = { 'new_sale_automatic', 'show_product_image', 'delivery_product.code', 'encoded_sale_price', 'delivery_product.list_price', 'delivery_product.name', 'allow_discount_handle', - 'no_remove_commanded', 'cache_products_local', 'show_party_categories', 'print_lines_product', 'uvt_pos' ] diff --git a/app/reporting.py b/app/reporting.py index 4e8cbc9..f5dbb20 100755 --- a/app/reporting.py +++ b/app/reporting.py @@ -8,7 +8,6 @@ from datetime import datetime from decimal import Decimal import subprocess import time - from .printing.protocols import FileSSH try: @@ -77,7 +76,6 @@ class Receipt(object): __name__ = 'frontend_pos.ticket' def __init__(self, context={}, row_characters=None, logo=None, environment='retail'): - self.logger = logging.getLogger('reporting') self._company = context.get('company') self._sale_device = context.get('sale_device') self._shop = context.get('shop') @@ -217,18 +215,16 @@ class Receipt(object): except Exception: host, port = self._device, None if port: - self._printer = printer.Network(host, port=int(port), timeout=15) + self._printer = printer.Network(host, port=int(port), timeout=5) else: - self._printer = printer.Network(host, timeout=15) + self._printer = printer.Network(host, timeout=5) if not self._printer: msg = "Warning: Can not found Printer!" - self.logger.info("Warning: Can not found Printer!") + logging.info("Warning: Can not found Printer!") return msg - self.logger.info("Info: Printer is OK!") - except Exception as e: - traceback.print_exc() - self.logger.info( - "Warning: Printer error or device not found!", str(e)) + except Exception: + logging.exception( + "Warning: Printer error or device not found!") def print_sale(self, sale, type_doc=None, open_box=False): try: @@ -236,33 +232,6 @@ class Receipt(object): msg = self.set_printer() if msg: return {"error": msg} - # if self._interface == 'usb': - # if OS_NAME == 'posix': - # self._printer = printer.File( - # self._device, profile=self._profile) - # elif OS_NAME == 'nt': - # self._printer = printer.Win32Raw(self._device) - # self._printer.open() - # elif self._interface == 'network': - # try: - # host, port = self._device.split(":") - # except: - # host, port = self._device, None - # if port: - # self._printer = printer.Network(host, port=int(port), timeout=15) - # else: - # self._printer = printer.Network(host, timeout=15) - # elif self._interface == 'ssh': - # self._printer = FileSSH(*self._device.split('@')) - # self._printer.open() - # elif self._interface == 'cups': - # self.conn = cups.Connection() - # self._file = open(TEMP_INVOICE_FILE, 'w') - # self._printer = CupsPrinter(self._file, self._row_characters) - # if not self._printer: - # self.logger.info("Warning: Can not found Printer!") - # return - # self.logger.info("Info: Printer is OK!") try: if type_doc in ('invoice', 'quotation') or self._environment == 'retail': self._print_sale(sale, type_doc, open_box) @@ -271,9 +240,8 @@ class Receipt(object): except Exception: pass self._printer.close() - except Exception as e: - print(str(e)) - self.logger.info("Warning: Printer error or device not found!") + except Exception: + logging.exception("Warning: Printer error or device not found!") def _print_sale(self, sale, type_doc=None, open_box=False): short = sale['short_invoice'] @@ -432,7 +400,7 @@ class Receipt(object): self._printer.set(align='center') self._printer.image(self._img_logo, center=True) self.print_enter() - except: + except Exception: pass def print_qrcode(self, qrcode): @@ -440,11 +408,15 @@ class Receipt(object): self.print_enter() def print_tasks(self, data): - for value in data.values(): + tasks_printed = [] + for value in data: try: self._printer = None self.config_printer(value['printer']) self.set_printer() + if not self._printer: + logging.error('impresora no disponible error impresion tarea %s', str(value['printer'])) + continue title = value['sale'] + ' - ' + value['work_station'] self._printer.set(custom_size=True, width=2, height=2, align='center') @@ -453,17 +425,18 @@ class Receipt(object): height=2, align='left') self._printer.ln(2) for ln in value['lines']: - line_ = str(int(ln['qty'])) + ' ' + ln['name'] + line_ = str(int(ln['quantity'])) + ' ' + ln['name'] self._printer.textln(line_) if ln.get('note'): self._printer.textln('NOTA:' + ln.get('note')) self._printer.ln(2) + tasks_printed.append(ln['task']) self._printer.cut() self._printer.close() - except Exception as e: - print(e) - traceback.print_exc() + except Exception: + logging.exception('error tarea') time.sleep(1) + return tasks_printed def print_header(self, short=False): if not short: @@ -508,9 +481,9 @@ class Receipt(object): def print_split(self, left, right): len_left = self._row_characters - len(right) - 1 left = left[:len_left] - if type(left) == bytes: + if isinstance(left, bytes): left = left.decode("utf-8") - if type(right) == bytes: + if isinstance(right, bytes): right = right.decode("utf-8") left += (len_left - len(left) + 1) * ' ' self._printer.text(left) @@ -534,11 +507,11 @@ class Receipt(object): if self._show_discount and discount and Decimal(discount) > 0: amount_w_tax = Decimal(line['amount_w_tax']) discount = Decimal(discount) - initial = 'DCTO - ' + str(round(discount*100, 0)) + '%' + initial = 'DCTO - ' + str(round(discount * 100, 0)) + '%' if discount == 1: line_total = 0 else: - line_total = amount_w_tax/(1-discount) + line_total = amount_w_tax / (1 - discount) discount = '-' + money(line_total - amount_w_tax) line_total = money(line_total) @@ -547,7 +520,7 @@ class Receipt(object): length_name = self._row_characters - 11 first_line = code + ' ' + line['name'][:length_name] - if type(first_line) == bytes: + if isinstance(first_line, bytes): first_line = first_line.decode('utf-8') self._printer.text(first_line + '\n') @@ -866,38 +839,40 @@ class Receipt(object): if not hasattr(self, '_printer') or not self._printer and self._environment != 'restaurant': self.set_printer() if not self._printer: - self.logger.info( + logging.info( "Warning: Interface not found for printer!") # res.append(None) return False - self.logger.info("Info: Printer is OK!") + logging.info("Info: Printer is OK!") try: - self._print_order(order, reversion) + res = self._print_order(order, reversion) # if True: - res.extend(order['lines_ids']) - except Exception as e: - print(e) - traceback.print_exc() + if res: + res.extend(res) + elif order.get('lines_ids') and True: + res.extend(order['lines_ids']) + except Exception: + logging.exception('error de impresora') self._printer.close() time.sleep(1) - except Exception as e: - print(e) - traceback.print_exc() - self.logger.info("Warning: Can not found Printer!") + except Exception: + logging.exception('Can not found Printer!') return res def _print_order(self, order, reversion): + lines_printed = [] for copie in range(self.order_copies): - self.print_body_order(order, reversion) + lines_printed = self.print_body_order(order, reversion) self._print_info_consumer(order) self._printer.cut() - return True + return lines_printed def print_body_order(self, order, reversion): # Exists 2 types of order: # command => For restaurants kitchens # dispatch => For external dispatch + lines_printed = [] self._printer.set(font=_FONT_B) self._printer.set(align='center') turn = order.get('turn') @@ -994,21 +969,25 @@ class Receipt(object): def print_lines_order(lines, group=False): for line in lines: - if self.order_kind == 'command': - self._printer.set(custom_size=True, width=1, height=2) - qty = ' ' + str(int(Decimal(line['quantity']))) - name = line['name'] - if group: - name = ' ' + name - self.print_col(qty, self.order_col_1) - self.print_col(name, col_width_name) - if line['note']: - self.print_enter() - for msg_note in line['note'].split('\n'): - self._printer.text(f' NOTA -> {msg_note}') + try: + if self.order_kind == 'command': + self._printer.set(custom_size=True, width=1, height=2) + qty = ' ' + str(int(Decimal(line['quantity']))) + name = line['name'] + if group: + name = ' ' + name + self.print_col(qty, self.order_col_1) + self.print_col(name, col_width_name) + if line['note']: self.print_enter() + for msg_note in line['note'].split('\n'): + self._printer.text(f' NOTA -> {msg_note}') + self.print_enter() + if line.get('id'): + lines_printed.append(line['id']) + except Exception: + traceback.print_exc() self.print_enter() - print('este es el camino de la comanda') self.print_enter() if isinstance(order['lines'], list): print_lines_order(order['lines']) @@ -1031,6 +1010,7 @@ class Receipt(object): self._printer.text(str(order['comment'])) self.print_enter() self._printer.ln(2) + return lines_printed # if self._environment != 'retail': # self._printer.set(custom_size=True, width=2, height=2, align='center') # title = f'+ + + {_kind} + + +' diff --git a/app/tools.py b/app/tools.py index 395d02f..0fc5a41 100644 --- a/app/tools.py +++ b/app/tools.py @@ -27,3 +27,17 @@ def get_screen(): width = screen.width() height = screen.height() return width, height + +def compare_versions(version_validate, version_required): + v1_parts = version_validate.split('.') + v2_parts = version_required.split('.') + + for i in range(max(len(v1_parts), len(v2_parts))): + v1_num = int(v1_parts[i]) if i < len(v1_parts) else 0 + v2_num = int(v2_parts[i]) if i < len(v2_parts) else 0 + + if v1_num < v2_num: + return "lower" + elif v1_num > v2_num: + return "higher" + return 'equal' diff --git a/app/version.py b/app/version.py index eab5bfc..52a42bb 100644 --- a/app/version.py +++ b/app/version.py @@ -1 +1 @@ -__version__ = "6.0.24" +__version__ = "6.0.25" diff --git a/logger_config.py b/logger_config.py new file mode 100644 index 0000000..c31d4e8 --- /dev/null +++ b/logger_config.py @@ -0,0 +1,20 @@ +import os +import logging + + +log_file_path = os.path.dirname(os.path.abspath(__file__)) + '/presik_pos.log' +log_formater = logging.Formatter( + '%(asctime)s - %(levelname)s - %(funcName)s - %(name)s - %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', style="%") + + +handlerConsole = logging.StreamHandler() +handlerConsole.setFormatter(log_formater) + +handlerFile = logging.FileHandler(log_file_path, mode='a', encoding='utf-8') +handlerFile.setFormatter(log_formater) + +logger = logging.getLogger() +logger.setLevel(logging.DEBUG) +logger.addHandler(handlerConsole) +logger.addHandler(handlerFile)