#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import sys
import os
import logging
import base64
from decimal import Decimal
from datetime import datetime, timedelta, date
from collections import OrderedDict
from PyQt5.QtCore import Qt, QDate
from .tools import get_icon, to_float, to_numeric
from PyQt5.QtWidgets import (
    QLabel, QHBoxLayout, QVBoxLayout, QWidget, QLineEdit, QGridLayout,
    QSizePolicy, QFrame
)

from .frontwindow import FrontWindow
from app.commons.action import Action
from app.commons.forms import GridForm, ComboBox, FieldNumeric
from app.commons.messages import MessageBar

from app.commons.table import TableView
from app.commons.model import TableModel, TableModelEdit
from app.commons.menu_buttons import MenuDash
from .localdb import LocalDB
from .reporting import Receipt
from .buttonpad import ButtonsStacked, ButtonsFunction, StartButtons
from .states import STATES, RE_SIGN
from .commons.custom_button import CustomButton
from .threads import DoInvoice
from .store import StoreView
from .constants import (
    PATH_PRINTERS, DELTA_LOCALE, STRETCH, alignRight, alignLeft, alignCenter,
    alignHCenter, DIALOG_REPLY_NO, ZERO, RATE_CREDIT_LIMIT,
    CONVERSION_DIGITS, MONEY, MINIMUM_DATE,
)
from .dialogs import DialogDeliveryParty

invoice_type = [('P', ('POS'))]


