configure dialogs for fast init pos

This commit is contained in:
Wilson Gomez 2023-01-02 14:06:27 -05:00
parent d01a27e103
commit f792521158
21 changed files with 516 additions and 562 deletions

13
INSTALL
View File

@ -6,8 +6,7 @@ Prerequisites Client
* Python 3.7 or later (http://www.python.org/)
* python-setuptools
* python3-pyqt5
* python3-pyqt5.qtsvg
* python3-PySide6
* python3-dateutil
* python-pip
* libusb-1.0-0
@ -21,16 +20,12 @@ Prerequisites Client
pip3 install pillow
pip3 install qrcode
pip3 install paramiko
pip3 install pycups
pip3 install requests
pip3 install simplejson
pip3 install orjson
pip3 install escpos
pip3 install packaging
pip3 install PySide6>=6.4.1
For Windows add:
pip install pywin32
pip install PyQt5==5.12.3
pip install win32printing
Prerequisites Server Modules

View File

@ -33,17 +33,10 @@ Los siguientes paquetes se deben instalar usando PIP
pip3 install pillow
pip3 install qrcode
pip3 install paramiko
pip3 install pycups
pip3 install requests
pip3 install simplejson
pip3 install orjson
pip3 install escpos
pip3 install packaging
Para Windows agregar:
pip install pywin32
pip install PyQt5==5.12.3
pip install win32printing
pip3 install PySide6>=6.4.1
Tener en cuenta que algunos paquetes se deben instalar con pip para python3.

0
__init__.py Normal file
View File

View File

@ -1 +0,0 @@

View File

@ -7,6 +7,7 @@ import logging
from collections import OrderedDict
from pathlib import Path
from PySide6.QtWidgets import (QMainWindow, QDialog)
from PySide6.QtCore import Qt
# from PyQt5.QtWidgets import (QDialogButtonBox, QPushButton,
# QLineEdit, QHBoxLayout, QFrame, QLabel,
# QVBoxLayout, QStyle,)
@ -64,6 +65,14 @@ class Login(QDialog):
styles.append(infile.read())
self.setStyleSheet(''.join(styles))
def keyPressEvent(self, event):
print(event, 'this is event')
if event.key() == Qt.Key_Escape:
self.reject()
elif event.key() == Qt.Key_Enter:
self.accept()
event.accept()
# def init_UI(self):
# hbox_logo = QHBoxLayout()
# label_logo = QLabel()
@ -144,21 +153,11 @@ class Login(QDialog):
self.error_msg.hide()
def run(self, profile=None):
self.api_url = self.params['api_url']
# self.api_url = self.params['api_url']
if self.params['database']:
self.ui.field_database.setText(self.params['database'])
if self.params['user']:
self.ui.field_user.setText(self.params['user'])
# if self.params['server']:
# self.ui.field_host.setText(self.params['server'])
# if self.mode_conn == 'offline':
# self.api_url = self.params['api_url_offline']
# if self.params['database_offline']:
# self.field_database.setText(self.params['database_offline'])
# if self.params['user']:
# self.field_user.setText(self.params['user'])
# if self.params['server']:
# self.field_host.setText(self.params['server_offline'])
def accept(self):
self.validate_access()
@ -188,9 +187,8 @@ class Login(QDialog):
password = self.ui.field_password.text()
server = self.params.get('server')
database = self.ui.field_database.text()
self.connection = xconnection(self.params['mode'],
user, password, server, self.params['port'],
database, self.params['protocol']
self.connection = xconnection(
self.params['mode'], user, password, server, database
)
if not self.connection:
self.ui.field_password.setText('')
@ -206,67 +204,46 @@ class Login(QDialog):
self.ui.label_error.show()
def xconnection(mode, user, password, host, port, database, protocol):
def xconnection(mode, user, password, host, database):
# Get user_id and session
try:
url = '%s://%s:%s@%s:%s/%s/' % (
mode, user, password, host, port, database)
print(url, 'url....')
try:
if not common.test_server_version(host, int(port)):
print(u'Incompatible version of the server')
return
except:
pass
if protocol == 'json':
conn = connection.set_jsonrpc(url[:-1])
elif protocol == 'local':
conn = connection.set_trytond(
database=database,
user=user,
)
elif protocol == 'xml':
conn = connection.set_xmlrpc(url)
else:
print("Protocol error...!")
return None
return conn
mode, user, password, host, 8000, database)
return connection.set_xmlrpc(url)
except:
print('LOG: Data connection invalid!')
return None
def safe_reconnect(main):
field_password = QLineEdit()
field_password.setEchoMode(QLineEdit.Password)
field_password.cursorPosition()
field_password.cursor()
dialog_password = QuickDialog(main, 'question',
info=main.tr('Enter your password:'),
widgets=[field_password],
buttons=['ok'],
response=True
)
field_password.setFocus()
# def safe_reconnect(main):
# field_password = QLineEdit()
# field_password.setEchoMode(QLineEdit.Password)
# field_password.cursorPosition()
# field_password.cursor()
# dialog_password = QuickDialog(main, 'question',
# info=main.tr('Enter your password:'),
# widgets=[field_password],
# buttons=['ok'],
# response=True
# )
# field_password.setFocus()
password = field_password.text()
if not password or password == '':
safe_reconnect(main)
# password = field_password.text()
# if not password or password == '':
# safe_reconnect(main)
main.conn = xconnection(
main.user,
str(password),
main.server,
main.port,
main.database,
main.protocol,
)
# main.conn = xconnection(
# main.user,
# str(password),
# main.server,
# main.port,
# main.database,
# main.protocol,
# )
if main.conn:
field_password.setText('')
dialog_password.hide()
main.global_timer = 0
else:
safe_reconnect(main)
# if main.conn:
# field_password.setText('')
# dialog_password.hide()
# main.global_timer = 0
# else:
# safe_reconnect(main)

View File

@ -7,6 +7,7 @@ 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
@ -221,18 +222,23 @@ class QuickDialog(QDialog):
def set_simple_model(self):
self.data_model = QStandardItemModel(0, len(self.data['heads']), self)
_horizontal = Qt.Horizontal
for i, h in enumerate(self.data['heads'], 0):
self.data_model.setHeaderData(i, _horizontal, h)
# _horizontal = Qt.Horizontal
# print('simple model')
map(self.data_model.setHeaderData, enumerate(self.data['heads'], 0))
# for i, h in enumerate(self.data['heads'], 0):
# self.data_model.setHeaderData(i, _horizontal, h)
def _insert_items(self, model, values):
ItemIsEnabled, ItemIsSelectable = Qt.ItemIsEnabled, Qt.ItemIsSelectable
insertRow = self.data_model.insertRow
for value in values:
row = []
row_append = row.append
for v in value:
itemx = QStandardItem(v)
itemx.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
row.append(itemx)
self.data_model.insertRow(0, row)
itemx.setFlags(ItemIsEnabled | ItemIsSelectable)
row_append(itemx)
insertRow(0, row)
self.data_model.sort(0, Qt.AscendingOrder)
@Slot(QModelIndex)
@ -293,7 +299,7 @@ class SearchDialog(QDialog):
self.completer.activated.connect(on_activated)
def set_model(self):
headers_name = [h[1] for h in self.headers]
headers_name = (h[1] for h in self.headers)
self.model = get_simple_model(self.parent, self.values, headers_name)
self.completer.setModel(self.model)

View File

@ -368,12 +368,12 @@ class ComboBox(QComboBox):
self.setFrame(True)
self.setObjectName('field_' + key)
self.setFocusPolicy(Qt.StrongFocus)
values = []
if data.get('values'):
values = data.get('values')
heads = []
if data.get('heads'):
heads = data.get('heads')
# values = []
# if data.get('values'):
values = data.get('values', [])
# heads = []
# if data.get('heads', []):
heads = data.get('heads', [])
selection_model = get_simple_model(obj, values, heads)
self.setModel(selection_model)
self.setModelColumn(1)
@ -459,38 +459,65 @@ class GridForm(QGridLayout):
if col == 0:
align = 'left'
TYPES_ = {
'selection': ComboBox,
'checkbox': CheckBox,
'money': FieldMoney,
'text': TextField,
'text_area': TextAreaField,
'date': FieldDate,
'editable': FieldInput,
}
setted_focus = False
addWidget = self.addWidget
for key, value in values.items():
type_ = value.get('type')
expand = 0
self.store[key] = None
if value.get('editable'):
_field = FieldInput(obj, key, value, form=self)
elif value.get('type') == 'selection':
_field = ComboBox(obj, key, value, form=self)
elif value.get('type') == 'checkbox':
_field = CheckBox(obj, key, value, form=self)
expand = 1
elif value.get('type') == 'money':
_field = FieldMoney(obj, key, value, form=self)
elif value.get('type') == 'text':
_field = TextField(obj, key, value, form=self)
setted_focus = True
expand = 1
align = 'left'
elif value.get('type') == 'text_area':
_field = TextAreaField(obj, key, value, form=self)
# setted_focus = True
expand = 1
align = 'left'
elif value.get('type') == 'date':
_field = FieldDate(obj, key, value, form=self)
else:
_field = Field(obj, key, value, self)
try:
Field_ = TYPES_[type_]
_field = Field_(obj, key, value, form=self)
if type_ in ('checkbox', 'text', 'text_area'):
expand = 1
if type_ == 'text':
align = 'left'
except:
_field = Field(obj, key, value, form=self)
if value.get('password') is True:
_field.setEchoMode(QLineEdit.Password)
if value.get('placeholder'):
_field.setPlaceholderText(value['name'])
# if value.get('editable'):
# _field = FieldInput(obj, key, value, form=self)
# elif type_ == 'selection':
# _field = ComboBox(obj, key, value, form=self)
# elif type_ == 'checkbox':
# _field = CheckBox(obj, key, value, form=self)
# expand = 1
# elif type_ == 'money':
# _field = FieldMoney(obj, key, value, form=self)
# elif type_ == 'text':
# _field = TextField(obj, key, value, form=self)
# setted_focus = True
# expand = 1
# align = 'left'
# elif type_ == 'text_area':
# _field = TextAreaField(obj, key, value, form=self)
# # setted_focus = True
# expand = 1
# align = 'left'
# elif type_ == 'date':
# _field = FieldDate(obj, key, value, form=self)
# else:
# _field = Field(obj, key, value, self)
# if value.get('password') is True:
# _field.setEchoMode(QLineEdit.Password)
# if value.get('placeholder'):
# _field.setPlaceholderText(value['name'])
if not setted_focus:
self.focus_widget = _field
setted_focus = True
@ -506,15 +533,15 @@ class GridForm(QGridLayout):
continue
if not expand:
if not value.get('placeholder'):
self.addWidget(_label, row, column1)
addWidget(_label, row, column1)
if col == 0:
row = row + 1
self.addWidget(_field, row, column1)
addWidget(_field, row, column1)
else:
self.addWidget(_field, row, column2)
addWidget(_field, row, column2)
else:
self.addWidget(_label, row, column1, row, column2)
self.addWidget(_field, row + 1, column1, row + 1, column2)
addWidget(_label, row, column1, row, column2)
addWidget(_field, row + 1, column1, row + 1, column2)
if value.get('translate') is True:
_field.translate = True

View File

@ -14,6 +14,7 @@ from PySide6.QtWidgets import (
)
from .custom_button import CustomButton
from ..tools import get_icon
pkg_dir = str(Path(os.path.dirname(__file__)).parents[0])
file_back_icon = os.path.join(pkg_dir, 'share', 'back.svg')
@ -29,7 +30,7 @@ def money(v):
class MenuDash(QWidget):
def __init__(self, parent, values, selected_method=None, title=None):
def __init__(self, parent, values=[], selected_method=None, title=None):
"""
parent: parent window
values: is to list of list/tuples values for data model
@ -110,14 +111,14 @@ class MenuDash(QWidget):
view_id = str(view_id)
view = self.ctx_widgets[self.current_view]['items']
view.hide()
if not view_id:
view_id = '0'
new_view = self.ctx_widgets[view_id]['items']
if not new_view:
# if not view_id:
# view_id = '0'
try:
new_view = self.ctx_widgets[view_id]['items']
new_view.show()
except:
return
new_view.show()
self.main.addWidget(new_view)
self.current_view = view_id
self.setGeometry(self.rect_expanded)
@ -135,10 +136,7 @@ class MenuDash(QWidget):
self.main_categories.setSpacing(4)
self.menu.setLayout(self.main_categories)
num_cat_cols = 3
row_cat = 0
col_cat = 0
parent_id = '0'
num_cat_cols, row_cat, col_cat, parent_id = 3, 0, 0, '0'
self.ctx_widgets = {
'0': {
'items': self.menu_area,
@ -147,9 +145,10 @@ class MenuDash(QWidget):
}
main_cat_addWidget = self.main_categories.addWidget
for value in self.values:
# print(value, type(value['id']))
cat_id = str(value['id'])
if not value:
continue
# if not value:
# continue
if col_cat > num_cat_cols - 1:
col_cat = 0
row_cat += 1
@ -157,7 +156,7 @@ class MenuDash(QWidget):
button = CustomButton(
parent=self,
id=value['id'],
icon=value['icon'],
icon=get_icon(value['name_icon']),
method='selected_method',
desc_extractor='name',
record=value,
@ -167,8 +166,8 @@ class MenuDash(QWidget):
main_cat_addWidget(button, row_cat, col_cat)
col_cat += 1
items = value.get('items')
childs = value.get('childs', [])
items = value.get('products.')
childs = value.get('childs.', [])
if items:
products = self.get_products(items)
self.ctx_widgets[cat_id] = {
@ -176,8 +175,7 @@ class MenuDash(QWidget):
'parent': parent_id,
}
if childs:
subrow = 0
subcol = 0
subrow, subcol = 0, 0
sub_categories = QGridLayout()
sub_categories.setSpacing(4)
scroll_subarea = QScrollArea()
@ -196,7 +194,7 @@ class MenuDash(QWidget):
button = CustomButton(
parent=self,
id=sub_id,
icon=value['icon'],
icon=get_icon(value['name_icon']),
method='selected_method',
desc_extractor='name',
record=subcat,
@ -205,7 +203,7 @@ class MenuDash(QWidget):
)
sub_cat_addWidget(button, subrow, subcol)
subcol += 1
products_list = subcat.get('items')
products_list = subcat.get('products.')
products_items = None
if products_list:
products_items = self.get_products(products_list)
@ -215,6 +213,7 @@ class MenuDash(QWidget):
'parent': cat_id,
}
sub_categories.setRowStretch(subrow + 1, 1)
print('..... final')
self.main_categories.setRowStretch(row_cat + 1, 1)
def action_back(self):
@ -264,7 +263,7 @@ class GridButtons(QWidget):
self.set_items()
def create_list_items(self):
self.list_items = []
self.list_items, button_size, style = [], self.button_size, self.style
list_items_append = self.list_items.append
for value in self.values:
_button = CustomButton(
@ -273,8 +272,8 @@ class GridButtons(QWidget):
desc_extractor='name',
method='action_selected',
record=value,
size=self.button_size,
name_style=self.style,
size=button_size,
name_style=style,
)
list_items_append(_button)
@ -282,11 +281,10 @@ class GridButtons(QWidget):
self.action(idx)
def set_items(self):
colx = 0
rowy = 0
colx, rowy, num_cols = 0, 0, self.num_cols
layout_addWidget = self.layout.addWidget
for item_button in self.list_items:
if colx >= self.num_cols:
if colx >= num_cols:
colx = 0
rowy += 1
layout_addWidget(item_button, rowy, colx)

View File

@ -39,7 +39,7 @@ class TLabel(QLabel):
class RLabel(QLabel):
#Item Label
# Item Label
def __init__(self, name, idx):
super(RLabel, self).__init__(name)
@ -71,16 +71,17 @@ class List(QWidget):
self.set_items(rows)
def action_selected(self, idx):
self.action(idx) #.selected_method(idx)
self.action(idx) # selected_method(idx)
def set_items(self, rows):
self.rows = rows
idx = 0
self.layout_list.addWidget(Separator(), 0, 0, 1, self.num_cols)
addWidget = self.layout_list.addWidget
separator = Separator()
addWidget(separator, 0, 0, 1, self.num_cols)
for row in rows:
idx += 1
separator = Separator()
for col in range(self.num_cols):
val = row[col]
if isinstance(val, Decimal):
@ -89,9 +90,9 @@ class List(QWidget):
if col == 0:
val = ''
item = RLabel(val, idx=row[0])
self.layout_list.addWidget(item, idx, col)
addWidget(item, idx, col)
idx += 1
self.layout_list.addWidget(separator, idx, 0, 1, self.num_cols)
addWidget(separator, idx, 0, 1, self.num_cols)
self.layout_list.setRowStretch(idx + 1, 1)
@ -154,12 +155,13 @@ class MenuWindow(QDialog):
self.layout_category = QVBoxLayout()
self.category.setLayout(self.layout_category)
id_ = 1
self.layout_category.addWidget(Separator())
addWidget = self.layout_category.addWidget
addWidget(Separator())
separator = Separator()
for k, values in self.values.items():
separator = Separator()
label = TLabel(k, id_, self)
self.layout_category.addWidget(label)
self.layout_category.addWidget(separator)
addWidget(label)
addWidget(separator)
list_item = List(values, 3, self.show_code, self.selected_method)
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)

View File

@ -1,6 +1,9 @@
# from PyQt5.QtCore import Qt, QAbstractTableModel, QModelIndex
from PySide6.QtCore import Qt, QAbstractTableModel, QModelIndex
import math
from itertools import islice
_horizontal = Qt.Horizontal
__all__ = ['TableModel', 'TableEdit']
@ -63,11 +66,12 @@ class TableEdit(QAbstractTableModel):
""" Set the headers to be displayed. """
if role != Qt.DisplayRole:
return None
if orientation == Qt.Horizontal:
for i in range(len(self._fields)):
if section == i:
return self._fields[i]['label']
return None
try:
return next(islice(self._fields, section, None))['label']
except:
return None
# if orientation == Qt.Horizontal:
# return None
def add_record(self, rec):
length = len(self._data)
@ -77,7 +81,7 @@ class TableEdit(QAbstractTableModel):
return rec
def get_sum(self, col):
return sum([int(d[col]) for d in self._data])
return sum(int(d[col]) for d in self._data)
class TableModel(QAbstractTableModel):
@ -126,11 +130,11 @@ class TableModel(QAbstractTableModel):
def get_value(self, data, field):
value = ''
list_ = field.split('.')
for l in list_:
if not data.get(l):
return None
value = data[l]
data = data[l]
if len(list_) > 1:
for l in list_[:-1]:
l = l + '.'
data = data[l]
value = data[list_[-1]]
return value
def data(self, index, role, field_name='name'):
@ -188,7 +192,7 @@ class TableModel(QAbstractTableModel):
return None
def get_sum(self, field_target):
res = sum([d[field_target] for d in self._data])
res = sum(d[field_target] for d in self._data)
return res
def update_record(self, rec, pos=None):
@ -205,13 +209,11 @@ class TableModel(QAbstractTableModel):
self.dataChanged.emit(start_pos, end_pos)
return rec
def headerData(self, section, orientation, role):
def headerData(self, section, orientation=_horizontal, role=None):
""" Set the headers to be displayed. """
if role != Qt.DisplayRole:
return None
elements = [f['description'] for f in self._fields]
if orientation == Qt.Horizontal:
for i in range(len(elements)):
if section == i:
return elements[i]
return None
elements = (f['description'] for f in self._fields)
return next(islice(elements, section, None))
# if orientation == Qt.Horizontal:
# return None

View File

@ -9,21 +9,24 @@ def get_simple_model(obj, data, header=[]):
model = QStandardItemModel(0, len(header), obj)
if header:
i = 0
setHeaderData = model.setHeaderData
for head_name in header:
model.setHeaderData(i, Qt.Horizontal, head_name)
setHeaderData(i, Qt.Horizontal, head_name)
i += 1
_insert_items(model, data)
return model
def _insert_items(model, data):
appendRow = model.appendRow
for d in data:
row = []
row_append = row.append
for val in d:
itemx = QStandardItem(str(val))
itemx.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
row.append(itemx)
model.appendRow(row)
row_append(itemx)
appendRow(row)
model.sort(0, Qt.AscendingOrder)

View File

@ -10,8 +10,6 @@ from datetime import timedelta, datetime
# QHBoxLayout, QItemDelegate, QMenu, QAction)
# from PyQt5.QtGui import QPixmap, QIcon, QCursor
from PySide6.QtWidgets import QApplication
# from PySide6.Qt import QApplication, QClipboard
from PyQt5.QtCore import (QVariant)
from PySide6.QtCore import (
Qt, QAbstractTableModel, Signal, QModelIndex
)
@ -20,9 +18,9 @@ from PySide6.QtWidgets import (
QHBoxLayout, QItemDelegate, QMenu
)
from PySide6.QtGui import QPixmap, QIcon, QCursor, QAction
from .buttons import ActionButton
from ..tools import get_screen
_horizontal = Qt.Horizontal
__all__ = ['Item', 'SearchWindow', 'TableModel']
@ -138,8 +136,10 @@ class SearchWindow(QDialog):
def set_from_objects(self, objects):
self.rows = []
rows_append = self.rows.append
for object_ in objects:
row = []
row_append = row.append
for field, data in self.headers.items():
val = getattr(object_, field)
if hasattr(val, 'name'):
@ -150,8 +150,8 @@ class SearchWindow(QDialog):
val = str(val)
elif data['type'] == 'date':
val = val.strftime('%d/%m/%Y')
row.append(val)
self.rows.append(row)
row_append(val)
rows_append(row)
self.table_model.set_rows(self.rows)
def create_table(self):
@ -449,24 +449,29 @@ class TableModel(QAbstractTableModel):
return item
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return QVariant(self.header_name[col])
return QVariant()
if role != Qt.DisplayRole:
return None
try:
return self.header_name[col]
except:
return None
def insertRows(self, item, row=0, column=1, index=QModelIndex()):
self.beginInsertRows(index, row, row + 1)
self.items.append(item)
self.endInsertRows()
# def sort(self, column, order):
# print(order, 'order....')
# name_field = self.header_fields[column]
# if 'icon-' in name_field:
# return
# data = [(str(value[name_field]), value) for value in self.items]
# data.sort(key=itemgetter(0), reverse=order)
# self.currentItems = [v for k, v in data]
# self.layoutChanged.emit()
def sort(self, column, order):
name_field = self.header_fields[column]
if 'icon-' in name_field or not self.items:
return
if order == Qt.AscendingOrder:
reverse = False
else:
reverse = True
self.items.sort(key=lambda x: (x[name_field] is not None, x[name_field]), reverse=reverse)
self.layoutChanged.emit()
def setFilter(self, searchText=None, mainColumn=None, order=None):
if not searchText:
@ -479,7 +484,7 @@ class TableModel(QAbstractTableModel):
self.currentItems = self.items
if searchText and self.filter_column:
matchers = [t.lower() for t in searchText.split(' ')]
matchers = (t.lower() for t in searchText.split(' '))
self.filteredItems = []
for item in self.currentItems:
values = list(item.values())

View File

@ -106,6 +106,7 @@ class Ui_Login(object):
self.field_password.setMinimumSize(QSize(0, 44))
self.field_password.setMaximumSize(QSize(16777215, 44))
self.field_password.setFont(font1)
self.field_password.setFocus()
self.field_password.setAutoFillBackground(False)
self.field_password.setStyleSheet(u"border: 1.4px solid; border-radius:10%; background-color: palette(base); padding-top:8;padding-left:20;padding-bottom:0; padding-right:10;\n"
"border-color: rgb(154, 153, 150);\n"
@ -127,10 +128,6 @@ class Ui_Login(object):
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.verticalLayout_2.setContentsMargins(-1, 10, -1, 20)
# self.box_buttons = QDialogButtonBox()
# self.box_buttons.setOrientation(Qt.Vertical)
# sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
# self.box_buttons.setSizePolicy(sizePolicy)
font2 = QFont()
font2.setBold(True)
self.pushButtonOk = QPushButton(self.gridGroupBoxMain)
@ -155,11 +152,7 @@ class Ui_Login(object):
self.pushButtonCancel.setStyleSheet(u"border: 1.4px solid; border-radius:10%; border-color: red;\n"
"color: rgb(255, 255, 255);\n"
"background-color: qlineargradient(spread:pad, x1:0.234, y1:0.448864, x2:0.78607, y2:0.449, stop:0.00995025 rgba(255, 20, 89, 252), stop:0.313433 rgba(252, 28, 86, 255), stop:0.666667 rgba(255, 58, 87, 255), stop:0.935323 rgba(246, 60, 60, 253));")
# self.pushButtonCancel.setIconSize(QSize(20, 20))
# self.box_buttons.addButton(self.pushButtonOk, QDialogButtonBox.AcceptRole)
# self.box_buttons.addButton(self.pushButtonCancel, QDialogButtonBox.RejectRole)
# self.verticalLayout_2.addWidget(self.box_buttons)
self.verticalLayout_2.addWidget(self.pushButtonOk)
self.verticalLayout_2.addWidget(self.pushButtonCancel)
self.gridLayout.addLayout(self.verticalLayout_2, 9, 0, 2, 1)
@ -211,16 +204,10 @@ class Ui_Login(object):
self.gridLayout_2.addWidget(self.label_image, 0, 0, 3, 1)
# MainWindow.setCentralWidget(self.centralwidget)
# MainWindow.setLayout(self.centralwidget)
# connect signals and slots
# self.box_buttons.accepted.connect(MainWindow.accept)
# self.box_buttons.rejected.connect(MainWindow.reject)
self.pushButtonOk.clicked.connect(MainWindow.accept)
self.pushButtonCancel.clicked.connect(MainWindow.reject)
# self.field_user.textChanged.connect(MainWindow.update)
# self.field_database.textChanged.connect(MainWindow.update)
self.field_password.editingFinished.connect(MainWindow.accept)
# QMetaObject.connectSlotsByName(MainWindow)
# setupUi

View File

@ -1,5 +1,6 @@
from decimal import Decimal
from datetime import datetime
from operator import itemgetter
from .commons.dialogs import HelpDialog, QuickDialog
# from PyQt5.QtCore import Qt, QSize
# from PyQt5.QtWidgets import (
@ -104,13 +105,13 @@ class ControlPanel(QuickDialog):
self.setWindowTitle('PANEL DE CONTROL')
def get_control_panel(self):
menu_dash = [
menu_dash = (
('button_open', 'ABRIR ESTADOS DE CUENTA', 'action_open_statement'),
('button_closed', 'CERRAR ESTADOS DE CUENTA', 'action_close_statement'),
('button_expenses', 'GASTOS', 'action_expenses'),
('button_discount', 'DESCUENTOS AUTORIZADOS', 'action_table_discount'),
('button_delivery_party', 'CREAR DOMICILIARIO', 'action_delivery_party_panel'),
]
)
return menu_dash
@ -120,11 +121,11 @@ class DialogReports(QuickDialog):
vbox = QVBoxLayout()
grid = QGridLayout()
scroll_area = QScrollArea()
_reports = [
_reports = (
('button_square_box', 'CUADRE DE CAJA', 'action_square_box_report'),
('button_terminal_journal', 'PAGOS ELECTRONICOS', 'action_terminal_journal_report'),
('button_delivery_report', 'ENTREGA DOMICILIARIOS', 'action_delivery_report'),
]
)
self.reports = ButtonsFunction(parent, values=_reports)
self.parent = parent
scroll_area.setLayout(self.reports)
@ -179,28 +180,28 @@ class SearchSale(SearchWindow):
headers['invoice_number'] = {'desc': 'FACTURA', 'type': 'char'}
headers['salesman.rec_name'] = {'desc': 'VENDEDOR', 'type': 'char'}
widths = [20, 115, 115, 160]
widths_append = widths.append
if parent._sale_pos_restaurant:
headers['kind'] = {'desc': 'CLASE', 'type': 'char'}
widths.append(110)
widths_append(110)
headers['consumer.rec_name'] = {'desc': 'CONSUMIDOR', 'type': 'char'}
widths.append(300)
widths_append(300)
headers['table_assigned.rec_name'] = {'desc': 'MESA', 'type': 'char'}
widths.append(100)
widths_append(100)
headers['source.name'] = {'desc': 'FUENTE', 'type': 'char'}
widths.append(150)
widths_append(150)
headers['create_date'] = {'desc': 'HORA', 'type': 'time'}
widths.append(120)
widths_append(120)
else:
headers['party.name'] = {'desc': 'CLIENTE', 'type': 'char'}
widths.append(160)
widths_append(160)
headers['sale_date'] = {'desc': 'FECHA', 'type': 'char'}
widths.append(80)
widths_append(80)
headers['position'] = {'desc': 'POSICION', 'type': 'char'}
widths.append(130)
widths_append(130)
headers['total_amount_cache'] = {'desc': 'VALOR TOTAL', 'type': 'number'}
widths.append(90)
widths_append(90)
title = ('BUSCAR PEDIDOS...')
methods = {
@ -245,7 +246,7 @@ class SearchSale(SearchWindow):
self.buttons_layout_filter.addWidget(self.pushButtonReservation)
widgets_to_create = self.buttons_layout_filter
super(SearchSale, self).__init__(parent, headers, None, methods,
filter_column=[2, 3, 4, 5, 6, 7], cols_width=widths,
filter_column=(2, 3, 4, 5, 6, 7), cols_width=widths,
title=title, fill=True, widgets=[widgets_to_create])
def action_search_sale(self, _type):
@ -278,6 +279,7 @@ class SearchParty(SearchWindow):
class SearchProduct(SearchWindow):
def __init__(self, parent):
_cols_width = [10, 80]
_cols_width_append = _cols_width.append
headers = OrderedDict()
headers['id'] = {'desc': ('ID'), 'type': 'char'}
headers['code'] = {'desc': ('COD'), 'type': 'char'}
@ -286,22 +288,22 @@ class SearchProduct(SearchWindow):
if parent._config['show_stock_pos'] == 'icon':
headers['quantity']['icon'] = 'stock'
headers['quantity']['type'] = 'icon'
_cols_width.append(60)
_cols_width_append(60)
if not parent.cache_local:
headers['name'] = {'desc': 'NOMBRE', 'type': 'char'}
else:
headers['template.name'] = {'desc': 'NOMBRE', 'type': 'char'}
_cols_width.append(350)
_cols_width_append(350)
if parent._config.get('show_description_pos'):
headers['description'] = {'desc': 'DESCRIPCION', 'type': 'char'}
_cols_width.append(300)
_cols_width_append(300)
if parent._config.get('show_brand'):
headers['template.brand'] = {'desc': 'BRAND', 'type': 'char'}
_cols_width.append(100)
_cols_width_append(100)
price = {'desc': ('PRICE'), 'type': 'number'}
if not parent._config.get('encoded_sale_price'):
@ -310,15 +312,15 @@ class SearchProduct(SearchWindow):
price['type'] = 'char'
headers['encoded_sale_price'] = price
_cols_width.append(100)
_cols_width_append(100)
if parent._config.get('show_location_pos'):
headers['location.name'] = {'desc': 'BODEGA', 'type': 'char'}
_cols_width.append(100)
_cols_width_append(100)
if parent._config['show_product_image']:
headers['image'] = {'desc': 'IMAGEN', 'icon': 'image', 'type': 'icon'}
_cols_width.append(30)
_cols_width_append(30)
methods = {
'on_selected_method': 'on_selected_product',
@ -350,9 +352,9 @@ class DialogManageTables(QuickDialog):
widgets=[self.manager])
self.setFixedSize(int(width / 1.5), int(height / 1.5))
def exec_(self):
def exec(self):
self.open_tables()
super(DialogManageTables, self).exec_()
super(DialogManageTables, self).exec()
def open_tables(self):
tables = self.parent.RestTables.find([
@ -512,7 +514,7 @@ class DialogConsumer(QuickDialog):
class DialogHistoricSales(QuickDialog):
def __init__(self, parent):
width, height = get_screen()
col_sizes = [fd['width'] for fd in parent.fields_sales_query]
col_sizes = (fd['width'] for fd in parent.fields_sales_query)
vbox_ = QVBoxLayout()
table = TableView(
@ -556,8 +558,9 @@ class DialogSaleForm(QuickDialog):
]
fields = OrderedDict(_fields)
self.grid = GridForm(self, fields, col=2)
col_sizes = [field['width'] for field in parent.fields_sale_line]
self.table = TableView('model_sale_lines',
col_sizes = (field['width'] for field in parent.fields_sale_line)
self.table = TableView(
'model_sale_lines',
parent.model_sale_lines_simple, col_sizes
)
self.grid.addWidget(self.table, 4, 1, 1, 4)
@ -569,16 +572,21 @@ class DialogSaleForm(QuickDialog):
self.setFixedSize(int(width * 0.5), int(height * 0.6))
def start(self, data):
self.sale_customer_selected = data['id']
self.field_party.setText(data['party']['name'])
self.field_number.setText(data['number'])
self.field_sale_date.setText(data['sale_date'])
self.field_total_amount_cache.setText(str(data['total_amount_cache']))
self.field_invoice_number.setText(str(data['invoice_number']))
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'])
self.field_number.setText(number)
self.field_sale_date.setText(sale_date)
self.field_total_amount_cache.setText(str(total_amount_cache))
self.field_invoice_number.setText(str(invoice_number))
self.table.model.reset()
for line in data['lines']:
for line in lines:
self.table.model.add_record(line)
self.exec_()
self.exec()
def get_button(self):
button_duplicate_sale = CustomButton(
@ -599,14 +607,12 @@ class DialogSaleForm(QuickDialog):
self.dialog_search_consumer.close()
self.dialog_table_sale_consumer.close()
self.dialog_sale_consumer_selected.close()
# FIXME
# self.load_sale(res['sale_id'])
return res
class DialogAgent(QuickDialog):
def __init__(self, parent):
view = [
view = (
('agent_ask', {
'name': 'AGENTE',
'type': 'relation',
@ -620,18 +626,18 @@ class DialogAgent(QuickDialog):
}),
('commission_ask', {'name': 'COMISION'}),
('commission_amount', {'name': 'VALOR', 'readonly': True}),
]
)
super(DialogAgent, self).__init__(parent, 'action', data=view)
class DialogCancelInvoice(QuickDialog):
def __init__(self, parent):
view = [
view = (
('password_for_cancel_ask', {
'name': 'INGRESE LA CONTRASEÑA',
'password': True
}),
]
)
super(DialogCancelInvoice, self).__init__(parent, 'action', data=view)
@ -653,7 +659,7 @@ class DialogStock(QuickDialog):
data = {
'name': 'stock',
'values': [],
'heads': ['BODEGA', 'CANTIDAD', 'POSICION'],
'heads': ('BODEGA', 'CANTIDAD', 'POSICION'),
}
label = 'STOCK POR PRODUCTO:'
width, height = get_screen()
@ -671,7 +677,7 @@ class DialogGlobalDiscount(QuickDialog):
class DialogPrintInvoice(QuickDialog):
def __init__(self, parent):
view = [
view = (
('invoice_number_ask', {'name': 'ORDEN / FACTURA'}),
('type_ask', {
'name': 'TIPO',
@ -695,20 +701,20 @@ class DialogPrintInvoice(QuickDialog):
'type': 'checkbox',
'placeholder': 'REENVIO DIAN',
}),
]
)
super(DialogPrintInvoice, self).__init__(parent, 'action', data=view)
class DialogAdvance(QuickDialog):
def __init__(self, parent):
data = [
data = (
('amount_ask', {'name': 'VALOR'}),
('reservation_ask', {
'name': 'RESERVA',
'type': 'checkbox',
'placeholder': 'RESERVA',
}),
]
)
super(DialogAdvance, self).__init__(parent, 'action', data=data)
def clean(self):
@ -853,10 +859,11 @@ class DeliveryPartySelected(QuickDialog):
class DialogTableDeliveryParty(QuickDialog):
def __init__(self, parent):
self._parent = parent
col_sizes_tlines = [field['width'] for field in parent.fields_delivery_party]
table = TableView('model_delivery_party',
parent.model_delivery_party, col_sizes_tlines,
method_selected_row=parent.delivery_party_selected
col_sizes_tlines = (field['width'] for field in parent.fields_delivery_party)
table = TableView(
'model_delivery_party',
parent.model_delivery_party, col_sizes_tlines,
method_selected_row=parent.delivery_party_selected
)
width, height = get_screen()
table.setFixedSize(int(width/2.2), int(height/2.2))
@ -893,12 +900,12 @@ class DialogMoneyCount(QuickDialog):
self.kind = None
width, height = get_screen()
grid = QGridLayout()
_sizes = [160, 120, 240]
fields = [
_sizes = (160, 120, 240)
fields = (
{'label': 'MONEDA', 'type': 'integer', 'readonly': True},
{'label': 'CANTIDAD', 'type': 'integer', 'change': 'set_total'},
{'label': 'SUBTOTAL', 'type': 'integer', 'readonly': True},
]
)
self.model = TableEdit(self, MONEY, fields)
table = TableView('model', self.model, _sizes, editable=True)
table.setFixedSize(int(width * 0.35), int(height * 0.4))
@ -958,7 +965,7 @@ class DialogMoneyCount(QuickDialog):
if self.kind == 'open':
kind = 'APERTURA'
_data = [(str(d[0]), str(d[1]), str(d[2])) for d in self.model._data]
_data = ((str(d[0]), str(d[1]), str(d[2])) for d in self.model._data)
data = {
'type': kind,
'total': self.field_total_money.text(),
@ -995,14 +1002,14 @@ class DialogExpenses(QuickDialog):
# )
# grid.addWidget(self.button_test, 1, 1)
_sizes = [140, 290, 210, 150]
fields = [
_sizes = (140, 290, 210, 150)
fields = (
{'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': 'integer', 'change': 'set_total'},
]
)
self.model = TableEdit(self, [], fields)
self.table = TableView('model_expenses', self.model, _sizes, editable=True)
self.table.hideColumn(0)
@ -1028,15 +1035,16 @@ class DialogExpenses(QuickDialog):
def load(self):
if not self.parent.data_expenses:
return
model_add = self.model.add_record
for rec in self.parent.data_expenses:
data = [
data = (
rec['id'],
rec['invoice_number'],
rec['description'],
rec['reference'],
rec['amount']
]
self.model.add_record(data)
)
model_add(data)
self.field_total.setText(str(self.model.get_sum(4)))
def set_total(self, args=None):
@ -1079,7 +1087,7 @@ class DialogExpenses(QuickDialog):
class DialogTaxes(QuickDialog):
def __init__(self, parent):
if parent.shop_taxes:
taxes = [(str(e['id']), e['name']) for e in parent.shop_taxes]
taxes = ((str(e['id']), e['name']) for e in parent.shop_taxes)
else:
taxes = []
data = {
@ -1506,7 +1514,7 @@ class Help(HelpDialog):
def __init__(self, parent):
super(Help, self).__init__(parent)
shortcuts = [
shortcuts = (
('PANEL DE CONTROL', 'F1'),
('BUSCAR PRODUCTO', 'F2'),
('MEDIO DE PAGO', 'F3'),
@ -1522,7 +1530,7 @@ class Help(HelpDialog):
('POSICION', 'Insert'),
('FACTURAR', 'End'),
('COMENTARIO', 'Quotation Marks'),
]
)
self.set_shortcuts(shortcuts)
@ -1633,10 +1641,10 @@ class DialogInfoProduct(QuickDialog):
products = self._parent.local_db.find_product_elastic(domain, limit=100)
else:
products = self._parent.Product.find(domain, ctx=self._parent.stock_context,
fields=['name', 'code', 'categories', 'description', 'encoded_sale_price'
fields=['name', 'code', 'categories', 'description',
'id', 'image', 'image_icon', 'list_price', 'location'
'products_mix', 'quantity', 'rec_name', 'template',
'extra_tax', 'template.sale_price_w_tax', 'uom',
'extra_tax', 'template.sale_price_w_tax', 'sale_uom',
'barcode', 'write_date'])
if not products:
@ -1662,11 +1670,11 @@ class DialogInfoProduct(QuickDialog):
parent = self._parent
width, height = get_screen()
grid = QGridLayout()
_sizes = [160, 320]
fields = [
_sizes = (160, 320)
fields = (
{'label': 'CODIGO', 'type': 'integer', 'readonly': False},
{'label': 'NOMBRE', 'type': 'char', 'readonly': False},
]
)
self.model = TableEdit(self, [], fields)
self.table = TableView('model_info_product', self.model, _sizes, editable=False, method_selected_row=self.on_selected_product)
self.table.setFixedSize(int(width * 0.35), int(height * 0.4))

View File

@ -9,7 +9,8 @@ except:
print('Warning: missing pyserial module!')
from decimal import Decimal
from PyQt5.QtCore import QThread, pyqtSignal
# from PyQt5.QtCore import QThread, pyqtSignal
from PySide6.QtCore import QThread, Signal
ZERO_VALUES = [b'00.000\n', b'\r00.000\n']
FAKE_WEIGHT = b'01.500\n'
@ -20,9 +21,9 @@ class ScaleReader(QThread):
"""
Electronic Scale Reader Class
"""
sigSetDevice = pyqtSignal()
sigSetWeight = pyqtSignal()
sigCancelAction = pyqtSignal()
sigSetDevice = Signal()
sigSetWeight = Signal()
sigCancelAction = Signal()
def __init__(self, device_path='/dev/ttyUSB0', fake=False):
QThread.__init__(self)

View File

@ -9,8 +9,8 @@ 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
from .proxy import FastModel, Model
# from .commons.dblogin import safe_reconnect
from .proxy import Model
from .constants import SCREENS
from .dialogs import (
Help, ControlPanel, SearchSale, SearchParty, SearchProduct, Position,
@ -124,7 +124,8 @@ class FrontWindow(QMainWindow):
self.global_timer += 1
if self.global_timer > self.timeout:
self.global_timer = 0
safe_reconnect()
print('error esta linea no debia ejecutarse')
# safe_reconnect()
def close(self):
dialog = self.dialog('confirm_exit', response=True)
@ -163,13 +164,16 @@ class FrontWindow(QMainWindow):
self._keyStates[event.key()] = False
def create_dialogs(self):
print('control panel')
self.dialog_control_panel = ControlPanel(self)
self.dialog_money_count = DialogMoneyCount(self)
self.dialog_search_sales = SearchSale(self)
print('control panel')
self.dialog_search_parties = SearchParty(self)
self.dialog_search_products = SearchProduct(self)
self.dialog_position = Position(self)
self.dialog_tip_amount = TipAmount(self)
print('control panel')
self.dialog_delivery_amount = DeliveryAmount(self)
self.dialog_comment = Comment(self)
self.dialog_payment = DialogPayment(self)
@ -215,6 +219,15 @@ class FrontWindow(QMainWindow):
def resize_window_tablet_dev(self):
self.resize(690, self.get_geometry()[1])
def get_allow_categories_ids(self):
allow_cat = []
allow_cat_append = allow_cat.append
allow_cat_extend = allow_cat.extend
for pc in self.product_categories:
allow_cat_append(pc['id'])
allow_cat_extend(pc['childs'])
return allow_cat
def load_modules(self):
self._sale_pos_restaurant = None
time1 = time.time()
@ -270,7 +283,7 @@ class FrontWindow(QMainWindow):
])
if self._sale_pos_restaurant:
self.PartyConsumer = Model('party.consumer', self.ctx)
if self._config['delivery_product']:
if self._config['delivery_product.']:
self._delivery_product = 0
self.User = Model('res.user', self.ctx)
@ -342,6 +355,7 @@ class FrontWindow(QMainWindow):
self.user_can_delete = self.type_pos_user in ('frontend_admin', 'cashier')
self.product_categories = self.shop['product_categories.']
self.allow_categories_ids = self.get_allow_categories_ids()
self.salesman_required = self.shop['salesman_pos_required']
self.default_party = self.shop['party.']
@ -362,12 +376,11 @@ class FrontWindow(QMainWindow):
if self._config['show_stock_pos'] in ('value', 'icon'):
self.stock_context = {
'stock_date_end': date.today(),
'locations': [self.shop['warehouse']['id']],
'locations': [self.shop['warehouse']],
}
self.Source = Model('sale.source', self.ctx)
self.Pricelist = Model('product.price_list', self.ctx)
print('finalice load')
return True

View File

@ -10,8 +10,6 @@ from packaging.version import parse as parse_version
from decimal import Decimal
from datetime import datetime, timedelta, date
from collections import OrderedDict
# from PyQt5.QtCore import Qt
# from PyQt5.QtWidgets import (QLabel, QHBoxLayout, QVBoxLayout, QWidget)
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (QLabel, QHBoxLayout, QVBoxLayout, QWidget)
from app.commons.image import Image
@ -43,8 +41,10 @@ import time
invoice_type = []
_SALE_HISTORIC = [
'party', 'sale_date', 'number', 'invoice_number', 'consumer',
'total_amount_cache', 'lines'
'party.name', 'sale_date', 'number', 'invoice_number', 'consumer',
'total_amount_cache', 'lines.quantity', 'lines.product.name', 'lines.unit.symbol',
'lines.amount', 'lines.unit_price_w_tax', 'lines.amount_w_tax',
'lines.product.template.name', 'lines.note'
]
@ -61,30 +61,25 @@ class AppWindow(FrontWindow):
self.set_keys()
time1 = time.time()
StackMessages(self)
print(time.time() - time1, 'load stack messages')
self.stock_context = None
self._sale = {}
self.ctx = self._context
self.ctx['params'] = params
time2 = time.time()
response = self.load_modules()
print(time.time() - time2, 'load modules')
if response is not True:
d = self.dialog(response)
d.exec_()
super(AppWindow, self).close()
return
time3 = time.time()
self.setup_sale_line()
self.setup_delivery_party()
self.setup_sale_consumer()
self.setup_payment()
self.set_domains()
print(time.time() - time1, 'set domains')
print(time.time() - time3, 'load setups')
time1 = time.time()
self.create_gui()
print(time.time() - time1, 'load gui')
print(time.time() - time1, 'create gui')
self.message_bar.load_stack(self.stack_msg)
self.journal = {}
if not hasattr(self, 'auto_print_commission'):
@ -104,10 +99,8 @@ class AppWindow(FrontWindow):
self._amount_text = ''
self._input_text = ''
self._sign = None
time1 = time.time()
self.create_dialogs()
print(time.time() - time1, 'load dialogs')
time1 = time.time()
print(time.time() - time1, 'create dialogs')
self.store = StoreView(self, SALE_FIELDS)
if not hasattr(self, 'active_weighing'):
self.active_weighing = False
@ -127,7 +120,8 @@ class AppWindow(FrontWindow):
for j in self._journals:
if j['id'] == self.default_journal['id']:
self.default_journal = j
print(time.time() - time1, 'load final')
time6 = time.time()
print(time6 - time1, 'load final')
def set_domains(self):
self.domain_search_product = [
@ -336,23 +330,22 @@ class AppWindow(FrontWindow):
# CONFIGURE BOARD
board.addWidget(self.start_front, 0)
if self.mode_conn == 'offline':
self.WidgetOffline = QWidget()
self.WidgetOffline.setObjectName('label_offline')
vbox_label = QVBoxLayout()
vbox_label.setAlignment(Qt.AlignBottom)
LabelOffline = QLabel(self.mode_conn)
LabelOffline.setObjectName('LabelOffline')
LabelOffline.setAlignment(Qt.AlignCenter)
LabelOffline.setStyleSheet(
"""background-color:red;
font: 30px; color: white;
font-weight: bold;
min-height: 60px;
max-height: 90px""")
vbox_label.addWidget(LabelOffline)
self.WidgetOffline.setLayout(vbox_label)
board.addWidget(self.WidgetOffline, 2)
self.WidgetShop = QWidget()
self.WidgetShop.setObjectName('label_shop')
vbox_label = QVBoxLayout()
vbox_label.setAlignment(Qt.AlignBottom)
LabelShop = QLabel(self.WidgetShop)
LabelShop.setObjectName('LabelShop')
LabelShop.setText(self.shop['name'])
LabelShop.setStyleSheet(
"""
font: 30px; color: grey;
font-weight: bold;
min-height: 60px;
max-height: 90px""")
vbox_label.addWidget(LabelShop)
self.WidgetShop.setLayout(vbox_label)
board.addWidget(self.WidgetShop, 2)
board.addWidget(self.order_front, 0)
# LEFT HEAD COMPONENTS
@ -673,10 +666,12 @@ class AppWindow(FrontWindow):
if self.enviroment == 'restaurant':
self.panel_right_box = QWidget()
time3 = time.time()
values = self.get_product_by_categories_dash()
# print(self.product_categories, 'product categories')
# values = self.get_product_by_categories_dash()
values = self.product_categories
print(time.time() - time3, 'load products categories dash')
self.menu_dash = MenuDash(self, values, 'on_selected_item')
print('final dash')
self.order_front.hide()
vbox_order_front.addLayout(self.buttons_function, 0)
vbox_order_front.addLayout(self.grid_info, 0)
@ -801,7 +796,7 @@ class AppWindow(FrontWindow):
try:
quantity = Decimal(eval_value)
try:
product_id = self._sale_line['product']['id']
product_id = self._sale_line['product.']['id']
except:
product_id = self._sale_line['product']
if product_id and self.stock_context:
@ -855,7 +850,7 @@ class AppWindow(FrontWindow):
sale_line, = self.SaleLine.find([
('id', '=', line_id)
])
price_w_tax = float(str(round(sale_line['product']['sale_price_taxed'], 0)))
price_w_tax = float(str(round(sale_line['product.']['sale_price_taxed'], 0)))
if price_w_tax <= value:
discount_valid = self.set_unit_price(value, discount=False)
else:
@ -901,9 +896,10 @@ class AppWindow(FrontWindow):
return True
self.set_amounts()
for j in self._journals:
if j['id'] == self.default_journal['id']:
self.journal = j
print(self._journals, self.default_journal)
# for j in self._journals:
# if j['id'] == self.default_journal['id']:
self.journal = self.default_journal
if res['msg'] == 'missing_money':
self.message_bar.set('enter_payment', self.default_journal['name'])
@ -1114,7 +1110,7 @@ class AppWindow(FrontWindow):
self.set_amounts(res)
self._sale['number'] = res['number']
self.field_number.setText(self._sale['number'])
print(self.default_journal, 'defaut journal')
self.field_invoice_number.setText(res['invoice_number'])
self.field_amount.setText('')
self.set_state('payment')
@ -1614,7 +1610,7 @@ class AppWindow(FrontWindow):
sale_line, = self.SaleLine.find([
('id', '=', line_id)
])
price_w_tax = sale_line['product']['sale_price_taxed']
price_w_tax = sale_line['product.']['sale_price_taxed']
price = Decimal(price_w_tax) - (discount/Decimal(line['quantity']))
if price < 0:
price = 0
@ -2042,34 +2038,25 @@ class AppWindow(FrontWindow):
# return records
def get_product_by_categories_dash(self):
allow_categories = [
pc for pc in self.product_categories
if not pc['parent'] and not pc['accounting']]
get_products = self._get_products_by_category_dash
find = self.Product.find
for cat in allow_categories:
cat['icon'] = get_icon(cat['name_icon'])
if cat.get('childs.'):
for child in cat.get('childs.'):
get_products(child, find)
else:
get_products(cat, find)
return allow_categories
# self.allow_categories = {
# pc['id']: pc for pc in self.product_categories \
# if not pc['parent'] and not pc['accounting']
# }
# def get_product_by_categories_dash(self):
# self.allow_categories = [
# pc for pc in self.product_categories
# if not pc['parent'] and not pc['accounting']]
# get_products = self._get_products_by_category_dash
# find = self.Product.find
# for cat in self.allow_categories:
# cat['icon'] = get_icon(cat['name_icon'])
# if cat.get('childs.'):
# for child in cat.get('childs.'):
# get_products(child, find)
# else:
# get_products(cat, find)
# return self.allow_categories
# get_products = self._get_products_by_category_dash
# find = self.Product.find
# for cat in self.allow_categories:
# cat['icon'] = get_icon(cat['name_icon'])
# if cat.get('childs.'):
# for child in cat.get('childs.'):
# get_products(child, find)
# else:
# get_products(cat, find)
values = self.Sale.get_product_by_categories(
{
'categories': self.allow_categories_ids
})
return values
def action_square_box_report(self):
try:
@ -2190,7 +2177,10 @@ class AppWindow(FrontWindow):
line = self.dialog_product_edit.get()
self._current_line_id = line['id']
# list_price = line['product'].get('list_price')
code = line['product']['code']
try:
code = line['product.']['code']
except:
code = line['product']['code']
product = self.Product.find([('code', '=', code)], fields=["list_price"])
list_price = product[0].get('list_price')
@ -2200,7 +2190,7 @@ class AppWindow(FrontWindow):
if list_price < list_price_r:
# Update price in selected_line
self.set_unit_price(product_r[0]['template']['sale_price_w_tax'], discount=False)
self.set_unit_price(product_r[0]['template.']['sale_price_w_tax'], discount=False)
list_price = None
self.on_selected_item(record, list_price)
self.dialog_combine_product.close()
@ -2265,7 +2255,7 @@ class AppWindow(FrontWindow):
if journal.get('id'):
self.field_journal_id = journal['id']
self.dialog_payment.close()
self.message_bar.set('enter_payment', journal['rec_name'])
self.message_bar.set('enter_payment', journal['name'])
def on_search_product(self):
target = self.dialog_search_products.filter_field.text()
@ -2288,9 +2278,8 @@ class AppWindow(FrontWindow):
]
domain.append(clause)
if not self._sale_pos_restaurant and self.shop.get('product_categories'):
categories_id = [ct['id']
for ct in self.shop['product_categories']]
if self.shop.get('product_categories'):
categories_id = self.allow_categories_ids
domain.append([
'OR',
('template.categories', 'in', categories_id),
@ -2523,10 +2512,13 @@ class AppWindow(FrontWindow):
return True
for line in self.model_sale_lines._data:
product_id = None
if isinstance(line['product'], int):
product_id = line['product']
elif isinstance(line['product'], dict):
product_id = line['product']['id']
if line.get('product'):
if isinstance(line['product'], dict):
product_id = line['product']['id']
else:
product_id = line['product']
elif line.get('product.'):
product_id = line['product.']['id']
if product_id:
product, = self.Product.find(
[('id', '=', product_id)],
@ -2907,16 +2899,19 @@ class AppWindow(FrontWindow):
def action_combo(self):
line = self.dialog_product_edit.get()
code = line['product']['code']
try:
code = line['product.']['code']
except:
code = line['product']['code']
product = self.Product.find(
[('code', '=', code)],
fields=[
"barcode", "code", "description", "extra_tax", "name", "uom",
"barcode", "code", "description", "extra_tax", "name", "sale_uom",
"quantity", "sale_price_w_tax", "template.account_category",
"template.sale_price_w_tax", "template.rec_name", "product_mix",
'products_mix', 'products_mix.code', 'products_mix.name'
"template.sale_price_w_tax", "template.rec_name",
'products_mix.code', 'products_mix.name'
])
products_mix = product[0].get('products_mix')
products_mix = product[0].get('products_mix.')
if not products_mix:
return
self.dialog_combo_product.set_buttons(products_mix)
@ -2925,14 +2920,17 @@ class AppWindow(FrontWindow):
def action_combine_line(self):
line = self.dialog_product_edit.get()
code = line['product']['code']
try:
code = line['product.']['code']
except:
code = line['product']['code']
product = self.Product.find([('code', '=', code)])
categories = product[0].get('categories')
if not categories:
return
categories_ids = [cat['id'] for cat in categories]
mixables = self.Product.find([
('categories', 'in', categories_ids),
('categories', 'in', categories),
], fields=['id', 'name', 'code', 'categories', 'rec_name', 'list_price'])
self.dialog_combine_product.set_buttons(mixables)
self.dialog_combine_product.exec_()
@ -3131,7 +3129,6 @@ class AppWindow(FrontWindow):
self.action_read_weight()
def key_special_pressed(self, value):
print('especial presed2222')
self.clear_amount_text()
self.clear_input_text()
if value not in ['-', '/', '*']:
@ -3271,7 +3268,7 @@ class AppWindow(FrontWindow):
sale_line, = self.SaleLine.find([
('id', '=', line['id'])
])
base_price = float(str(round(sale_line['product']['sale_price_taxed'], 0)))
base_price = float(str(round(sale_line['product.']['sale_price_taxed'], 0)))
previous_qty = Decimal(line['quantity'])
self._current_line_id = line['id']
to_write = {}

View File

@ -96,16 +96,24 @@ MODELS = {
'rec_name': 'name',
'fields': [
'name', 'shop.company', 'shop.name', 'shop.taxes', 'shop.taxes.name',
'shop.party.name', 'journals.rec_name',
'shop.party.name', 'journals.name',
'shop.product_categories.accounting',
'shop.product_categories.rec_name',
'shop.product_categories.name',
'shop.product_categories.name_icon',
'shop.product_categories.parent',
'shop.product_categories.childs.accounting',
'shop.product_categories.childs.name_icon',
'shop.product_categories.childs.parent',
'shop.product_categories.childs.rec_name',
'shop.product_categories.childs.name',
'shop.product_categories.childs',
'shop.product_categories.products.id',
'shop.product_categories.products.name',
'shop.product_categories.products.code',
'shop.product_categories.childs.products.id',
'shop.product_categories.childs.products.name',
'shop.product_categories.childs.products.code',
'journal.name',
'journal.kind',
'shop.payment_term.name', 'shop.warehouse', 'shop.discount_pos_method',
'shop.salesman_pos_required', 'shop.electronic_authorization',
'shop.invoice_copies', 'shop.pos_authorization', 'shop.discounts',
@ -126,9 +134,10 @@ MODELS = {
'fields': [
'name', 'code', 'barcode', 'write_date', 'description',
'template.sale_price_w_tax', 'template.account_category',
'location.name', 'image', 'image_icon', 'quantity', 'list_price',
'encoded_sale_price', 'location', 'uom', 'categories',
'products_mix', 'products_mix.code', 'products_mix.name'
'image', 'image_icon', 'quantity', 'list_price',
'sale_uom.name', 'categories',
'products_mix.code', 'products_mix.name'
# 'location.name', 'encoded_sale_price',
],
'binaries': ['image']
},
@ -148,15 +157,17 @@ MODELS = {
'sale.configuration': {
'rec_name': 'id',
'fields': [
'tip_product', 'tip_product.code', 'show_description_pos',
'tip_product.code', 'show_description_pos',
'show_position_pos', 'show_stock_pos', 'password_force_assign',
'tip_rate', 'show_agent_pos', 'discount_pos_method', 'show_brand',
'show_location_pos', 'show_delivery_charge', 'use_price_list',
'decimals_digits_quantity', 'password_admin_pos', 'show_fractions',
'new_sale_automatic', 'show_product_image',
'print_invoice_payment', 'delivery_product', 'encoded_sale_price',
'delivery_product.list_price', 'delivery_product.code', 'allow_discount_handle',
'cache_products_local', 'show_party_categories', 'print_lines_product',
'print_invoice_payment', 'encoded_sale_price',
'delivery_product.list_price', 'delivery_product.code',
'delivery_product.name', 'allow_discount_handle',
'cache_products_local', 'show_party_categories',
'print_lines_product'
]
},
'party.address': {

View File

@ -1,11 +1,12 @@
import os
import base64
import requests
import tempfile
from datetime import date
# import simplejson as json
from decimal import Decimal
from http.client import HTTPConnection, HTTPSConnection
import orjson as json
# import simplejson as json
# import requests
try:
from app.models import MODELS
except:
@ -17,6 +18,12 @@ except:
from commons.common import slugify, file_open
HEADERS = {
"Content-type": "application/json",
"Accept": "text/plain"
}
def encoder(obj):
# FIXME: add datetime, buffer, bytes
if isinstance(obj, date):
@ -26,138 +33,24 @@ def encoder(obj):
'month': obj.month,
'day': obj.day,
}
elif isinstance(obj, Decimal):
return str(obj)
raise TypeError(repr(obj) + " is not JSON serializable")
class FastModel(object):
def __init__(self, model, ctx, fields=None):
self.model = model
self.ctx = ctx
api_url = ctx['params']['api_url']
db = ctx['params']['database']
self.api = '/'.join(['http:/', api_url, db])
_model = MODELS.get(model)
self.fields = None
if fields:
self.fields = fields
elif _model.get('fields'):
self.fields = _model['fields']
def __getattr__(self, name, *args):
'Return attribute value'
self.method = name
return self
def find(self, domain, order=None, limit=1000, ctx=None, fields=None):
if ctx:
self.ctx.update(ctx)
route = self.get_route('search')
if not fields:
fields = self.fields
args_ = {
'model': self.model,
'domain': domain,
'order': order,
'limit': limit,
'fields': fields,
'context': self.ctx,
}
data = json.dumps(args_, default=encoder)
res = requests.post(route, data=data)
return res.json()
def write_many(self, ids, values, fields=None):
route = self.get_route('save_many')
if not fields:
fields = self.fields
args_ = {
'model': self.model,
'ids': ids,
'values': values,
'fields': fields,
'context': self.ctx,
}
data = json.dumps(args_, default=encoder)
res = requests.put(route, data=data)
return res.json()
def write(self, ids, values, fields=None):
route = self.get_route('save')
if not fields:
fields = self.fields
if values.get('rec_name'):
_ = values.pop('rec_name')
args_ = {
'model': self.model,
'id': ids[0],
'ids': ids,
'record_data': values,
'fields': fields,
'context': self.ctx,
}
data = json.dumps(args_, default=encoder)
res = requests.put(route, data=data)
return res.json()
def create(self, values):
route = self.get_route('create')
if values.get('rec_name'):
_ = values.pop('rec_name')
args_ = {
'model': self.model,
'record': values,
'context': self.ctx,
}
data = json.dumps(args_, default=encoder)
res = requests.post(route, data=data)
return res.json()
def delete(self, ids):
route = self.get_route('delete')
args_ = {
'model': self.model,
'ids': ids,
'context': self.ctx,
}
data = json.dumps(args_, default=encoder)
res = requests.delete(route, data=data)
return res.json()
def get_route(self, target):
route = self.api + '/' + target
return route
def __call__(self, values=None, ctx=None):
if ctx:
self.ctx.update(ctx)
args_ = {
'model': self.model,
'method': self.method,
'args': values,
'context': self.ctx,
}
route = self.get_route('model_method')
data = json.dumps(args_, default=encoder)
res = requests.post(route, data=data)
response = None
try:
response = res.json()
except ValueError:
pass
return response
class Model(object):
def __init__(self, model, ctx, fields=None):
self.model = model
self.ctx = ctx
api_url = ctx['params']['api_url']
mode = ctx['params']['mode']
db = ctx['params']['database']
self.api = '/'.join([mode + ':/', api_url, db])
self.port = ctx['params']['port']
self.host = ctx['params']['server']
self.db = ctx['params']['database']
self.api = 'http://localhost:8010/ZIRUS'
if ctx['params']['mode'] == 'http':
self.conn = HTTPConnection
else:
self.conn = HTTPSConnection
_model = MODELS.get(model)
self.fields = None
if fields:
@ -173,7 +66,6 @@ class Model(object):
def find(self, domain, order=None, limit=1000, ctx=None, fields=None):
if ctx:
self.ctx.update(ctx)
route = self.get_route('search')
if not fields:
fields = self.fields
args_ = {
@ -184,12 +76,14 @@ class Model(object):
'fields_names': fields,
'context': self.ctx,
}
data = json.dumps(args_, default=encoder)
res = requests.post(route, data=data)
return res.json()
res = self.get_connection('POST', '/search', args_)
return res
# route = self.get_route('search')
# data = json.dumps(args_, default=encoder)
# res = requests.post(route, data=data)
# return res.json()
def write_many(self, ids, values, fields=None):
route = self.get_route('save_many')
if not fields:
fields = self.fields
args_ = {
@ -199,13 +93,14 @@ class Model(object):
'fields': fields,
'context': self.ctx,
}
data = json.dumps(args_, default=encoder)
res = requests.put(route, data=data)
return res.json()
res = self.get_connection('POST', '/save_many', args_)
return res
# route = self.get_route('save_many')
# data = json.dumps(args_, default=encoder)
# res = requests.put(route, data=data)
# return res.json()
def write(self, ids, values, fields=None):
route = self.get_route('write')
if not fields:
fields = self.fields
if values.get('rec_name'):
@ -217,12 +112,14 @@ class Model(object):
'fields': fields,
'context': self.ctx,
}
data = json.dumps(args_, default=encoder)
res = requests.post(route, data=data)
return res.json()
res = self.get_connection('POST', '/write', args_)
return res
# route = self.get_route('write')
# data = json.dumps(args_, default=encoder)
# res = requests.post(route, data=data)
# return res.json()
def create(self, values):
route = self.get_route('create')
if values.get('rec_name'):
_ = values.pop('rec_name')
args_ = {
@ -230,25 +127,43 @@ class Model(object):
'record': values,
'context': self.ctx,
}
data = json.dumps(args_, default=encoder)
res = requests.post(route, data=data)
return res.json()
res = self.get_connection('POST', '/create', args_)
return res
# route = self.get_route('create')
# data = json.dumps(args_, default=encoder)
# res = requests.post(route, data=data)
# return res.json()
def delete(self, ids):
route = self.get_route('delete')
args_ = {
'model': self.model,
'ids': ids,
'context': self.ctx,
}
data = json.dumps(args_, default=encoder)
res = requests.post(route, data=data)
return res.json()
res = self.get_connection('POST', '/delete', args_)
return res
# route = self.get_route('delete')
# data = json.dumps(args_, default=encoder)
# res = requests.post(route, data=data)
# return res.json()
def get_route(self, target):
route = self.api + '/' + target
return route
def get_connection(self, method, target, data=None):
url = '/' + self.db + target
if data:
payload = json.dumps(data, default=encoder)
else:
payload = None
conn = self.conn(self.host, port=self.port)
conn.request(method, url, body=payload, headers=HEADERS)
response = conn.getresponse()
res = json.loads(response.read())
conn.close()
return res
def __call__(self, values=None, ctx=None):
if ctx:
self.ctx.update(ctx)
@ -258,15 +173,17 @@ class Model(object):
'args': values,
'context': self.ctx,
}
route = self.get_route('method')
data = json.dumps(args_, default=encoder)
res = requests.post(route, data=data)
response = None
try:
response = res.json()
except ValueError:
pass
return response
res = self.get_connection('POST', '/method', args_)
return res
# route = self.get_route('method')
# data = json.dumps(args_, default=encoder)
# res = requests.post(route, data=data)
# response = None
# try:
# response = res.json()
# except ValueError:
# pass
# return response
class FastReport(object):

6
pospro
View File

@ -27,17 +27,13 @@ class Client(object):
self.app = QApplication(sys.argv)
def init_login(self):
_file_config = 'config_pos.ini'
_file_config = 'config_pos_v2.ini'
if args.o:
_file_config = args.o
login = Login(file_config=_file_config)
while not login.connection:
login.run()
login.exec()
# login.params['database'] = login.field_database.text()
# login.params['user'] = login.field_user.text()
# login.params['server'] = login.field_host.text()
# login.params['api_url'] = login.api_url
return login.connection, login.params, login.mode_conn
def main(self, conn, params, mode_conn):

View File

@ -1,11 +1,12 @@
#!/usr/bin/env python
# This file is part of Presik POS. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from setuptools import setup
from setuptools import setup, find_packages
import os
import glob
import shutil
from .app import __version__
# from .app import __version__
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
@ -33,14 +34,21 @@ if os.name == 'posix':
path_inifile = os.path.join(default_dir, 'config_pos.ini')
setup(name='presik_pos',
version=__version__,
setup(
name='presik_pos',
# version=__version__,
description='POS Client for Tryton',
author='Oscar Alvarez',
author_email='gerente@presik.com',
url='www.presik.com',
download_url="http://www.bitbucket.org",
packages=['app/frontend', 'app/commons', 'client', 'app/css', 'app/locale'],
packages=[
'app',
'app/printing',
'app/commons',
'app/css',
'app/locale'
],
data_files=data_files,
scripts=['pospro'],
classifiers=[
@ -55,5 +63,14 @@ setup(name='presik_pos',
'Topic :: Office/Business',
],
license='GPL',
install_requires=[]
install_requires=[
'pyusb',
'pillow',
'qrcode',
'paramiko',
'orjson',
'escpos',
'packaging',
'PySide6>=6.4.1'
]
)