375 lines
15 KiB
Python
375 lines
15 KiB
Python
import os
|
|
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 .commons.dialogs import QuickDialog
|
|
from .commons.dblogin import safe_reconnect
|
|
from .proxy import FastModel
|
|
from .constants import SCREENS
|
|
from .dialogs import (
|
|
Help, ControlPanel, SearchSale, SearchParty, SearchProduct, Position,
|
|
Comment, DialogPayment, DialogVoucher, DialogPrintInvoice, ProductEdit,
|
|
DialogGlobalDiscount, DialogPaymentTerm, DialogStock, DialogOrder,
|
|
DialogForceAssign, DialogTaxes, DialogCancelInvoice, DialogAgent,
|
|
DialogConsumer, DialogManageTables, DialogMoneyCount, CombineProduct,
|
|
DialogAuthDiscounts, DeliveryPartySelected, DialogTableDeliveryParty,
|
|
DialogHistoricSales, DialogSaleForm, DialogSource, DialogReports,
|
|
DialogDeliveryParty, TipAmount, DeliveryAmount, DialogSalesmanCode,
|
|
DialogFixedDiscounts, DialogFixedDiscountsManual, DialogComboProduct, DialogSplitSale, DialogExpenses,
|
|
DialogInfoProduct
|
|
)
|
|
from .constants import DIALOG_REPLY_YES
|
|
from .version import __version__
|
|
|
|
|
|
__all__ = ['FrontWindow', 'ClearUi']
|
|
parent = Path(__file__).parent
|
|
|
|
file_base_css = os.path.join(str(parent), 'css', 'base.css')
|
|
_DEFAULT_TIMEOUT = 60000 # on ms (100 minutes)
|
|
|
|
|
|
class FrontWindow(QMainWindow):
|
|
|
|
def __init__(self, connection, params, title=None, show_mode=None):
|
|
super(FrontWindow, self).__init__()
|
|
if not title:
|
|
title = 'APLICACION'
|
|
|
|
self._state = None
|
|
self._keyStates = {}
|
|
self.window().setWindowTitle(title)
|
|
self.setObjectName('WinMain')
|
|
self.conn = connection
|
|
self.version = __version__
|
|
self._context = connection.context
|
|
self.set_params(params)
|
|
self.logger = logging.getLogger('app_logger')
|
|
|
|
"""
|
|
We need get the size of screen (display)
|
|
--------------- -------------------
|
|
name width (px)
|
|
--------------- -------------------
|
|
small screen =< 1024
|
|
medium screen > 1024 and =< 1366
|
|
large screen > 1366
|
|
"""
|
|
|
|
screen = QDesktopWidget().screenGeometry()
|
|
self.setGeometry(0, 0, screen.width(), screen.height())
|
|
self.screen_width = screen.width()
|
|
self.screen_height = screen.height()
|
|
self.screen_size = 'large'
|
|
if self.screen_width <= 1024:
|
|
self.screen_size = 'small'
|
|
elif self.screen_width <= 1366:
|
|
self.screen_size = 'medium'
|
|
print('self.screen_size > ', self.screen_size)
|
|
self.timeout = _DEFAULT_TIMEOUT
|
|
|
|
self.setFocus()
|
|
self.global_timer = 0
|
|
_theme = params['theme'] if params.get('theme') else None
|
|
self.profile_printer = params['profile_printer'] if params.get('profile_printer') else 'TM-P80'
|
|
self.set_style(SCREENS[self.screen_size], _theme)
|
|
self.label_color = 'gray'
|
|
self.label_color_2 = ''
|
|
if _theme == 'dark':
|
|
self.label_color = 'light'
|
|
self.label_color_2 = 'orange'
|
|
self.window().showMaximized()
|
|
|
|
def filter_cache(self, data, filter, target):
|
|
res = []
|
|
for d in data:
|
|
for t in target:
|
|
if t in d[filter]:
|
|
res.append(d)
|
|
return res
|
|
|
|
def get_geometry(self):
|
|
screen = QDesktopWidget().screenGeometry()
|
|
return screen.width(), screen.height()
|
|
|
|
def set_style(self, file_css, theme_css=None):
|
|
styles = []
|
|
if theme_css:
|
|
theme_css = os.path.join(str(parent), 'css', theme_css + '.css')
|
|
for style in [theme_css or file_base_css, file_css]:
|
|
with open(style, 'r') as infile:
|
|
styles.append(infile.read())
|
|
self.setStyleSheet(''.join(styles))
|
|
|
|
def set_timeout(self):
|
|
if self.active_timeout != 'True':
|
|
return
|
|
|
|
self.timeout = eval(self.timeout)
|
|
if not self.timeout:
|
|
self.timeout = _DEFAULT_TIMEOUT
|
|
timer = QTimer(self)
|
|
timer.timeout.connect(self.count_time)
|
|
timer.start(1000)
|
|
|
|
def count_time(self):
|
|
self.global_timer += 1
|
|
if self.global_timer > self.timeout:
|
|
self.global_timer = 0
|
|
safe_reconnect()
|
|
|
|
def close(self):
|
|
dialog = self.dialog('confirm_exit', response=True)
|
|
response = dialog.exec_()
|
|
if response == DIALOG_REPLY_YES:
|
|
self.check_empty_sale()
|
|
if self.active_weighing and self.reader_thread:
|
|
self.reader_thread.onClose()
|
|
super(FrontWindow, self).close()
|
|
|
|
def dialog(self, name, response=False, widgets=None, extra_message=None):
|
|
kind, msg = self.stack_msg[name]
|
|
if extra_message:
|
|
print(extra_message)
|
|
msg += '\n' + extra_message
|
|
# if args:
|
|
# msg = msg % args
|
|
return QuickDialog(parent=self, kind=kind, string=msg, widgets=widgets)
|
|
|
|
def set_params(self, values):
|
|
for k, v in values.items():
|
|
if v in ('False', 'True'):
|
|
v = eval(v)
|
|
setattr(self, k, v)
|
|
|
|
def action_block(self):
|
|
safe_reconnect(self)
|
|
|
|
def dialog_password_accept(self):
|
|
self.connection()
|
|
|
|
def dialog_password_rejected(self):
|
|
self.connection()
|
|
|
|
def keyReleaseEvent(self, event):
|
|
self._keyStates[event.key()] = False
|
|
|
|
def create_dialogs(self):
|
|
self.dialog_control_panel = ControlPanel(self)
|
|
self.dialog_money_count = DialogMoneyCount(self)
|
|
self.dialog_search_sales = SearchSale(self)
|
|
self.dialog_search_parties = SearchParty(self)
|
|
self.dialog_search_products = SearchProduct(self)
|
|
self.dialog_position = Position(self)
|
|
self.dialog_tip_amount = TipAmount(self)
|
|
self.dialog_delivery_amount = DeliveryAmount(self)
|
|
self.dialog_comment = Comment(self)
|
|
self.dialog_payment = DialogPayment(self)
|
|
self.dialog_voucher = DialogVoucher(self)
|
|
self.dialog_print_invoice = DialogPrintInvoice(self)
|
|
self.dialog_global_discount = DialogGlobalDiscount(self)
|
|
self.dialog_auth_discount = DialogAuthDiscounts(self)
|
|
self.dialog_fixed_discount = DialogFixedDiscounts(self)
|
|
self.dialog_fixed_discount_manual = DialogFixedDiscountsManual(self)
|
|
self.dialog_payment_term = DialogPaymentTerm(self)
|
|
self.dialog_search_sales.activate_counter()
|
|
self.dialog_product_stock = DialogStock(self.dialog_search_products)
|
|
self.dialog_order = DialogOrder(self)
|
|
self.dialog_force_assign = DialogForceAssign(self)
|
|
self.field_password_force_assign_ask.setEchoMode(QLineEdit.Password)
|
|
self.dialog_tax = DialogTaxes(self)
|
|
self.dialog_cancel_invoice = DialogCancelInvoice(self)
|
|
self.dialog_product_edit = ProductEdit(self)
|
|
self.dialog_table_delivery_party = DialogTableDeliveryParty(self)
|
|
self.dialog_delivery_party_selected = DeliveryPartySelected(self)
|
|
self.dialog_delivery_party = DialogDeliveryParty(self)
|
|
self.dialog_salesman_code = DialogSalesmanCode(self)
|
|
self.dialog_reports = DialogReports(self)
|
|
self.dialog_source = DialogSource(self)
|
|
self.dialog_split_sale = DialogSplitSale(self)
|
|
self.dialog_expenses = DialogExpenses(self)
|
|
self.dialog_info_product = DialogInfoProduct(self)
|
|
if self._commission_activated:
|
|
self.dialog_agent = DialogAgent(self)
|
|
if self.enviroment == 'restaurant' and self._sale_pos_restaurant:
|
|
self.dialog_combine_product = CombineProduct(self)
|
|
self.dialog_combo_product = DialogComboProduct(self)
|
|
self.dialog_historic_sales = DialogHistoricSales(self)
|
|
self.dialog_sale_form = DialogSaleForm(self)
|
|
self.dialog_consumer = DialogConsumer(self)
|
|
self.dialog_manage_tables = DialogManageTables(self)
|
|
|
|
def action_help(self):
|
|
Help(self).show()
|
|
|
|
def resize_window_tablet_dev(self):
|
|
self.resize(690, self.get_geometry()[1])
|
|
|
|
def load_modules(self):
|
|
self._sale_pos_restaurant = None
|
|
self.Module = FastModel('ir.module', self.ctx)
|
|
self.Config = FastModel('sale.configuration', self.ctx)
|
|
self._config, = self.Config.find([('id', '=', 1)])
|
|
self.discount_method = self._config.get('discount_pos_method')
|
|
self.allow_discount_handle = self._config.get('allow_discount_handle', None)
|
|
self.sale_automatic = False
|
|
if self.enviroment == 'retail' and self._config.get('new_sale_automatic'):
|
|
self.sale_automatic = True
|
|
self._commission_activated = self.Module.find([
|
|
('name', '=', 'commission'),
|
|
('state', '=', 'activated'),
|
|
])
|
|
# self._source = self.Module.find([
|
|
# ('name', '=', 'sale_source'),
|
|
# ('state', '=', 'activated'),
|
|
# ])
|
|
self._credit_limit_activated = self.Module.find([
|
|
('name', '=', 'account_credit_limit'),
|
|
('state', '=', 'activated'),
|
|
])
|
|
|
|
_product = {
|
|
'name': 'product.product',
|
|
'fields': [
|
|
'template.name', 'code', 'barcode', 'write_date',
|
|
'description', 'template.sale_price_w_tax',
|
|
'template.account_category'
|
|
]
|
|
}
|
|
self.cache_local = self._config.get('cache_products_local')
|
|
|
|
if self._config['show_location_pos']:
|
|
_product['fields'].append('location_')
|
|
|
|
if self._config['show_stock_pos'] in ('value', 'icon'):
|
|
if self._config['show_stock_pos'] == 'value':
|
|
_product['fields'].append('quantity')
|
|
if self._config['show_brand']:
|
|
_product['fields'].append('brand.name')
|
|
|
|
if self._config['encoded_sale_price']:
|
|
_product['fields'].extend(['image', 'image_icon', 'encoded_sale_price'])
|
|
|
|
if self.enviroment == 'restaurant':
|
|
self._sale_pos_restaurant = self.Module.find([
|
|
('name', '=', 'sale_pos_frontend_rest'),
|
|
('state', '=', 'activated'),
|
|
])
|
|
if self._sale_pos_restaurant:
|
|
self.PartyConsumer = FastModel('party.consumer', self.ctx)
|
|
if self._config['delivery_product']:
|
|
self._delivery_product = 0
|
|
|
|
self.User = FastModel('res.user', self.ctx)
|
|
self._user, = self.User.find([('login', '=', self.user)])
|
|
self.Company = FastModel('company.company', self.ctx)
|
|
self._company, = self.Company.find([('id', '=', 1)])
|
|
self.logo = self._company['logo']
|
|
|
|
if not self._user['sale_device']:
|
|
return 'user_not_permissions_device'
|
|
|
|
self.ctx['user'] = self._user['id']
|
|
|
|
self.Sale = FastModel('sale.sale', self.ctx)
|
|
self.SaleLine = FastModel('sale.line', self.ctx)
|
|
self.Product = FastModel('product.product', self.ctx)
|
|
self.Journal = FastModel('account.statement.journal', self.ctx)
|
|
self.Statement = FastModel('account.statement', self.ctx)
|
|
self.Expenses = FastModel('sale_pos.expenses_daily', self.ctx)
|
|
self.Employee = FastModel('company.employee', self.ctx)
|
|
self.Shop = FastModel('sale.delivery_party', self.ctx)
|
|
self.SaleDiscont = FastModel('sale.discount', self.ctx)
|
|
self.Device = FastModel('sale.device', self.ctx)
|
|
self.Category = FastModel('product.category', self.ctx)
|
|
self.PaymentTerm = FastModel('account.invoice.payment_term', self.ctx)
|
|
self.Party = FastModel('party.party', self.ctx)
|
|
self.DeliveryParty = FastModel('sale.delivery_party', self.ctx)
|
|
self.Taxes = FastModel('account.tax', self.ctx)
|
|
self.Discount = FastModel('sale.discount', self.ctx, fields=[
|
|
'name', 'active', 'discount', 'type_discount'
|
|
])
|
|
self.ActionReport = FastModel('ir.action.report', self.ctx)
|
|
if self._commission_activated:
|
|
self.Agent = FastModel('commission.agent', self.ctx)
|
|
self.Comission = FastModel('commission', self.ctx)
|
|
if self._sale_pos_restaurant:
|
|
self.RestTables = FastModel('sale.shop.table', self.ctx)
|
|
self.Consumer = FastModel('party.consumer', self.ctx)
|
|
|
|
self.device, = self.Device.find([
|
|
('id', '=', self._user['sale_device']['id']),
|
|
])
|
|
|
|
self.shop = self.device['shop']
|
|
self.shop_taxes = self.shop['taxes']
|
|
self.company = self.shop['company']
|
|
self._journals = self.device['journals']
|
|
self.salesman_ids = [s['id'] for s in self.shop.get('salesmans', [])]
|
|
|
|
dom_salesman = [
|
|
('company', '=', self.company['id']),
|
|
]
|
|
if self.salesman_ids:
|
|
dom_salesman.append(('id', 'in', self.salesman_ids))
|
|
|
|
self.discounts = self.Discount.find([
|
|
('type_discount', '=', 'percentage')
|
|
])
|
|
self.discounts_fixed = self.Discount.find([])
|
|
self.delivery_man_table = self.shop.get('delivery_man', [])
|
|
if self.delivery_man_table:
|
|
self.delivery_man = [d for d in self.delivery_man_table if d['active']]
|
|
self._payment_terms = self.PaymentTerm.find([
|
|
('active', '=', True)
|
|
], order=[('name', 'ASC')])
|
|
self.type_pos_user = self._context.get('type_pos_user')
|
|
|
|
if not self.type_pos_user:
|
|
return 'user_without_permission'
|
|
self.user_can_delete = self.type_pos_user in ('frontend_admin', 'cashier')
|
|
|
|
self.product_categories = self.device['shop']['product_categories']
|
|
self.salesman_required = self.device['shop']['salesman_pos_required']
|
|
|
|
self.default_party = self.shop['party']
|
|
if not self.default_party:
|
|
return 'missing_party_configuration'
|
|
|
|
self.default_journal = self.device['journal']
|
|
if not self.default_journal:
|
|
return 'missing_journal_device'
|
|
|
|
self.default_payment_term = self.shop['payment_term']
|
|
self._password_admin = self._config.get('password_admin_pos')
|
|
self._password_force_assign = self._config.get('password_force_assign')
|
|
|
|
self._action_report, = self.ActionReport.find([
|
|
('report_name', '=', 'account.invoice'),
|
|
])
|
|
if self._config['show_stock_pos'] in ('value', 'icon'):
|
|
self.stock_context = {
|
|
'stock_date_end': date.today(),
|
|
'locations': [self.shop['warehouse']['id']],
|
|
}
|
|
# if self._source:
|
|
self.Source = FastModel('sale.source', self.ctx)
|
|
self.Pricelist = FastModel('product.price_list', self.ctx)
|
|
return True
|
|
|
|
|
|
class ClearUi(QThread):
|
|
sigActionClear = pyqtSignal()
|
|
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()
|