class MainWindow(FrontWindow):

    def __init__(self, connection, params):
        title = "PRESIK  |  SMART POS"
        global CONNECTION
        CONNECTION = connection
        super(MainWindow, self).__init__(connection, params, title)
        self.payment_ctx = {}
        self.set_keys()
        self.stock_context = None
        self._sale = {}
        self.ctx = self._context
        self.ctx['params'] = params
        response = self.load_modules()
        if response is not True:
            d = self.dialog(response)
            d.exec_()
            super(MainWindow, self).close()
            return
        self.setup_sale_line()
        self.setup_delivery_party()
        self.setup_sale_consumer()
        self.setup_payment()
        self.set_domains()
        self.setup_money_count()
        self.create_gui()
        self.message_bar.load_stack(self.stack_msg)
        self.journal = {}
        if not hasattr(self, 'auto_print_commission'):
            self.auto_print_commission = False

        self.active_usb_printers = []

        if os.name == 'posix' and os.path.exists(PATH_PRINTERS):
            self.set_printers_usb(PATH_PRINTERS)

        self.set_printing_context()
        self.create_statusbar()

        self.reader_thread = None
        self._current_line_id = None
        self._amount_text = ''
        self._sign = None
        self.create_dialogs()
        if self.sale_automatic:
            self.create_new_sale()
        if not hasattr(self, 'active_weighing'):
            self.active_weighing = False
        elif self.active_weighing is True:
            from .electronic_scale import ScaleReader
            self.reader_thread = ScaleReader()
            self.reader_thread.sigSetWeight.connect(self.set_weight_readed)

        self.do_invoice = DoInvoice(self, self._context)
        self.do_invoice.sigDoInvoice.connect(self.__do_invoice_thread)
        self.set_state('disabled')
        sale_fields = [
            'number', 'party', 'sale_date', 'comment', 'position',
            'description', 'invoice_number', 'tip_amount', 'delivery_amount',
            'salesman', 'state', 'kind', 'channel', 'reference',
            'invoice_type', 'consumer', 'delivery_party', 'table_assigned'
        ]
        self.store = StoreView(self, sale_fields)
        if self.cache_local:
            self.set_cache_company()
            self.set_cache_products()
        for j in self._journals:
            if j['id'] == self.default_journal['id']:
                self.default_journal = j

    def set_domains(self):
        self.domain_search_product = [
            ('code', '!=', None),
            ('active', '=', True),
            ('template.salable', '=', True),
            ('template.account_category', '!=', None),
        ]

        if self.shop['product_categories']:
            self.domain_search_product.append(
                ('account_category', 'in', self.shop['product_categories'])
            )

    def set_cache_company(self):
        self.local_db = LocalDB()
        self.local_db.create_table_config()
        self._local_config = self.local_db.get_config()
        if not self._local_config:
            company_id = self.device['shop']['company']['id']
            self._local_config = self.local_db.set_config([company_id])

    def set_cache_products(self):
        self.local_db.create_table_product()
        local_products = self.local_db.get_local_products()

        config = self.local_db.get_config()
        _sync_date = config[1]
        products = self.Product.sync_get_products({
            'write_date': _sync_date,
            'shop_id': self.ctx['shop']
        })
        self.local_db.update_products(products, local_products)
        now = datetime.now()
        self.local_db.set_config_sync(str(now))

    def set_printers_usb(self, PATH_PRINTERS):
        for usb_dev in os.listdir(PATH_PRINTERS):
            if 'lp' not in usb_dev:
                continue
            path_device = os.path.join(PATH_PRINTERS, usb_dev)
            self.active_usb_printers.append(['usb', path_device])

    def get_current_sale(self):
        if hasattr(self, '_sale') and self._sale['id']:
            sales = self.Sale.find([
                ('id', '=', self._sale['id'])
            ])
            if not sales:
                return
            return sales[0]

    def check_empty_sale(self):
        sale = self.get_current_sale()
        if sale and self.model_sale_lines.rowCount() == 0 \
                and sale['state'] == 'draft' and not sale['number']:
            self.delete_current_sale()

    def delete_current_sale(self):
        if self._sale['id']:
            args = {'id': self._sale['id']}
            self.Sale.cancel_sale(args)

    def set_printing_context(self):
        # Printing invoice context
        if self.printer_sale_name:
            if ">" in self.printer_sale_name:
                self.printer_sale_name = str(str("\\") + self.printer_sale_name.replace('>', str('\\')))

        ctx_printing = self.Sale.get_printing_context({
            'device_id': self.device['id'],
            'user': self.user,
        })
        ctx_printing['row_characters'] = self.row_characters
        ctx_printing['delta_locale'] = DELTA_LOCALE

        locale_logo = ''
        if self.logo:
            locale_logo = os.path.join(os.path.abspath(
                os.path.dirname(__file__)), 'logo.png')
            f = open(locale_logo, "wb")
            f.write(base64.decodestring(self.logo.encode()))
            f.close()

        self.receipt_sale = Receipt(ctx_printing, logo=locale_logo)

        # Printing order context
        if self.print_order:
            self.receipt_order = Receipt(ctx_printing)
        self.set_default_printer()

    def set_default_printer(self, printer=None):
        if self.active_usb_printers:
            self.printer_sale_name = self.active_usb_printers[0]
        if not printer and self.printer_sale_name:
            printer = {
                'interface': self.printer_sale_name[0],
                'device': self.printer_sale_name[1],
                'profile': self.profile_printer,
            }
        if printer:
            self.receipt_sale.set_printer(printer)

    def button_new_sale_pressed(self):
        self.create_new_sale()

    def button_send_to_pay_pressed(self):
        # Return sale to draft state
        if not self._check_quantity():
            return

        args = {'sale_id': self._sale['id']}
        self.Sale.to_quote(args)
        if self.model_sale_lines.rowCount() > 0:
            if self.check_salesman():
                # self.state_disabled()
                pass
        try:
            self.Sale.generate_shipment({
                'sale_id': self._sale['id'],
            })
            self.dialog('order_dispatched')
        except:
            self.dialog('error_order_dispatched')

    def button_to_draft_pressed(self):
        # Return sale to draft state
        if hasattr(self, '_sale'):
            self.Sale.to_draft(self._sale['id'])
            # self.state_disabled()

    def create_gui(self):
        panels = QHBoxLayout()
        panels.setSpacing(0)
        panels.setContentsMargins(0, 0, 0,  0)

        panel_left = QWidget()
        panel_left.setObjectName('panel_left')
        vbox_left = QVBoxLayout()
        vbox_left.setSpacing(0)
        vbox_left.setContentsMargins(0, 0, 0, 0)

        if self.screen_size == 'small':
            max_size = 620
        else:
            max_size = 1300
        panel_left.setMaximumWidth(max_size)
        panel_left.setLayout(vbox_left)
        panel_left.setContentsMargins(0, 0, 0, 0)

        self.panel_right = QVBoxLayout()
        self.panel_right.setSpacing(4)
        self.panel_right.setObjectName('panel_right')
        self.panel_right.setContentsMargins(3, 3, 3, 3)

        left_head = QHBoxLayout()
        left_head.setSpacing(4)
        left_invoice = QHBoxLayout()
        left_invoice.setSpacing(4)

        board = QVBoxLayout()
        board.setSpacing(0)

        # CREATE START FRONT
        self.start_front = QWidget()
        self.start_front.setObjectName('start_front')
        start_front = StartButtons(self)
        self.start_front.setLayout(start_front)

        # CREATE ORDER FRONT
        self.order_front = QWidget()
        self.order_front.setObjectName('order_front')
        vbox_order_front = QVBoxLayout()
        vbox_order_front.setSpacing(4)
        vbox_order_front.addLayout(left_head)
        vbox_order_front.addLayout(left_invoice)
        self.order_front.setLayout(vbox_order_front)

        # CONFIGURE BOARD
        board.addWidget(self.start_front, 0)
        board.addWidget(self.order_front, 0)

        # LEFT HEAD COMPONENTS
        start_front = CustomButton(
            self,
            id='button_start',
            size=self.screen_size,
            icon=get_icon('start_front'),
            title=self.tr('START'),
            method='see_start_front',
            name_style='mini_button',
        )
        self.message_bar = MessageBar()
        self.field_amount = FieldNumeric(self, 'amount', {})
        self.field_amount.setObjectName('field_amount')
        self.field_sign = QLabel('   ')
        self.field_sign.setObjectName('field_sign')

        left_head.addWidget(start_front, 0)
        left_head.addLayout(self.message_bar, 1)
        left_head.addWidget(self.field_sign, 0)
        left_head.addWidget(self.field_amount, 1)

        # LEFT INVOICE COMPONENTS
        self.label_input = QLabel()
        # self.label_input.setFocus()
        self.label_input.setObjectName('label_input')
        size_input = 100
        if self.screen_size == 'large':
            size_input = 300
        self.label_input.setMaximumWidth(size_input)

        if self.shop.get('manual_authorization'):
            invoice_type.append(('M', 'MANUAL'))
        if self.shop.get('electronic_authorization'):
            invoice_type.append(('1', ('VENTA ELECTRONICA')))

        self.field_invoice_type = ComboBox(self, 'invoice_type', {
            'values': invoice_type,
            'on_change': 'action_invoice_type_selection_changed'
        })

        left_invoice.addWidget(self.label_input, 1)
        left_invoice.addWidget(self.field_invoice_type, 0)

        self.field_invoice = QLineEdit('')
        self.field_invoice.setReadOnly(True)
        self.field_invoice.setObjectName('field_invoice')
        self.field_invoice.setPlaceholderText(self.tr('No Invoice'))
        left_invoice.addWidget(self.field_invoice, 1)

        self.field_state = QLineEdit('STATE')
        self.field_state.setReadOnly(True)
        self.field_state.setObjectName('field_state')
        left_invoice.addWidget(self.field_state)

        # LEFT TABLE COMPONENTS
        values = self.get_menu_control_panel()
        self.menu_control_panel = ButtonsFunction(self, values=values)
        button_functions = ButtonsFunction(self)

        info_fields = [
            ('party', {
                'name': self.tr('CUSTOMER'),
                'readonly': True,
                'placeholder': False,
                'size': self.screen_size,
                'color': self.label_color
            }),
            ('sale_date', {
                'name': self.tr('DATE'),
                'readonly': True,
                'placeholder': False,
                'size': self.screen_size,
                'color': self.label_color
            }),
            ('salesman', {
                'name': self.tr('SALESMAN'),
                'readonly': True,
                'placeholder': False,
                'size': self.screen_size,
                'color': self.label_color
            }),
            ('number', {
                'name': self.tr('No ORDER'),
                'placeholder': False,
                'readonly': True,
                'size': self.screen_size,
                'color': self.label_color
            }),
            ('payment_term', {
                'name': self.tr('PAYMENT TERM'),
                'readonly': True,
                'invisible': False,
                'placeholder': False,
                'size': self.screen_size,
                'color': self.label_color
            }),
            ('delivery_party', {
                'name': self.tr('DELIVERY MEN'),
                'placeholder': False,
                'size': self.screen_size,
                'color': self.label_color
            })
        ]

        if self._web_channel:
            self.channels = self.Channel.find([])

            info_fields.append(
                ('channel', {
                    'name': self.tr('CHANNEL'),
                    'readonly': True,
                    'placeholder': False,
                    'size': self.screen_size,
                    'color': self.label_color
                }))

        if self._config['show_position_pos']:
            info_fields.append(('position', {
                'name': self.tr('POSITION'),
                'readonly': True,
                'placeholder': False,
                'size': self.screen_size,
                'color': self.label_color
            }))
        if self._commission_activated and self._config['show_agent_pos']:
            info_fields.append(('agent', {
                'name': self.tr('AGENT'),
                'placeholder': False,
                'readonly': True,
                'size': self.screen_size,
                'color': self.label_color
            }))

        _cols = 2
        self.field_delivery_charge = None
        if self._config['show_delivery_charge']:
            info_fields.append(
                ('delivery_charge', {
                    'name': self.tr('DELIVERY CHARGE'),
                    'placeholder': False,
                    'type': 'selection',
                    'on_change': 'action_delivery_charge_selection_changed',
                    'values': [
                        ('', ''),
                        ('customer', self.tr('CUSTOMER')),
                        ('company', self.tr('COMPANY')),
                    ],
                    'size': self.screen_size,
                    'color': self.label_color
                }))

        self.field_table_assigned = None
        if self._sale_pos_restaurant:
            info_fields.append(
                ('consumer', {
                    'name': self.tr('CONSUMER'),
                    'placeholder': False,
                    'size': self.screen_size,
                    'color': self.label_color
                }))
            KIND = [
                ('', ''),
                ('take_away', self.tr('TAKE AWAY')),
                ('delivery', self.tr('DELIVERY')),
                ('to_table', self.tr('TO TABLE'))
            ]
            info_fields.append(
                ('kind', {
                    'name': self.tr('KIND'),
                    'placeholder': False,
                    'type': 'selection',
                    'on_change': 'action_kind_selection_changed',
                    'values': KIND,
                    'size': self.screen_size,
                    'color': self.label_color
                }))

            PAYMENT_METHODS = [
                ('', ''),
                ('cash', self.tr('CASH')),
                ('terminal', self.tr('TERMINAL')),
            ]
            info_fields.append(
                ('payment_method', {
                    'name': self.tr('PAYMENT METHOD'),
                    'placeholder': False,
                    'type': 'selection',
                    'on_change': 'action_payment_method_selection_changed',
                    'values': PAYMENT_METHODS,
                    'size': self.screen_size,
                    'color': self.label_color
                }))

            info_fields.append(
                ('table_assigned', {
                    'name': self.tr('ASSIGNED TABLE'),
                    'placeholder': False,
                    'size': self.screen_size,
                    'color': self.label_color
                }))

        col_sizes_tlines = [field['width'] for field in self.fields_sale_line]
        self.table_sale_lines = TableView('model_sale_lines',
            self.model_sale_lines, col_sizes_tlines,
            method_selected_row=self.sale_line_selected
        )

        for i, f in enumerate(self.model_sale_lines._fields, 0):
            if f.get('invisible'):
                self.table_sale_lines.hideColumn(i)

        invisible = False
        if self.enviroment == 'restaurant':
            invisible = True
        _fields_amounts = [
            ('untaxed_amount', {
                'name': self.tr('SUBTOTAL'),
                'readonly': True,
                'type': 'money',
                'size': self.screen_size,
                'color': self.label_color,
                'invisible': invisible,
            }),
            ('taxes_amount', {
                'name': self.tr('TAXES'),
                'readonly': True,
                'type': 'money',
                'size': self.screen_size,
                'color': self.label_color,
                'invisible': invisible,
            }),
            ('discount', {
                'name': self.tr('DISCOUNT'),
                'readonly': True,
                'type': 'money',
                'size': self.screen_size,
                'color': self.label_color,
                'invisible': invisible,
            }),
            ('tip_amount', {
                'name': self.tr('VR. PROPINA'),
                'type': 'money',
                'size': self.screen_size,
                'color': self.label_color,
            }),
            ('delivery_amount', {
                'name': self.tr('VR. DOMIC'),
                'type': 'money',
                'size': self.screen_size,
                'color': self.label_color,
            }),
            ('total_amount', {
                'name': self.tr('TOTAL'),
                'readonly': True,
                'type': 'money',
                'size': self.screen_size,
                'color': 'black',
                'font_size': 'big',
            }),
            ('net_amount', {
                'name': self.tr('NETO TOTAL'),
                'readonly': True,
                'type': 'money',
                'size': self.screen_size,
                'color': 'black',
                'font_size': 'big',
            }),
            ('paid_amount', {
                'name': self.tr('PAID'),
                'readonly': True,
                'type': 'money',
                'size': self.screen_size,
                'color': self.label_color,
            }),
            ('residual_amount', {
                'name': self.tr('PENDING'),
                'readonly': True,
                'type': 'money',
                'size': self.screen_size,
                'color': self.label_color_2 or 'blue'
            }),
            ('change', {
                'name': self.tr('CHANGE'),
                'readonly': True,
                'type': 'money',
                'size': self.screen_size,
                'color': self.label_color_2 or 'orange'
            })
        ]
        fields_amounts = OrderedDict(_fields_amounts)
        self.grid_amounts = GridForm(self, fields_amounts, col=1)
        self.buttons_stacked = ButtonsStacked(self)

        self.table_payment = TableView('table_payment',
            self.table_payment_lines, [250, STRETCH])

        self.grid_info = GridForm(self, OrderedDict(info_fields), col=_cols)

        vbox_order_front.addWidget(self.table_sale_lines, 1)
        vbox_left.addLayout(board, 0)

        if self.enviroment == 'restaurant':
            self.panel_right_box = QWidget()
            values = self.get_product_by_categories()
            self.menu_dash = MenuDash(self, values, 'on_selected_item')
            self.order_front.hide()
            vbox_order_front.addLayout(button_functions, 0)
            vbox_order_front.addLayout(self.grid_info, 0)
            self.panel_right.addWidget(self.menu_dash, 1)
            _panel_right_box = QVBoxLayout()
            _panel_right_box.addLayout(self.grid_amounts, 0)
            _panel_right_box.addLayout(self.buttons_stacked, 0)
            self.panel_right_box.setLayout(_panel_right_box)
            self.panel_right.addWidget(self.panel_right_box)
        else:
            vbox_left.addLayout(self.grid_info, 1)
            self.panel_right.addLayout(self.grid_amounts, 1)
            self.panel_right.addLayout(button_functions, 1)
            self.panel_right.addLayout(self.buttons_stacked, 0)
            self.panel_right.addWidget(self.table_payment)

        panels.addWidget(panel_left, 1)
        panels.addLayout(self.panel_right, 0)
        widget = QWidget()
        widget.setLayout(panels)
        self.setCentralWidget(widget)

    def show_right_panel(self, bool):
        if bool:
            self.panel_right_box.show()
        else:
            self.panel_right_box.hide()

    def button_plus_pressed(self):
        error = False
        if self._input_text == '' and self._amount_text == '0':
            return
        if self._state in ('paid', 'disabled'):
            return
        if self._sign in ('*', '-', '/'):
            if hasattr(self, '_sale_line') and self._sale_line \
                and self._sale_line.get('type') and self._state == 'add' \
                and self.model_sale_lines.rowCount() > 0:
                if self._sign == '*':
                    self._process_quantity(self._amount_text)
                else:
                    error = not(self._process_price(self._amount_text))
        elif self._state in ['add', 'cancel', 'accept']:
            self.clear_right_panel()
            self.add_product(code=self._input_text)
        elif self._state == 'payment':
            is_paid = self._process_pay(self.field_amount.text())
            if not is_paid:
                self.set_state('payment')
                self.clear_input_text()
                self.clear_amount_text()
                return
            self.set_state('finished')
        else:
            logging.warning('Unknown command/text')
        self._clear_context(error)

    def see_start_front(self):
        self.change_view_to('start_front')

    def change_view_to(self, to_view):
        if to_view == 'start_front':
            self.order_front.hide()
            self.start_front.show()
        else:
            self.start_front.hide()
            self.order_front.show()

    def action_read_weight(self):
        self.reader_thread.start()

    def set_weight_readed(self):
        if not self.reader_thread or not self.reader_thread.best_weight:
            return

        if self.reader_thread.best_weight:
            self.amount_text_changed(self.reader_thread.best_weight)
            self._process_quantity(self._amount_text)
            self._clear_context(False)
        self.reader_thread.fZERO()

    def _clear_context(self, error=False):
        self.clear_input_text()
        self.clear_amount_text()
        self.clear_sign()

        if self.state == 'disabled':
            self.message_bar.set('not_sale')
        elif self._state not in ('warning', 'cash', 'payment') and not error:
            self.message_bar.set('system_ready')
        else:
            self.set_state('add')

    def _process_quantity(self, text):
        eval_value = text.replace(',', '.')
        rec = {}
        try:
            quantity = Decimal(eval_value)
            product_id = self.product_id
            if product_id and self.stock_context:
                _product, = self.Product.find([
                    ('id', '=', product_id)],
                    ctx=self.stock_context
                )
                if _product and 'quantity' in _product:
                    if not self._check_stock_quantity(_product, quantity):
                        return False
            if self._current_line_id:
                self._sale_line['quantity'] = float(quantity)
                args = {
                    'id': self._sale_line['id'],
                    'quantity': quantity,
                }
                rec = self.SaleLine.faster_set_quantity(args)
        except:
            return self.message_bar.set('quantity_not_valid')

        self.message_bar.set('system_ready')
        self.model_sale_lines.update_record(rec)
        self.set_amounts()

    def _process_price(self, text):
        discount_valid = True
        eval_value = text.replace(',', '')
        value = float(eval_value)
        if self._sign == '-':
            if self.discount_method == 'percentage' and value > 90:
                discount_valid = False
            else:
                discount_valid = self.set_discount(eval_value)
        elif self._sign == '/':
            if value <= 0:
                return
            sale_line, = self.SaleLine.find([
                ('id', '=', self._current_line_id)
            ])
            price_w_tax = sale_line['product']['sale_price_w_tax']
            if price_w_tax <= Decimal(value):
                # Change unit price
                discount_valid = self.set_unit_price(value)
                self.set_discount(0)
            else:
                eval_value = (1 - (value / price_w_tax)) * 100
                if self.discount_method == 'fixed':
                    eval_value = price_w_tax - value
                discount_valid = self.set_discount(eval_value)
        if not discount_valid:
            self.message_bar.set('discount_not_valid')
            return False

        self.message_bar.set('system_ready')
        self.set_amounts()
        return True

    def _process_pay(self, text):
        if not self.validate_done_sale():
            return
        val = Decimal(text.replace(',', ''))

        # FIXME
        # if self._commission_activated:
        #     if self._journals[self.field_journal_id]['kind'] == 'payment':
        #         agent_id = None
        #         if self.field_agent_id:
        #             agent_id = self.field_agent_id
        #         else:
        #             agent_id = self.field_agent_ask.get_id()
        #
        #         if not agent_id:
        #             self.message_bar.set('missing_agent')
        #             return False

        cash_received = Decimal(val)
        self.set_amounts()
        # residual_amount = self._sale['residual_amount']
        residual_amount = self.store.get('residual_amount')
        if residual_amount <= 0:
            # The sale is paid
            self._done_sale()
            return True

        change = float(cash_received) - residual_amount

        if residual_amount >= cash_received:
            amount_to_add = cash_received
        else:
            amount_to_add = residual_amount

        all_money = float(cash_received) + self.store.get('paid_amount')
        res = self.add_payment(amount_to_add, all_money, change)
        if res.get('msg') == 'statement_closed':
            self.dialog('statement_closed')
            return False
        if change < ZERO:
            residual_amount = abs(change)
        else:
            residual_amount = ZERO
        self.store.set({'residual_amount': residual_amount})
        self.set_amount_received(all_money)

        if residual_amount <= 0:
            self._done_sale()
            return True

        for j in self._journals:
            if j['id'] == self.default_journal['id']:
                self.journal = j

        if res['msg'] == 'missing_money':
            self.message_bar.set('enter_payment', self.default_journal['name'])
            return False

        if change < ZERO:
            self.message_bar.set('enter_payment', self.default_journal['name'])

        residual_amount = res['residual_amount']
        self.store.set({
            'residual_amount': residual_amount,
            'change': change,
        })

        if residual_amount <= 0:
            self._done_sale()
            return True

    def validate_done_sale(self):
        if self.model_sale_lines.rowCount() == 0:
            self.dialog('sale_without_products')
            self.set_state('add')
            self.message_bar.set('system_ready')
            return
        return True

    def _get_total_amount(self):
        return self.model_sale_lines.get_sum('amount_w_tax')

    def set_discount_amount(self):
        res = 0
        if self.store.sale_id:
            res = self.Sale.get_discount_total({
                'sale_id': self.store.sale_id
            })
        self.store.set({'discount': res})

    def amount_text_changed(self, text=None):
        if text:
            self._amount_text += text
        self.field_amount.setText(self._amount_text)

    def input_text_changed(self, text=None):
        if text:
            self._input_text += text
        elif text == '':
            self._input_text = ''
        self.label_input.setText(self._input_text)

    def __do_invoice_thread(self):
        try:
            res = self.Sale.faster_post_invoice({
                'sale_id': self.sale_to_post_id
            })
        except:
            self.dialog('invoice_done_failed')
            return
        if not res['result']:
            self.dialog('send_electronic_failed')
            return
        if self.store.get('is_credit'):
            return

        self.Sale.reconcile_invoice({'sale_id': self.sale_to_post_id})

    def _done_sale(self, is_credit=False):
        self.store.set({'is_credit': is_credit})
        # We need create this temp variable called sale_to_post_id for this
        # thread, because self.store.sale_id is deleted inmediately,
        # so post invoice and reconcile it will fail if reference to sale_id
        # is missing or None
        self.sale_to_post_id = self.store.sale_id
        table_assigned = self.store.get('table_assigned')
        if table_assigned:
            self.RestTables.write(
                [table_assigned['id']], {
                    'state': 'available',
                    'sale': None,
                }
            )
        self.do_invoice.start()
        try:
            if self.print_receipt == 'automatic':
                _copies = self.device['shop']['invoice_copies']
                if not is_credit:
                    self.print_invoice(copies=_copies, open_box=True)
            if self.print_order and self.print_auto_order:
                self.action_print_order()
        except:
            logging.error(sys.exc_info()[0])

        # if not is_credit and self._commission_activated:
        #     agent_id = self.field_agent_ask.get_id()
        #     if self.auto_print_commission and agent_id:
        #         self.print_equivalent_invoice(self._sale['id'])

        self.change_view_to('start_front')
        if self.sale_automatic and self.type_pos_user not in ('cashier', 'order'):
            self.create_new_sale()

        # self.state_disabled()
        self.message_bar.set('system_ready')
        return True

    def print_invoice(self, sale_id=None, type_doc='invoice', open_box=False, copies=1):
        if not sale_id:
            sale_id = self.store.sale_id
        args = {
            'sale_id': sale_id,
            'type_doc': type_doc,
        }
        data = self.Sale.get_data(args)
        for i in range(copies):
            self.receipt_sale.print_sale(data, type_doc, open_box)

    def button_duplicate_sale(self):
        if self.sale_customer_selected:
            res = self.Sale.duplicate_sale({
                'sale_id': self.sale_customer_selected,
            })
            self.load_sale(res['sale_id'])
        self.dialog_search_consumer.close()
        self.dialog_table_sale_consumer.close()
        self.dialog_sale_consumer_selected.close()

    def button_create_delivery_party(self):
        self.clear_delivery_party()
        self.dialog_delivery_party_selected.show()

    def button_sale_consumer_history(self):
        if self._consumer:
            delta = str(datetime.now() - timedelta(180))
            dom = [
                ('create_date', '>=', delta),
                ('state', 'in', ['processing', 'done']),
                ('consumer', '=', self._consumer['id']),
            ]
            self.model_sale_consumer.reset()
            sales = self.Sale.find(dom, limit=10)
            for record in sales:
                self.model_sale_consumer.add_record(record)
            self.dialog_table_sale_consumer.exec_()

    def button_accept_pressed(self):
        if not self._check_quantity() or not self._sale.get('id'):
            return
        if not self._sale['id'] or not self.model_sale_lines.rowCount() > 0:
            return
        self.set_state('accept')

    def button_cash_pressed(self):
        if not self.check_salesman():
            return
        if not self.validate_payment_term():
            return
        sale_id = self._sale['id']
        res, msg = self.Sale.faster_process({'sale_id': sale_id})
        if msg:
            self.message_bar.set(msg)
            return

        self.set_amounts(res)
        self._sale['number'] = res['number']
        self.field_number.setText(self._sale['number'])

        self.field_invoice.setText(res['invoice_number'])
        self.field_amount.setText('')
        if self.type_pos_user == 'salesman':
            self.print_invoice(sale_id)
            res = self._print_order(sale_id, 'delivery')
            if self.sale_automatic:
                self.create_new_sale()
            return
        if self.type_pos_user != 'cashier':
            self.field_invoice_type.set_enabled(False)

        self.message_bar.set('enter_payment', self.default_journal['name'])
        self.set_state('payment')
        self.label_input.setFocus()
        self.table_sale_lines.setDisabled(True)
        if self.enviroment == 'restaurant':
            self.menu_dash.setDisabled(True)

    def action_reservations(self):
        logging.info('Buscando reservas.....')

    def action_tables(self):
        self.manage_tables.open_tables()
        self.dialog_manage_tables.exec_()

    def action_tip(self):
        if self._state in ['finished']:
            return
        value = self.field_tip_amount_ask.text()
        if not value and self._config['tip_rate']:
            total_amount = int(self._get_total_amount())
            value = int((self._config['tip_rate'] / 100) * total_amount)
            self.field_tip_amount_ask.setText(str(value))
        else:
            self.dialog_tip_amount.exec_()
            value = self.field_tip_amount_ask.text()
        value = int(value)
        res = self.store.update({'tip_amount': value})
        self.set_amounts(res)

    def action_delivery(self):
        if self._state in ['finished']:
            return
        self.dialog_delivery_amount.exec_()
        value = self.field_delivery_amount_ask.text()
        value = int(value)
        res = self.store.update({'delivery_amount': value})
        self.set_amounts(res)

    def action_salesman(self):
        if self._state in ['cash']:
            return
        self.dialog_salesman.exec_()

    def action_delivery_party(self):
        self.dialog_delivery_party.exec_()

    def action_delivery_party_panel(self):
        self.dialog_control_panel.close()
        self.dialog_table_delivery_party.exec_()

    def action_control_panel(self):
        self.dialog_control_panel.exec_()

    def clear_money_count_table(self):
        new_data = [[d[0], 0, 0] for d in self.model_money_count._data]
        self.model_money_count._data = new_data

    def dialog_money_count_accepted(self):
        return True

    def action_open_statement(self):
        if not self.dialog_money_count.exec_():
            return
        res = self.Sale.faster_open_statement({
            'device': self.device['id'],
            'total_money': Decimal(
                self.row_field_total_money.text().replace(',', '')
            ),
        })
        if res['result']:
            self.dialog('statement_created')
            self.row_field_total_money.setText('0')
        self.clear_money_count_table()

    def action_closed_statement(self):
        if not self.dialog_money_count.exec_():
            return
        res = self.Sale.faster_close_statement({
            'device': self.device['id'],
            'data': self.model_money_count._data,
        })
        if res['result']:
            self.dialog('statement_finish')
            self.row_field_total_money.setText('0')
        self.clear_money_count_table()

    def action_table_discount(self):
        self.dialog_global_discount_table.exec_()

    def action_tax(self):
        self.dialog_tax.exec_()

    def button_payment_pressed(self):
        if self._state not in ('cash', 'payment'):
            self.dialog('add_payment_sale_draft')
            return
        self.dialog_payment.exec_()

    def _check_credit_capacity(self, party):
        if party['credit_limit_amount']:
            if (party['credit_limit_amount'] * Decimal(RATE_CREDIT_LIMIT)) < (
                    party['credit_amount'] + self._get_total_amount()):
                self.dialog('credit_limit_capacity')
                return True

    def validate_payment_term(self):
        payment_term = self.store.get('payment_term')
        is_credit = payment_term.get('is_credit', None)
        if not is_credit:
            return True

        party, = self.Party.find([('id', '=', self.party_id)])
        if self._credit_limit_activated:
            if self.party_id == self.default_party['id']:
                self.dialog('customer_not_credit')
                return False
            elif not party['credit_limit_amount']:
                self.dialog('customer_not_credit')
                return False

        self._credit_amount = self.Sale.get_credit_amount_party({'party_id': self.party_id})
        self._credit_limit_amount = party['credit_limit_amount']

        if is_credit and self._credit_limit_amount and \
            self._credit_limit_amount < (self._credit_amount + self._get_total_amount()):
            self.dialog('credit_limit_exceed')
            return False
        return True

    def action_payment_term_selection_changed(self):
        is_credit = self._payment_terms[str(self.field_payment_term_id)]['is_credit']
        self.Sale.write([self._sale['id']], {'payment_term': self.field_payment_term_id})
        self.field_payment_term.setText(self._payment_terms[str(self.field_payment_term_id)]['name'])
        if is_credit and self.type_pos_user != 'salesman':
            if self.validate_credit_limit():
                self._done_sale(is_credit=True)

    def validate_credit_limit(self):
        if self._credit_limit_amount and self._credit_limit_amount < (self._credit_amount + self._get_total_amount()):
            self.dialog('credit_limit_exceed')
            return False
        else:
            return True

    def action_delivery_charge_selection_changed(self, index):
        val = self.field_delivery_charge.get_id()
        if val:
            self.Sale.write([self._sale['id']], {'delivery_charge': val})

    def action_kind_selection_changed(self, index):
        val = self.field_kind.get_id()
        self.store.update({'kind': val})

    def action_payment_method_selection_changed(self, index):
        val = self.field_payment_method.get_id()
        self.store.update({'payment_method': val})

    def action_invoice_type_selection_changed(self, index):
        val = self.field_invoice_type.get_id()
        if val and self._sale and self._sale.get('id'):
            self.Sale.write([self._sale['id']], {'invoice_type': val})

    def action_tax_selection_changed(self):
        res = self.Sale.add_tax(self._sale['id'], self.field_tax_id,
            self._context)
        self.set_amounts(res)

    def action_consumer(self):
        if not self._consumer.get('id'):
            self.clear_dialog_consumer()
        else:
            self.set_consumer()
        self.dialog_search_consumer.show()
        self.row_field_phone.setFocus()

    def action_print_sale(self):
        number = self.field_invoice.text()
        if not number:
            number = self.field_number.text()
        if number:
            self.field_invoice_number_ask.setText(number)
        res = self.dialog_print_invoice.exec_()
        if res == DIALOG_REPLY_NO:
            return
        number = self.field_invoice_number_ask.text()
        printer_id = self.field_printer_ask.get_id()
        type_doc = self.field_type_ask.get_id()
        sale_id = None
        if number:
            if type_doc in ['order', 'delivery']:
                if number == self._sale.get('number'):
                    sale_id = self._sale['id']
                else:
                    sales = self.Sale.find([('number', '=', number)])
                    if sales:
                        sale_id = sales[0]['id']
            else:
                args = {'number': number}
                sale = self.Sale.get_sale_from_invoice(args)
                if sale:
                    sale_id = sale['id']
        else:
            sale_id = self._sale['id']

        if not sale_id:
            return self.message_bar.set('sale_number_not_found')

        if printer_id == '1':
            self.print_invoice(sale_id, type_doc=type_doc)
        else:
            self.print_odt_invoice(sale)

    def print_odt_invoice(self, sale):
        if not sale.get('invoices'):
            return
        invoice_id = sale['invoices'][0]
        model = u'account.invoice'
        data = {
            'model': model,
            'action_id': self._action_report['id'],
            'id': invoice_id,
            'ids': [invoice_id],
        }
        ctx = {'date_format': u'%d/%m/%Y'}
        ctx.update(self._context)
        Action.exec_report(self.conn, u'account.invoice', data, direct_print=True, context=ctx)

    def action_comment(self):
        self.dialog_comment.exec_()
        comment = self.field_comment.toPlainText()
        if comment:
            self.Sale.write([self._sale['id']], {'comment': comment})

    def action_position(self):
        self.dialog_position.exec_()
        position = self.field_position.text()
        self.store.update({'position': position})

    def action_agent(self):
        self.dialog_agent.exec_()
        res = self.field_commission_ask.text()
        if not res:
            return
        commission = float(res)
        sale, = self.Sale.find([
            ('id', '=', self._sale['id']),
        ])
        self.field_agent_id = self.field_agent_ask.get_id()

        if self.field_agent_id and commission:
            agent, = self.Agent.find([
                ('id', '=', self.field_agent_id),
            ])
            if commission <= agent['plan']['percentage']:
                self.Sale.write([self._sale['id']], {
                    'agent': self.field_agent_id,
                    'commission': int(commission),
                })
            else:
                self.message_bar.set('invalid_commission')
                return
            self.message_bar.set('system_ready')
            comm_string = str('[' + str(commission) + ']' + ' ') + (str(self.field_agent_ask.text()))
            self.field_agent.setText(comm_string)
            self._set_commission_amount(sale['untaxed_amount'], commission)

    def _set_commission_amount(self, untaxed_amount, commission):
        untaxed_amount = int(untaxed_amount)
        commission = int(commission)
        total = ((untaxed_amount * commission) / 100)
        self.field_commission_amount.setText(str(total))

    def action_party(self):
        if self._state in ['cash']:
            return
        self.dialog_search_parties.clear_rows()
        self.dialog_search_parties.execute()

    def action_global_discount(self, sale_id=None):
        if self._state in ['accept', 'cash']:
            return
        self.dialog_global_discount.exec_()
        discount = self.field_global_discount_ask.text()
        if discount and discount.isdigit():
            self.validate_discount(discount)

    def validate_discount(self, record):
        if self.model_sale_lines.rowCount() > 0:
            lines = [line['id'] for line in self.model_sale_lines._data]
            res = self.set_discount(int(record['discount']), lines)
            if not res:
                self.message_bar.set('discount_not_valid')
                return False

    def _print_order(self, sale_id, kind, reversion=False):
        result = False
        try:
            args = {
                'sale_id': sale_id,
                'reversion': reversion,
                'repeat': False,
            }
            orders, sale_number = self.Sale.get_order2print(args)
            self._sale['number'] = sale_number
            self.field_number.setText(self._sale['number'])
            result = self.receipt_order.print_orders(orders, reversion, kind)
        except:
            logging.error('Printing order fail!')
        return result

    def action_print_order(self, sale_id=None, reversion=False):
        res = self.dialog_order.exec_()
        if res == DIALOG_REPLY_NO:
            return

        kind = 'dispatch'
        if self.enviroment == 'restaurant':
            kind = 'command'
        if not self.print_order:
            return
        if not sale_id and self._sale['id']:
            sale_id = self._sale['id']

        result = self._print_order(sale_id, kind)
        if result:
            # Show dialog if send sale order was successful
            self.dialog('order_successfully')
        else:
            self.dialog('order_failed')
        if self.enviroment == 'restaurant':
            self.change_view_to('start_front')

    def action_channel(self):
        if self._state != 'cash':
            self.dialog_channel.exec_()

    def action_payment_term(self):
        if self._state == 'cash' or self.type_pos_user == 'salesman':
            self.dialog_payment_term.exec_()

    def action_new_sale(self):
        if self._state in ['cash']:
            return
        if not self._sale['id']:
            return
        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

    def _ask_new_sale(self):
        dialog = self.dialog('new_sale', response=True)
        res = dialog.exec_()
        if res == DIALOG_REPLY_NO:
            return False
        return True

    def action_cancel(self):
        if self._state == 'disabled':
            return
        if self.type_pos_user == 'cashier':
            self.dialog_cancel_invoice.exec_()
            password = self.field_password_for_cancel_ask.text()
            if password != self._password_admin:
                return self.dialog('not_permission_for_cancel')

        if not self._sale['id']:
            return
        if self._state in ('cash', 'payment') and not self.user_can_delete:
            return self.dialog('not_permission_delete_sale')
        if self.type_pos_user in ('order', 'salesman') and \
                self._sale.get('invoice_number'):
            return self.dialog('not_permission_delete_sale')
        dialog = self.dialog('cancel_sale', response=True)
        response = dialog.exec_()
        if response == DIALOG_REPLY_NO:
            return
        self.Sale.cancel_sale(self._sale['id'])
        self.field_password_for_cancel_ask.setText('')
        self.set_state('cancel')
        self.clear_right_panel()
        if self.sale_automatic:
            self.create_new_sale()

    def action_search_product(self):
        if self._state == 'cash':
            return
        self.dialog_search_products.show()

    def action_start_delivery(self):
        # self.store.clear()
        self.create_new_sale(kind='delivery')

    def action_start_table(self):
        # self.store.clear()
        self.create_new_sale(kind='to_table')

    def action_start_take_away(self):
        # self.store.clear()
        self.create_new_sale(kind='take_away')

    def action_search_sale(self):
        delta = str(datetime.now() - timedelta(2))
        if self.type_pos_user == 'cashier':
            dom = ['OR', [
                ('create_date', '>=', delta),
                ('state', 'in', ['quotation', 'confirmed']),
            ], [
                ('state', '=', 'processing'),
                ('invoice.state', '=', 'draft'),
                ('invoice.type', '=', 'out'),
            ]]
        elif self.type_pos_user in ('order', 'salesman'):
            dom = [
                ('state', '=', 'draft'),
                ('create_date', '>=', delta),
            ]
        else:
            dom = [
                ('state', 'in', ['draft', 'quotation', 'confirmed']),
                ('create_date', '>=', delta),
            ]

        fields = self.dialog_search_sales.fields_names
        sales = self.Sale.find(dom, fields=fields, order=[('id', 'DESC')])
        self.dialog_search_sales.set_from_values(sales)
        if self.enviroment == 'retail':
            dom_draft = [
                ('create_date', '>=', delta),
                ('state', '=', 'draft'),
                ('invoice_number', '!=', None),
            ]
            sales_draft = self.Sale.find(dom_draft)
            self.dialog_search_sales.set_counter_control(sales_draft)
        response = self.dialog_search_sales.execute()
        self.field_invoice_type.set_enabled(True)
        if response == DIALOG_REPLY_NO:
            return

    def on_selected_sale(self):
        sale_id = self.dialog_search_sales.get_id()
        if not sale_id:
            return
        self.load_sale(sale_id)
        self.setFocus()
        self.label_input.setFocus()
        self.change_view_to('order_front')

    def on_selected_party(self, party_id=None):
        if not party_id:
            party_id = self.dialog_search_parties.get_id()
        if not party_id:
            return

        party, = self.Party.find([('id', '=', party_id)])
        address_id = ''
        if party['addresses']:
            address_id = party['addresses'][0]['id']
        values = {
            'party': {'id': party_id, 'name': party['name']},
            'invoice_address': address_id,
            'shipment_address': address_id,
        }

        payment_term = party.get('customer_payment_term')
        if payment_term:
            values['payment_term'] = payment_term

        if party.get('salesman'):
            values.update({'salesman': party.get('salesman')})

        self.store.update(values)
        self.party_id = party_id

        # if self._credit_limit_activated:
        #     self._check_credit_capacity(party)
        self.message_bar.set('system_ready')
        self.setFocus()
        self.label_input.setFocus()

    def load_sale(self, sale_id):
        # loads only draft sales
        self.clear_data()
        self.clear_left_panel()
        self.clear_right_panel()
        self.store.clear()
        sale, = self.Sale.find([('id', '=', sale_id)])
        self.store.set_sale(sale['id'])
        self.store.set(sale)
        self._sale.update(sale)
        self.table_payment_lines.reset()
        self._set_sale_date()
        self.journal = {}
        if self.field_delivery_charge:
            self.field_delivery_charge.set_enabled(True)
            if sale.get('delivery_charge'):
                self.field_delivery_charge.set_from_id(sale['delivery_charge'])

        if sale.get('table_assigned'):
            self.field_table_assigned.setText(sale['table_assigned']['name'] or '')

        consumer = sale.get('consumer', None)
        if consumer:
            self.field_consumer.setText(consumer['name'] or '')
            self._consumer, = self.Consumer.find([
                ('id', '=', consumer['id']),
            ])

        self.field_change.zero()
        if self._commission_activated:
            if hasattr(self, 'field_agent') and sale.get('agent') \
                    and sale.get('commission'):
                commission = sale.get('commission')
                self.field_agent.setText('[' + str(int(commission)) + ']' + ' ' + sale['agent']['name'])
                self.field_agent_id = sale['agent']['id']
                self.field_agent_ask.setText(sale['agent']['name'])
                self.field_commission_ask.setText(str(commission))
                self._set_commission_amount(sale['untaxed_amount'], commission)
        self.line_ids = [l['id'] for l in sale.get('lines')]
        if sale.get('lines'):
            lines = self.SaleLine.find([
                ('id', 'in', self.line_ids),
            ])
            sale['lines'] = lines
            for line in lines:
                self.add_sale_line(line)

        if sale.get('payments'):
            for payment in sale['payments']:
                self.table_payment_lines.record_add(payment)

        self.set_state('add')
        self.party_id = sale['party']['id']
        self.set_amounts(sale)
        self.set_amount_received()
        self.field_amount.setText('')
        self.message_bar.set('system_ready')
        if self.type_pos_user in ('cashier', 'order', 'salesman'):
            self.table_sale_lines.setEnabled(True)
        if self.enviroment == 'restaurant':
            self.table_sale_lines.setEnabled(True)
            self.menu_dash.setDisabled(False)

    def set_change_amount(self):
        amount_paid = self.table_payment_lines.get_sum('amount')
        res = amount_paid - self._get_total_amount()
        self.field_change.setText(res)

    def set_amount_received(self, cash_received=ZERO):
        pass

    def set_amounts(self, res=None):
        if not res:
            res = self.Sale.get_amounts({'sale_id': self._sale['id']})
        self.store.set(res)
        # self.set_discount_amount()

    def _get_products_by_category(self, cat_id):
        records = self.Product.find([
            ('code', '!=', None),
            ('template.salable', '=', True),
            ('template.categories', '=', cat_id),
        ])
        return records

    def get_product_by_categories(self):
        self.allow_categories = [
            pc for pc in self.product_categories if not pc['parent'] and not pc['accounting']
        ]

        for cat in self.allow_categories:
            cat['icon'] = get_icon(cat['name_icon'])
            if cat.get('childs'):
                for child in cat.get('childs'):
                    child['items'] = self._get_products_by_category(child['id'])
            else:
                cat['items'] = self._get_products_by_category(cat['id'])
        return self.allow_categories

    def get_menu_control_panel(self):
        menu_dash = [
            ['button_open', self.tr('OPEN STATEMENTS'), 'action_open_statement'],
            ['button_closed', self.tr('CLOSED STATEMENTS'), 'action_closed_statement'],
            # ['button_money', self.tr('COUNT MONEY'), 'action_count_money'],
            ['button_discount', self.tr('GLOBAL DISCOUNT'), 'action_table_discount'],
            ['button_delivery_party', self.tr('DELIVERY MEN'), 'action_delivery_party_panel'],
            ['button_help', self.tr('HELP'), 'action_help'],
        ]
        return menu_dash

    def _get_childs(self, parent_cat):
        res = {}
        for cat_id in parent_cat['childs']:
            sub_categories = self.Category.find([
                ('parent', '=', parent_cat['id'])
            ])

            for sub_cat in sub_categories:
                res.update(self._get_childs(sub_cat))
        res = {
            'id': parent_cat['id'],
            'name': parent_cat['name'],
            'childs': parent_cat['childs'],
            'records': [],
            'obj': parent_cat,
        }
        return res

    def get_category_items(self, records):
        records_by_category = {}

        def _get_tree_categories(cat):
            sub_categories = {}
            if not cat['childs']:
                sub_categories[cat['name']] = records_by_category.get(cat['id']) or []
            else:
                for child in cat['childs']:
                    sub_categories.update(_get_tree_categories(
                        self.target_categories[child]['obj']))
            return sub_categories

        for record in records:
            cat_id = record.get('template.account_category')
            if cat_id not in records_by_category.keys():
                records_by_category[cat_id] = []

            records_by_category[cat_id].append(record)

        res = {}
        for ac in self.allow_categories:
            res[ac['name']] = _get_tree_categories(ac)
        return res

    def on_selected_product(self):
        if self.dialog_search_products.current_row:
            self._current_line_id = None
            self.clear_right_panel()
            self.add_product(record=self.dialog_search_products.current_row)

    def on_selected_icon_product(self):
        if self.dialog_search_products.current_row:
            code = self.dialog_search_products.current_row['code']
            products = self.Product.find([
                ('code', '=', code)
            ])
            if not products:
                return

            product = products[0]

            # image = Image(name='product_icon')
            # if not product['image']:
            #     return
            #
            # b64image = product['image'].encode()
            # image.set_image(b64image, kind='bytes')
            # image.activate()

    def on_selected_stock_product(self):
        if self.dialog_search_products.current_row:
            code = self.dialog_search_products.current_row['code']
            res = self.Product.get_stock_by_locations({'code': code})
            self.dialog_product_stock.update_values(res)
            self.dialog_product_stock.show()

    def on_selected_item_mix(self, record):
        list_price = self._current_line['product'].get('list_price')
        if list_price < record['list_price']:
            # Update price in selected_line
            self.set_unit_price(record['template']['sale_price_w_tax'])
            list_price = None
        self.on_selected_item(record, list_price)

    def on_selected_item(self, record, list_price=None):
        if record:
            self.clear_right_panel()
            self.add_product(record=record, list_price=list_price)

    def on_selected_salesman(self, salesman):
        if salesman:
            salesman_data = {
                'id': salesman['id'],
                'name': salesman['rec_name'],
            }
            self.store.update({'salesman': salesman_data})
            self.dialog_salesman.close()

    def on_selected_discount(self, discount):
        if discount:
            self.validate_discount(discount)
        self.dialog_global_discount_table.close()
        self.dialog_control_panel.close()

    def on_selected_delivery_party(self, delivery_party_id):
        if delivery_party_id:
            self.store.update({'delivery_party': delivery_party_id})
            self.dialog_delivery_party.close()

    def on_selected_payment_term(self, payterm_id):
        if payterm_id:
            self.field_payment_term_id = payterm_id
            self.action_payment_term_selection_changed()
            self.dialog_payment_term.close()

    def on_selected_channel(self, channel):
        self.store.update({'channel': channel})
        self.dialog_channel.close()

    def on_selected_payment(self, journal):
        self.journal = journal
        if journal.get('id'):
            self.field_journal_id = journal['id']
            self.dialog_payment.close()
            self.message_bar.set('enter_payment', journal['rec_name'])

    def on_search_product(self):
        target = self.dialog_search_products.filter_field.text()
        if not target:
            return
        target_words = target.split(' ')
        domain = [
            ('template.active', '=', True),
            ('active', '=', True),
            ('template.salable', '=', True),
        ]
        for tw in target_words:
            if len(tw) <= 1:
                continue
            clause = [
                'OR',
                ('template.name', 'ilike', '%{:}%'.format(tw)),
                ('description', 'ilike', '%{:}%'.format(tw)),
                ('code', 'ilike', '%{:}%'.format(tw))
            ]
            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']]
            domain.append(('template.categories', 'in', categories_id))

        if not domain:
            return

        if self.cache_local:
            domain = [clause]
            products = self.local_db.find_product_elastic(domain, limit=100)
        else:
            fields = self.dialog_search_products.fields_names
            products = self.Product.find(domain, fields=fields,
                limit=100, ctx=self.stock_context)

        self.dialog_search_products.set_from_values(products)

    def on_search_party(self):
        target = self.dialog_search_parties.filter_field.text()
        if not target:
            return
        target_words = target.split(' ')
        domain = [('id_number', '!=', None)]
        for tw in target_words:
            if len(tw) <= 2:
                continue
            or_clause = [
                'OR',
                 ('name', 'ilike', '%' + tw + '%'),
                 ('contact_mechanisms.value', 'like', tw + '%'),
                 ('id_number', 'like', tw + '%')
            ]
            domain.append(or_clause)
        fields_names = self.dialog_search_parties.fields_names
        parties = self.Party.find(domain, fields=fields_names)
        self.dialog_search_parties.set_from_values(parties)

    def clear_data(self):
        self._sale = {'total_amount': 0, 'tip_amount': 0, 'delivery_amount': 0}
        self.party_name = None
        self._sale_line = {'id': None}
        self._total_amount = {}
        self._sale_lines_taxes = {}
        self.field_journal_id = self.default_journal['id']
        self.field_voucher_ask.setText('')

    def clear_left_panel(self):
        self.field_party.setText('')
        self.field_salesman.setText('')
        self.field_salesman_id = None
        self.field_invoice_type.set_from_id('P')
        self.field_party_id = None
        self.field_agent_id = None
        self.field_payment_term_id = self.default_payment_term['id']
        self.field_payment_term.setText(self.default_payment_term['name'])
        self.field_sale_date.setText('')
        self.field_global_discount_ask.setText('')
        self.field_amount.setText('')
        self.field_number.setText('')
        self.field_state.setText('')
        self.current_comment = ''
        if hasattr(self, 'field_consumer'):
            self.field_consumer.setText('')
        if self.field_delivery_charge:
            self.field_delivery_charge.set_from_id('')
        if self.field_table_assigned:
            self.field_table_assigned.setText('')
        if hasattr(self, 'field_comment'):
            self.field_comment.document().clear()
        if self._commission_activated and hasattr(self, 'field_agent'):
            self.field_agent.setText('')
            self.field_agent_ask.setText('')
            self.field_commission_ask.setText('')
            self.field_commission_amount.setText('')
        self.model_sale_lines.reset()
        self.clear_input_text()
        self.clear_amount_text()

    def clear_right_panel(self):
        self.field_invoice.setText('')
        self.field_tip_amount.setText('')
        self.field_delivery_amount.setText('')
        self.field_untaxed_amount.zero()
        self.field_net_amount.zero()
        self.field_taxes_amount.zero()
        self.field_total_amount.zero()
        self.field_change.zero()
        self.field_paid_amount.zero()
        self.field_discount.zero()
        self.field_residual_amount.zero()
        self.table_payment_lines.reset()

    def state_enabled(self):
        pass

    def state_disabled(self):
        self.payment_ctx = {}
        self.clear_left_panel()
        self.table_sale_lines.setDisabled(True)
        self.set_state('disabled')
        if self.field_delivery_charge:
            self.field_delivery_charge.set_enabled(False)

    def create_new_sale(self, kind=None):
        if self.enviroment == 'restaurant' and self._sale_pos_restaurant:
            self.clear_dialog_consumer()
        # self.check_empty_sale()
        if self.type_pos_user == 'cashier':
            self.message_bar.set('not_sale')
            # self.state_disabled()
            return
        self.store.clear()
        self.journal = {}
        self.set_state('add')
        self.input_text_changed('')
        self.amount_text_changed('0')
        self.clear_sign()
        self.show_right_panel(True)
        self.consumer_id = None
        self.payment_ctx = {}
        self.table_sale_lines.setEnabled(True)
        self.field_invoice_type.set_enabled(True)
        self.clear_data()
        self.clear_right_panel()
        self.clear_left_panel()
        self.message_bar.set('system_ready')
        to_create = {
            'shop': self.shop['id'],
            'invoice_type': 'P',
            'company': self.company['id'],
            'party': self.default_party['id'],
            'sale_device': self.device['id'],
            'payment_term': self.default_payment_term['id'],
        }
        if kind:
            kind_dict = {'kind': kind}
            to_create.update(kind_dict)
        self._sale = self.Sale.new_sale(to_create)
        self.store.set(self._sale)
        if kind:
            self.store.set(kind_dict)

        # FIXME ADD MORE
        self._sale.update({
            'total_amount': 0
        })

        self.party_id = self.default_party['id']
        if self._sale.get('id') and self.field_delivery_charge:
            if self.field_delivery_charge:
                self.field_delivery_charge.set_enabled(True)
        self.change_view_to('order_front')
        if self.enviroment == 'restaurant':
            self.menu_dash.setDisabled(False)

    def _set_sale_date(self):
        if self._sale.get('sale_date'):
            local_date = self._sale['sale_date']
            if isinstance(local_date, date):
                local_date = local_date.isoformat()
            self.field_sale_date.setText(local_date)

    def _search_product(self, code):
        domain = [
            ('template.salable', '=', True),
            ('template.account_category', '!=', None),
        ]
        domain.append(['OR',
                       ('barcode', '=', code),
                       ('code', '=', code)])
        if self.cache_local:
            clause = ['OR',
                      ('barcode', '=', '%{:}%'.format(code)),
                      ('code', '=', '%{:}%'.format(code))]
            domain = [clause]
            products = self.local_db.find_product_elastic(domain, limit=100)
        else:
            products = self.Product.find(domain, ctx=self.stock_context)

        if not products or len(products) > 1:
            self.message_bar.set('product_not_found')
            return False
        else:
            product = products[0]
        return product

    def _check_quantity(self):
        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 product_id:
                product, = self.Product.find([('id', '=', product_id)], ctx=self.stock_context)
                if 'quantity' in product and not self._check_stock_quantity(product):
                    return False
        return True

    def check_salesman(self):
        salesman = self.store.get('salesman')
        if self.salesman_required and not salesman:
            dialog = self.dialog('missing_salesman')
            dialog.exec_()
            return False
        return True

    def add_product(self, record=None, code=None, list_price=None):
        if self._state == 'disabled':
            self.message_bar.set('must_load_or_create_sale')
            return

        product_id = None
        if record:
            product_id = record['id']
        elif code:
            # REMOVE ME
            product = self._search_product(code)
            if product:
                product_id = product['id']
        elif product:
            product_id = product['id']

        if not product_id:
            self._state = 'warning'
            return

        data = {
            'sale_id': self._sale['id'],
            'product_id': product_id,
            'qty': 1,
        }
        if list_price:
            data['list_price'] = list_price
        res = self.Sale.faster_add_product(data)
        self._sale_line = res
        self._current_line_id = res['id']
        self.add_sale_line(res)
        self._sale_line['product'] = record
        self.product_id = product_id

        self.set_amounts()
        self.set_state('add')

    def _check_stock_quantity(self, product, request_qty=None):
        if not isinstance(product['quantity'], (str, int, float, Decimal)):
            return True
        qty_ = Decimal(product['quantity'])
        if self._password_force_assign:
            if (request_qty and qty_ < request_qty) or (qty_ <= 0):
                self.message_bar.set('without_stock_quantity', product['name'])
                self.dialog_force_assign.exec_()
                password = self.field_password_force_assign_ask.text()
                self.field_password_force_assign_ask.setText('')
                if password != self._password_force_assign:
                    self.message_bar.set('not_can_force_assign')
                    return False
                else:
                    self.message_bar.set('system_ready')
        return True

    def add_sale_line(self, record):
        if not record.get('unit.symbol'):
            record['unit.symbol'] = record['unit']['symbol']
        if isinstance(record['product'], dict):
            if not record.get('product.template.name'):
                record['product.template.name'] = record['product']['template']['name']
            if not record.get('product.code'):
                record['product.code'] = record['product']['code']
        if record.get('order_sended'):
            record['order_sended'] = '✔'
        rec = self.model_sale_lines.add_record(record)
        self.field_amount.setText(rec['amount_w_tax'])

    def sale_line_selected(self, line):
        if self._state in ('cash', 'payment'):
            return

        self._current_line = line
        self._current_line_id = line['id']
        product_id = None
        if isinstance(line['product'], int):
            product_id = line['product']
        elif isinstance(line['product'], dict):
            product_id = line['product']['id']
        self.product_id = product_id
        self.label_product.setText(line['product.template.name'])
        self.row_field_description.setText(line['description'])
        self.row_field_qty.setValue(float(line['quantity']))
        self.row_field_price.setText(str(line['unit_price_w_tax']))
        self.row_field_note.setText(str(line['note']))
        self.dialog_product_edit.show()
        self.row_field_note.setFocus()

    def sale_consumer_selected(self, data):
        self.sale_customer_selected = data['id']
        self.row_sale_party.setText(data['party']['name'])
        self.row_sale_number.setText(data['number'])
        self.row_sale_date.setText(data['sale_date'])
        self.row_sale_tax_amount.setText(str(data['tax_amount']))
        self.row_sale_untaxed.setText(str(data['untaxed_amount']))
        self.row_sale_total.setText(str(data['total_amount_cache']))
        self.model_sale_customer_lines.reset()
        for line in data['lines']:
            self.model_sale_customer_lines.add_record(line)
        self.dialog_sale_consumer_selected.exec_()

    def clear_delivery_party(self):
        self._delivery_party_selected = None
        self.row_delivery_party.setText('')
        self.row_id_number.setText('')
        self.row_phone.setText('')
        self.row_number_plate.setText('')
        self.row_type_vehicle.set_from_id('')
        self.row_delivery_party_active.setChecked(True)

    def delivery_party_selected(self, data):
        self._delivery_party_selected = data['id']
        self.row_delivery_party.setText(data['rec_name'])
        self.row_id_number.setText(data['party']['id_number'])
        self.row_number_plate.setText(data['number_plate'])
        if data.get('type_vehicle'):
            self.row_type_vehicle.set_from_id(data['type_vehicle'])
        self.row_delivery_party_active.setChecked(data['active'])
        self.dialog_delivery_party_selected.show()
        self.row_delivery_party_active.setFocus()

    def setup_money_count(self):
        self.model_money_count = TableModelEdit(self, MONEY)

    def setup_sale_line(self):
        product_code = {
            'name': 'product.code',
            'align': alignRight,
            'description': self.tr('COD'),
            'width': 80
        }
        product = {
            'name': 'product.template.name',
            'align': alignLeft,
            'description': self.tr('NAME'),
            'width': STRETCH
        }
        description = {
            'name': 'description',
            'align': alignLeft,
            'description': self.tr('DESCRIPTION'),
            'width': 180
        }
        uom = {
            'name': 'unit.symbol',
            'align': alignHCenter,
            'description': self.tr('UNIT'),
            'width': 50
        }
        qty = {
            'name': 'quantity',
            'format': '{:3,.%sf}',
            'align': alignRight,
            'description': self.tr('QTY'),
            'digits': ('unit.symbol', CONVERSION_DIGITS),
            'width': 80
        }
        discount = {
            'name': 'discount',
            'format': '{0:.0%}',
            'align': alignRight,
            'description': self.tr('DISC'),
            'width': 50
        }
        amount = {
            'name': 'amount_w_tax',
            'format': '{:,d}',
            'align': alignRight,
            'description': self.tr('SUBTOTAL'),
            'width': 100
        }
        note = {
            'name': 'note',
            'align': alignLeft,
            'description': self.tr('NOTE'),
            'invisible': True,
            'width': 100
        }
        unit_price = {
            'name': 'unit_price_w_tax',
            'format': '{:5,.1f}',
            'align': alignLeft,
            'description': self.tr('UNIT PRICE W TAX'),
            'invisible': True,
            'width': 100
        }

        qty_fraction = {
            'name': 'qty_fraction',
            'align': alignHCenter,
            'description': self.tr('FRAC'),
            'width': 50
        }

        commanded = {
            'name': 'order_sended',
            'align': alignHCenter,
            'description': self.tr('COMMANDED'),
            'width': 60
        }

        self.fields_sale_line = [product, uom, qty, discount,
            amount, note, unit_price]

        if self.enviroment == 'retail':
            self.fields_sale_line.insert(0, product_code)

        if self.enviroment == 'restaurant':
            self.fields_sale_line.insert(1, commanded)

        if self._config.get('show_description_pos'):
            self.fields_sale_line.insert(2, description)

        if self._config.get('show_fractions'):
            self.fields_sale_line.insert(4, qty_fraction)

        self.model_sale_lines = TableModel('sale.line', self.fields_sale_line)
        self.model_sale_customer_lines = TableModel('sale.line', self.fields_sale_line)

    def setup_sale_consumer(self):
        number = {
            'name': 'number',
            'align': alignCenter,
            'description': self.tr('NUMBER'),
            'width': 200
        }
        invoice_number = {
            'name': 'invoice_number',
            'align': alignCenter,
            'description': self.tr('INVOICE NUMBER'),
            'width': 200
        }
        consumer = {
            'name': 'consumer.name',
            'align': alignCenter,
            'description': self.tr('CONSUMER'),
            'width': 300
        }
        sale_date = {
            'name': 'sale_date',
            'align': alignCenter,
            'description': self.tr('DATE'),
            'width': 300
        }
        total_amount_cache = {
            'name': 'total_amount_cache',
            'align': alignCenter,
            'description': self.tr('TOTAL AMOUNT'),
            'width': 300
        }

        self.fields_sale_consumer = [number, invoice_number, consumer, sale_date,
                                     total_amount_cache]
        self.model_sale_consumer = TableModel('sale.sale', self.fields_sale_consumer)

    def setup_delivery_party(self):
        party = {
            'name': 'rec_name',
            'align': alignLeft,
            'description': self.tr('PARTY'),
            'width': 380
        }
        id_number = {
            'name': 'party.id_number',
            'align': alignLeft,
            'description': self.tr('ID NUMBER'),
            'width': 200
        }
        phone = {
            'name': 'party.phone',
            'align': alignLeft,
            'description': self.tr('PHONE'),
            'width': 200
        }
        number_plate = {
            'name': 'number_plate',
            'align': alignCenter,
            'description': self.tr('NUMBER PLATE'),
            'width': 200
        }
        type_vehicle = {
            'name': 'type_vehicle',
            'align': alignCenter,
            'description': self.tr('TYPE VEHICLE'),
            'width': 300
        }

        self.fields_delivery_party = [party, id_number, phone, number_plate, type_vehicle]
        self.model_delivery_party = TableModel('sale.delivery_party', self.fields_delivery_party)
        for record in self.delivery_man_table:
            self.model_delivery_party.add_record(record)
        self.delivery_parties = [d for d in self.model_delivery_party._data if d['active']]

    def setup_payment(self):
        pay_fields = [{
            'name': 'statement',
            'align': alignLeft,
            'description': self.tr('STATEMENT JOURNAL'),
        }, {
            'name': 'amount',
            'align': alignRight,
            'format': '{:5,.1f}',
            'description': self.tr('AMOUNT'),
        }, {
            'name': 'voucher',
            'align': alignCenter,
            'description': self.tr('VOUCHER'),
        }]
        self.table_payment_lines = TableModel('account.statement.line', pay_fields)

    def action_table(self):
        self.table_sale_lines.setFocus()

    def on_change_line_selected(self, key):
        self.table_sale_lines.moved_selection(key)

    def action_addition_line(self):
        if not self._current_line:
            return

        categories = self._current_line['product'].get('categories')
        if not categories:
            return
        categories_ids = [cat['id'] for cat in categories]
        mixables = self.Product.find([
            ('categories', 'in', categories_ids),
        ])
        self.dialog_addition_product.set_products(mixables)
        self.dialog_addition_product.exec_()
        self.dialog_addition_product.close()

    def action_delete_line(self):
        """Delete Product """
        if self.model_sale_lines.rowCount() <= 0 or self._state == 'cash':
            return

        self.table_sale_lines.setFocus()

        # if not removed_item:
        removed_item = self.table_sale_lines.delete_item(ignore_focus=True)
        self.SaleLine.delete([removed_item['id']])
        self.set_amounts()

        self._current_line_id = None
        self.setFocus()
        self.label_input.setFocus()
        self.dialog_product_edit.hide()
        sale_number = self.store.get('number')
        if self.enviroment == 'restaurant':
            if removed_item and self.print_order and sale_number:
                self.action_print_order(self._sale['id'], removed_item)
            if self._config['tip_product']['code'] == removed_item['product.code']:
                self.Sale.write([self._sale['id']], {'tip': None})

    def set_discount(self, eval_value, lines_ids=[]):
        res = False
        try:
            value = round(float(str(eval_value)), 6)
        except ValueError:
            logging.warning('ValueError > ', ValueError)
            return
        if float(value) < 0:
            return False

        if not lines_ids:
            target_lines = [self._current_line_id]
        else:
            target_lines = lines_ids

        records = self.SaleLine.faster_set_discount({
            'line_ids': target_lines,
            'value': value
        })
        for rec in records:
            self.model_sale_lines.update_record(rec)

        if records:
            res = True
            self.set_amounts()
        return res

    def set_unit_price(self, value):
        rec = self.SaleLine.set_faster_unit_price({
            'id': self._current_line_id,
            'value': value,
        })

        if rec:
            self.model_sale_lines.update_record(rec)
            self.set_amounts()
            return True
        return False

    def add_payment(self, amount, cash_received=0, change=0):
        voucher_number = None
        if not self.journal:
            journal = self.default_journal
        else:
            journal = self.journal

        if journal.get('require_voucher'):
            self.dialog_voucher.exec_()
            voucher_number = self.field_voucher_ask.text()
            if voucher_number is None or voucher_number == '':
                return self.add_payment(amount)

        res = self.Sale.faster_add_payment({
            'sale_id': self._sale['id'],
            'journal_id': journal['id'],
            'amount': to_numeric(amount),
            'voucher_number': voucher_number,
            'cash_received': to_numeric(cash_received),
            'change': to_numeric(change)
        })

        if res.get('msg') not in ('missing_money', 'ok'):
            self.dialog(res['msg'])
            return res
        residual_amount = res.pop('residual_amount')
        change = res.pop('change')
        paid_amount = res.pop('paid_amount')
        self.store.set({
            'residual_amount': residual_amount,
            'change': change,
            'paid_amount': paid_amount,
        })

        self.table_payment_lines.add_record(res)
        return res

    def set_keys(self):
        self.keys_numbers = list(range(Qt.Key_0, Qt.Key_9 + 1))
        self.keys_alpha = list(range(Qt.Key_A, Qt.Key_Z + 1))
        self.keys_period = [Qt.Key_Period]
        self.show_keys = self.keys_numbers + self.keys_alpha + self.keys_period

        self.keys_special = [Qt.Key_Asterisk, Qt.Key_Comma, Qt.Key_Minus, Qt.Key_Slash]
        self.keys_input = [Qt.Key_Backspace]
        self.keys_input.extend(self.keys_special)
        self.keys_input.extend(self.show_keys)
        self.keys_input.extend(self.keys_numbers)
        self.keys_input.extend([Qt.Key_Return, Qt.Key_Plus])

    def set_state(self, state='add'):
        self._state = state
        state = STATES[state]
        self._re = state['re']
        if not self.type_pos_user == 'order':
            if not self.buttons_stacked.stacked.currentWidget():
                return
            if state['button']:
                self.buttons_stacked.stacked.setCurrentWidget(
                    getattr(self.buttons_stacked, state['button'])
                )
                self.buttons_stacked.stacked.currentWidget().setVisible(True)
            else:
                self.buttons_stacked.stacked.currentWidget().setVisible(False)

    def key_pressed(self, text):
        if not self._sign and self._state not in ('cash', 'payment'):
            # FIXME
            # if self._re.match(self._input_text + text):
            #     self.input_text_changed(text)
            pass
        else:
            if RE_SIGN['quantity'].match(self._amount_text + text):
                self.amount_text_changed(text)

    def clear_sign(self):
        self._sign = None
        self.field_sign.setText(' {0} '.format(' '))

    def sign_text_changed(self, sign):
        self._sign = sign
        self.field_sign.setText(' {0} '.format(sign))
        if hasattr(self, '_sale_line') and self._sale_line:
            if sign == '-':
                self.message_bar.set('enter_discount')
            elif sign == '/':
                self.message_bar.set('enter_new_price')
            elif sign == '*':
                self.message_bar.set('enter_quantity')
                if self.active_weighing and self._sale_line['unit_symbol'] != 'u':
                    self.action_read_weight()

    def key_special_pressed(self, value):
        self.clear_amount_text()
        self.clear_input_text()
        if value not in ['-', '/', '*']:
            return
        self.sign_text_changed(value)

    def key_backspace_pressed(self):
        if self._sign or self._state in ('cash', 'payment'):
            self._amount_text = self._amount_text[:-1]
            self.amount_text_changed()
            self.label_input.setFocus()
        else:
            self._input_text = self._input_text[:-1]
            self.input_text_changed()

    def set_text(self, text):
        if not self._state == 'cash':
            self.input_text_changed(text)
        else:
            self.amount_text_changed(text)

    def clear_input_text(self):
        self.input_text_changed('')

    def clear_amount_text(self):
        self._amount_text = '0'
        self.amount_text_changed()

    def keyPressEvent(self, event):
        self._keyStates[event.key()] = True
        key = event.key()
        if self._state == 'add' and key not in self.keys_input and \
                key not in (Qt.Key_Enter, Qt.Key_End):
            # Clear ui context when keys function are pressed
            self._clear_context()
        if key in (Qt.Key_Return, Qt.Key_Plus):
            self.button_plus_pressed()
        elif key in self.show_keys:
            # No allow change quantity o discount in state == cash
            if self._state in ('cash', 'payment') and key not in self.keys_numbers:
                return
            self.key_pressed(event.text())
        elif key in self.keys_special:
            if self._state == 'cash' or not self._current_line_id:
                return
            self.key_special_pressed(event.text())
        elif key == Qt.Key_Backspace:
            self.key_backspace_pressed()
        elif key == Qt.Key_Escape:
            if self._state not in ('cash', 'payment'):
                self._clear_context()
            # self.close()
        elif key == Qt.Key_F1:
            # help = Help(self).show()
            self.action_control_panel()
        elif key == Qt.Key_F9:
            self.action_search_sale()
        elif key == Qt.Key_F11:
            self.action_new_sale()
        elif key == Qt.Key_F7:
            self.action_print_sale()
        elif self._state == 'disabled':
            self.message_bar.set('must_load_or_create_sale')
            return
        elif key in (Qt.Key_Enter, Qt.Key_End):
            if self.type_pos_user in ['order', 'salesman']:
                return
            if self._state == 'add':
                self.button_accept_pressed()
            elif self._state in ['cash', 'accept']:
                self.button_cash_pressed()
        elif key == Qt.Key_F2:
            self.action_search_product()
        elif key == Qt.Key_F3:
            self.action_payment()
        elif key == Qt.Key_F4:
            self.action_party()
        elif key == Qt.Key_F5:
            self.action_global_discount()
        elif key == Qt.Key_F6:
            self.action_print_order()
        elif key == Qt.Key_F8:
            self.action_payment_term()
        elif key == Qt.Key_F10:
            self.action_table()
        elif key == Qt.Key_F12:
            self.action_cancel()
        elif key == Qt.Key_Home:
            self.action_salesman()
        elif key == Qt.Key_Down or key == Qt.Key_Up:
            self.on_change_line_selected(key)
        elif key == Qt.Key_Insert:
            self.action_position()
        elif key == Qt.Key_Semicolon and self._commission_activated:
            sale = self.get_current_sale()
            if sale['state'] == 'draft' and self._state not in ['cash', 'payment']:
                self.action_agent()
        elif key == Qt.Key_QuoteDbl:
            self.action_comment()
        elif key == Qt.Key_Question:
            self.action_tax()

    @property
    def state(self):
        return self._state

    def update_sale_line(self, field):
        value = None
        self.state_line['id'] = self._current_line_id
        if field == 'quantity':
            value = Decimal(self.row_field_qty.value())
        if field == 'unit_price':
            value = self.row_field_price.text()
        if field == 'qty_fraction':
            qty = self.field_combobox_fraction.get_id()
            self.row_field_qty.setValue(float(qty))
            value = self.field_combobox_fraction.get_label()
            self.state_line['quantity'] = qty
            price_ = self.Sale.get_product_prices({
                'ids': [self._sale_line['product']['id']],
                'quantity': float(qty),
                'sale_id': self._sale['id'],
            })
            if price_ and price_.get('unit_price_w_tax'):
                price_list = str(price_['unit_price_w_tax'])
                self.row_field_price.setText(price_list)
                self.state_line['unit_price'] = price_list

        if field == 'description':
            value = self.row_field_description.text()
        if field == 'note':
            value = self.row_field_note.toPlainText()

        if value:
            self.state_line[field] = value

    def dialog_product_edit_accepted(self):
        if not self.state_line:
            return
        _record = None
        if self.state_line.get('unit_price'):
            unit_price = self.state_line.pop('unit_price')
            self._sign = '/'
            self._process_price(unit_price)
            self._sign = None
            _record = self.SaleLine.write([self._current_line_id], {})

        if self.state_line.get('quantity'):
            quantity = self.state_line.pop('quantity')
            _record = self.SaleLine.faster_set_quantity({
                'id': self._current_line_id,
                'quantity': to_float(quantity, 2)
            })

        if self.state_line.get('description'):
            _record = self.SaleLine.write([self._current_line_id], {
                'description': self.state_line['description']
            })

        if self.state_line.get('note'):
            _record = self.SaleLine.write([self._current_line_id], {
                'note': self.state_line['note']
            })
        if _record:
            if not _record.get('unit.symbol'):
                _record['unit.symbol'] = _record['unit']['symbol']
            if not _record.get('product.template.name'):
                _record['product.template.name'] = _record['product']['template']['name']
            if not _record.get('product.code'):
                _record['product.code'] = _record['product']['code']
            self.model_sale_lines.update_record(_record)
        self.set_amounts()
        self.state_line = {}

    def dialog_search_consumer_accepted(self):
        if not self.state_consumer:
            return
        if self._consumer:
            res = self.Sale.update_consumer({
                'id': self._consumer['id'],
                'fields': self.state_consumer,
            })
        else:
            res = self.Sale.create_consumer({
                'fields': self.state_consumer,
            })
        if res.get('msg') == 'ok':
            self._consumer = res['consumer']
            self.consumer_id = self._consumer['id']
            self._sale['consumer'] = self.consumer_id
            self.set_consumer()
            self.field_consumer.setText(self._consumer['name'])
            self.Sale.write([self._sale['id']], {'consumer': self.consumer_id})
            if res.get('party'):
                self.on_selected_party(res['party'])

    def dialog_delivery_party_accepted(self):
        if not self.state_delivery_party:
            return
        if hasattr(self, '_delivery_party_selected') and self._delivery_party_selected:
            res = self.Sale.update_delivery_party({
                'id': self._delivery_party_selected,
                'data': self.state_delivery_party
            })
            self._delivery_party_selected = None
            self.model_delivery_party.update_record(res)
        else:
            res = self.Sale.create_delivery_party({
                'data': self.state_delivery_party,
                'shop_id': self.ctx['shop']
            })
            self.model_delivery_party.add_record(res)

        self.delivery_parties = [d for d in self.model_delivery_party._data if d['active']]
        self.dialog_delivery_party = DialogDeliveryParty(self).get()

    def update_delivery_party(self, field=''):
        if field == 'delivery_party':
            self.state_delivery_party['party'] = self.row_delivery_party.text()
        if field == 'row_phone':
            self.state_delivery_party['phone'] = self.row_phone.text()
        if field == 'id_number':
            self.state_delivery_party['id_number'] = self.row_id_number.text()
        if field == 'number_plate':
            self.state_delivery_party['number_plate'] = self.row_number_plate.text()
        if field == 'type_vehicle':
            self.state_delivery_party['type_vehicle'] = self.row_type_vehicle.get_id()
        if field == 'delivery_party_active':
            self.state_delivery_party['active'] = self.row_delivery_party_active.isChecked()

    def update_consumer_data(self, field=''):
        if field == 'notes':
            self.state_consumer['notes'] = self.row_field_consumer_notes.toPlainText()
        if field == 'address':
            self.state_consumer['address'] = self.row_field_address.text()
        elif field == 'id_number':
            self.state_consumer['id_number'] = self.row_field_id_number.text()
        elif field == 'name':
            self.state_consumer['name'] = self.row_field_consumer.text()
        elif field == 'birthday':
            self.state_consumer['birthday'] = self.row_field_birthday.date().toPyDate()
        elif field == 'phone':
            self._text_field_phone = self.row_field_phone.text()
            if self._text_field_phone:
                self.state_consumer['phone'] = self._text_field_phone
                consumers = self.PartyConsumer.find([
                    ('phone', '=', self._text_field_phone),
                ])

                if not consumers:
                    self._consumer = {}
                    self.row_field_address.setText('')
                    self.row_field_consumer.setText('')
                    self.row_field_id_number.setText('')
                    self.row_field_birthday.setDate(MINIMUM_DATE)
                    self.row_field_consumer_notes.clear()
                else:
                    self.button_history_customer.setVisible(True)
                    self._consumer = consumers[0]
                    self.set_consumer()
                    # self.row_field_address.setText(self._consumer['address'])
                    # self.row_field_consumer.setText(self._consumer['name'])
                    # self.row_field_id_number.setText(self._consumer['id_number'])
                    # self.row_field_consumer_notes.insertPlainText(
                    #     self._consumer['notes'])
                    # if self._consumer.get('birthday'):
                    #     y, m, d = self._consumer['birthday'].split('-')
                    #     self.row_field_birthday.setDate(QDate(int(y), int(m), int(d)))

    def action_table_assigned(self, table, name, trasition_state):
        current_table = self._sale.get('table_assigned')
        current_sale_id = self._sale['id']
        table_id = table['id']

        table_sale_id = table['sale_id']
        new_table_id = table_id
        table_state = table['state']

        sale_id = current_sale_id
        if table_state == 'occupied':
            if current_sale_id != table_sale_id and trasition_state == 'occupied':
                return False
            elif current_table and current_table['id'] == table_id and trasition_state == 'available':
                name = ''
                new_table_id = None
                current_sale_id = None

        vals = {'table_assigned': {
            'id': table_id,
            'name': name,
        }}
        self.store.set(vals)
        # self._sale['table_assigned.state'] = trasition_state
        self.RestTables.write([table_id], {
            'state': trasition_state,
            'sale': current_sale_id,
        })

        self.Sale.write([self.store.sale_id], {'table_assigned': new_table_id})
        return {
            'state': trasition_state,
            'sale': sale_id,
        }

    def action_see_table_sale(self, table_id):
        table_, = self.RestTables.find([
            ('id', '=', table_id),
        ], limit=1)
        sale = table_['sale']
        if sale:
            self.load_sale(sale['id'])
            self.dialog_manage_tables.hide()

    def clear_dialog_consumer(self):
        self._consumer = {}
        self.row_field_phone.setText('')
        self.row_field_address.setText('')
        self.row_field_consumer.setText('')
        self.row_field_id_number.setText('')
        self.row_field_birthday.setDate(QDate(2000, 1, 1))
        self.row_field_consumer_notes.clear()
        self.button_history_customer.setVisible(False)

    def set_consumer(self):
        self.row_field_consumer_notes.clear()
        self.row_field_phone.setText(self._consumer['phone'])
        self.row_field_consumer.setText(self._consumer['name'])
        self.row_field_address.setText(self._consumer['address'])
        id_number = self._consumer.get('id_number')
        if id_number:
            self.row_field_id_number.setText(id_number)
        self.row_field_consumer_notes.insertPlainText(
            self._consumer['notes']
        )
        if self._consumer.get('birthday'):
            y, m, d = self._consumer['birthday'].split('-')
            self.row_field_birthday.setDate(QDate(int(y), int(m), int(d)))

# 2798
