Add initial support for item lookup dialog
This commit is contained in:
parent
ced1d37edd
commit
55203afc4d
|
@ -24,219 +24,26 @@
|
||||||
WuttaPOS - customer lookup control
|
WuttaPOS - customer lookup control
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import flet as ft
|
from .lookup import WuttaLookup
|
||||||
|
|
||||||
from .base import WuttaControl
|
|
||||||
from .keyboard import WuttaKeyboard
|
|
||||||
|
|
||||||
|
|
||||||
class WuttaCustomerLookup(WuttaControl):
|
class WuttaCustomerLookup(WuttaLookup):
|
||||||
|
|
||||||
default_font_size = 40
|
def get_results_columns(self):
|
||||||
font_size = default_font_size * 0.8
|
return [
|
||||||
default_button_height_dlg = 80
|
self.app.get_customer_key_label(),
|
||||||
disabled_bgcolor = '#aaaaaa'
|
"Name",
|
||||||
|
"Phone",
|
||||||
|
"Email",
|
||||||
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def get_results(self, session, entry):
|
||||||
self.initial_search = kwargs.pop('initial_search', None)
|
return self.app.get_clientele_handler().search_customers(session, entry)
|
||||||
self.on_customer = kwargs.pop('on_customer', None)
|
|
||||||
self.on_cancel = kwargs.pop('on_cancel', None)
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
# track current selection
|
def make_result_row(self, customer):
|
||||||
self.selected_customer_uuid = None
|
return [
|
||||||
self.selected_control = None
|
customer['_customer_key_'],
|
||||||
|
customer['name'],
|
||||||
def build(self):
|
customer['phone_number'],
|
||||||
|
customer['email_address'],
|
||||||
self.searchbox = ft.TextField("", text_size=self.font_size * 0.8,
|
]
|
||||||
on_submit=self.lookup,
|
|
||||||
autofocus=True,
|
|
||||||
expand=True)
|
|
||||||
|
|
||||||
self.search_results = ft.DataTable(
|
|
||||||
columns=[
|
|
||||||
ft.DataColumn(self.make_cell_text(self.app.get_customer_key_label())),
|
|
||||||
ft.DataColumn(self.make_cell_text("Name")),
|
|
||||||
ft.DataColumn(self.make_cell_text("Phone")),
|
|
||||||
ft.DataColumn(self.make_cell_text("Email")),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.no_results = ft.Text("NO RESULTS", size=32, color='red',
|
|
||||||
weight=ft.FontWeight.BOLD,
|
|
||||||
visible=False)
|
|
||||||
|
|
||||||
self.select_button = ft.Container(
|
|
||||||
content=ft.Text("Select", size=self.font_size * 0.8),
|
|
||||||
alignment=ft.alignment.center,
|
|
||||||
height=self.default_button_height_dlg * 0.8,
|
|
||||||
width=self.default_button_height_dlg * 1.3,
|
|
||||||
border=ft.border.all(1, 'black'),
|
|
||||||
border_radius=ft.border_radius.all(5),
|
|
||||||
on_click=self.select_customer,
|
|
||||||
disabled=True,
|
|
||||||
bgcolor=self.disabled_bgcolor,
|
|
||||||
)
|
|
||||||
|
|
||||||
return ft.Column(
|
|
||||||
[
|
|
||||||
ft.Row(
|
|
||||||
[
|
|
||||||
ft.Text("SEARCH FOR:"),
|
|
||||||
self.searchbox,
|
|
||||||
ft.Container(
|
|
||||||
content=ft.Text("Lookup", size=self.font_size * 0.8),
|
|
||||||
alignment=ft.alignment.center,
|
|
||||||
height=self.default_button_height_dlg * 0.8,
|
|
||||||
width=self.default_button_height_dlg * 1.3,
|
|
||||||
border=ft.border.all(1, 'black'),
|
|
||||||
border_radius=ft.border_radius.all(5),
|
|
||||||
on_click=self.lookup,
|
|
||||||
bgcolor='blue',
|
|
||||||
),
|
|
||||||
ft.Container(
|
|
||||||
content=ft.Text("Reset", size=self.font_size * 0.8),
|
|
||||||
alignment=ft.alignment.center,
|
|
||||||
height=self.default_button_height_dlg * 0.8,
|
|
||||||
width=self.default_button_height_dlg * 1.3,
|
|
||||||
border=ft.border.all(1, 'black'),
|
|
||||||
border_radius=ft.border_radius.all(5),
|
|
||||||
on_click=self.reset,
|
|
||||||
bgcolor='yellow',
|
|
||||||
),
|
|
||||||
ft.Container(
|
|
||||||
content=ft.Text("Cancel", size=self.font_size * 0.8),
|
|
||||||
alignment=ft.alignment.center,
|
|
||||||
height=self.default_button_height_dlg * 0.8,
|
|
||||||
width=self.default_button_height_dlg * 1.3,
|
|
||||||
border=ft.border.all(1, 'black'),
|
|
||||||
border_radius=ft.border_radius.all(5),
|
|
||||||
on_click=self.cancel,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
ft.Divider(),
|
|
||||||
WuttaKeyboard(self.config, on_keypress=self.keypress,
|
|
||||||
on_long_backspace=self.long_backspace),
|
|
||||||
ft.Divider(),
|
|
||||||
ft.Row(
|
|
||||||
[
|
|
||||||
ft.Column(
|
|
||||||
[
|
|
||||||
self.search_results,
|
|
||||||
self.no_results,
|
|
||||||
],
|
|
||||||
expand=True,
|
|
||||||
),
|
|
||||||
self.select_button,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
def did_mount(self):
|
|
||||||
if self.initial_search:
|
|
||||||
self.searchbox.value = self.initial_search
|
|
||||||
self.initial_search = None # only do it once
|
|
||||||
self.update()
|
|
||||||
self.lookup()
|
|
||||||
|
|
||||||
def make_cell_text(self, text):
|
|
||||||
return ft.Text(text, size=32)
|
|
||||||
|
|
||||||
def make_cell(self, text):
|
|
||||||
return ft.DataCell(self.make_cell_text(text))
|
|
||||||
|
|
||||||
def cancel(self, e):
|
|
||||||
if self.on_cancel:
|
|
||||||
self.on_cancel(e)
|
|
||||||
|
|
||||||
def keypress(self, key):
|
|
||||||
if key == '⏎':
|
|
||||||
self.lookup()
|
|
||||||
else:
|
|
||||||
if key == '⌫':
|
|
||||||
self.searchbox.value = self.searchbox.value[:-1]
|
|
||||||
else:
|
|
||||||
self.searchbox.value += key
|
|
||||||
self.searchbox.focus()
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def long_backspace(self):
|
|
||||||
self.searchbox.value = self.searchbox.value[:-10]
|
|
||||||
self.searchbox.focus()
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def lookup(self, e=None):
|
|
||||||
entry = self.searchbox.value
|
|
||||||
if not entry:
|
|
||||||
self.searchbox.focus()
|
|
||||||
self.update()
|
|
||||||
return
|
|
||||||
|
|
||||||
session = self.app.make_session()
|
|
||||||
results = self.app.get_clientele_handler().search_customers(session, entry)
|
|
||||||
|
|
||||||
self.search_results.rows.clear()
|
|
||||||
self.selected_customer_uuid = None
|
|
||||||
self.select_button.disabled = True
|
|
||||||
self.select_button.bgcolor = self.disabled_bgcolor
|
|
||||||
|
|
||||||
if results:
|
|
||||||
for customer in results:
|
|
||||||
self.search_results.rows.append(ft.DataRow(
|
|
||||||
cells=[
|
|
||||||
self.make_cell(customer['_customer_key_']),
|
|
||||||
self.make_cell(customer['name']),
|
|
||||||
self.make_cell(customer['phone_number']),
|
|
||||||
self.make_cell(customer['email_address']),
|
|
||||||
],
|
|
||||||
on_select_changed=self.select_changed,
|
|
||||||
data={'uuid': customer['uuid']},
|
|
||||||
))
|
|
||||||
self.no_results.visible = False
|
|
||||||
|
|
||||||
else:
|
|
||||||
self.no_results.value = f"NO RESULTS FOR: {entry}"
|
|
||||||
self.no_results.visible = True
|
|
||||||
|
|
||||||
self.searchbox.focus()
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def reset(self, e):
|
|
||||||
self.searchbox.value = ""
|
|
||||||
self.search_results.rows.clear()
|
|
||||||
self.no_results.visible = False
|
|
||||||
self.selected_customer_uuid = None
|
|
||||||
self.select_button.disabled = True
|
|
||||||
self.select_button.bgcolor = self.disabled_bgcolor
|
|
||||||
self.searchbox.focus()
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def select_changed(self, e):
|
|
||||||
|
|
||||||
if e.data: # selected
|
|
||||||
if self.selected_control:
|
|
||||||
self.selected_control.color = None
|
|
||||||
self.selected_customer_uuid = e.control.data['uuid']
|
|
||||||
self.selected_control = e.control
|
|
||||||
self.selected_control.color = ft.colors.BLUE
|
|
||||||
self.select_button.disabled = False
|
|
||||||
self.select_button.bgcolor = 'blue'
|
|
||||||
else:
|
|
||||||
if self.selected_control:
|
|
||||||
self.selected_control.color = None
|
|
||||||
self.selected_control = None
|
|
||||||
self.selected_customer_uuid = None
|
|
||||||
self.select_button.disabled = True
|
|
||||||
self.select_button.bgcolor = self.disabled_bgcolor
|
|
||||||
e.control.color = None
|
|
||||||
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def select_customer(self, e):
|
|
||||||
if not self.selected_customer_uuid:
|
|
||||||
raise RuntimeError("no customer selected?")
|
|
||||||
if self.on_customer:
|
|
||||||
self.on_customer(self.selected_customer_uuid)
|
|
||||||
|
|
47
wuttapos/controls/itemlookup.py
Normal file
47
wuttapos/controls/itemlookup.py
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# WuttaPOS -- Pythonic Point of Sale System
|
||||||
|
# Copyright © 2023 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of WuttaPOS.
|
||||||
|
#
|
||||||
|
# WuttaPOS is free software: you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# WuttaPOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# WuttaPOS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
WuttaPOS - item lookup control
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .lookup import WuttaLookup
|
||||||
|
|
||||||
|
|
||||||
|
class WuttaProductLookup(WuttaLookup):
|
||||||
|
|
||||||
|
def get_results_columns(self):
|
||||||
|
return [
|
||||||
|
self.app.get_product_key_label(),
|
||||||
|
"Description",
|
||||||
|
"Price",
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_results(self, session, entry):
|
||||||
|
return self.app.get_products_handler().search_products(session, entry)
|
||||||
|
|
||||||
|
def make_result_row(self, product):
|
||||||
|
return [
|
||||||
|
product['product_key'],
|
||||||
|
product['full_description'],
|
||||||
|
product['unit_price_display'],
|
||||||
|
]
|
243
wuttapos/controls/lookup.py
Normal file
243
wuttapos/controls/lookup.py
Normal file
|
@ -0,0 +1,243 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# WuttaPOS -- Pythonic Point of Sale System
|
||||||
|
# Copyright © 2023 Lance Edgar
|
||||||
|
#
|
||||||
|
# This file is part of WuttaPOS.
|
||||||
|
#
|
||||||
|
# WuttaPOS is free software: you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# WuttaPOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# WuttaPOS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
WuttaPOS - base lookup control
|
||||||
|
"""
|
||||||
|
|
||||||
|
import flet as ft
|
||||||
|
|
||||||
|
from .base import WuttaControl
|
||||||
|
from .keyboard import WuttaKeyboard
|
||||||
|
|
||||||
|
|
||||||
|
class WuttaLookup(WuttaControl):
|
||||||
|
|
||||||
|
default_font_size = 40
|
||||||
|
font_size = default_font_size * 0.8
|
||||||
|
default_button_height_dlg = 80
|
||||||
|
disabled_bgcolor = '#aaaaaa'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.initial_search = kwargs.pop('initial_search', None)
|
||||||
|
self.on_select = kwargs.pop('on_select', None)
|
||||||
|
self.on_cancel = kwargs.pop('on_cancel', None)
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# track current selection
|
||||||
|
self.selected_uuid = None
|
||||||
|
self.selected_control = None
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
|
||||||
|
self.searchbox = ft.TextField("", text_size=self.font_size * 0.8,
|
||||||
|
on_submit=self.lookup,
|
||||||
|
autofocus=True,
|
||||||
|
expand=True)
|
||||||
|
|
||||||
|
self.search_results = ft.DataTable(
|
||||||
|
columns=[ft.DataColumn(self.make_cell_text(text))
|
||||||
|
for text in self.get_results_columns()],
|
||||||
|
)
|
||||||
|
|
||||||
|
self.no_results = ft.Text("NO RESULTS", size=32, color='red',
|
||||||
|
weight=ft.FontWeight.BOLD,
|
||||||
|
visible=False)
|
||||||
|
|
||||||
|
self.select_button = ft.Container(
|
||||||
|
content=ft.Text("Select", size=self.font_size * 0.8),
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
height=self.default_button_height_dlg * 0.8,
|
||||||
|
width=self.default_button_height_dlg * 1.3,
|
||||||
|
border=ft.border.all(1, 'black'),
|
||||||
|
border_radius=ft.border_radius.all(5),
|
||||||
|
on_click=self.select_object,
|
||||||
|
disabled=True,
|
||||||
|
bgcolor=self.disabled_bgcolor,
|
||||||
|
)
|
||||||
|
|
||||||
|
return ft.Column(
|
||||||
|
[
|
||||||
|
ft.Row(
|
||||||
|
[
|
||||||
|
ft.Text("SEARCH FOR:"),
|
||||||
|
self.searchbox,
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Text("Lookup", size=self.font_size * 0.8),
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
height=self.default_button_height_dlg * 0.8,
|
||||||
|
width=self.default_button_height_dlg * 1.3,
|
||||||
|
border=ft.border.all(1, 'black'),
|
||||||
|
border_radius=ft.border_radius.all(5),
|
||||||
|
on_click=self.lookup,
|
||||||
|
bgcolor='blue',
|
||||||
|
),
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Text("Reset", size=self.font_size * 0.8),
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
height=self.default_button_height_dlg * 0.8,
|
||||||
|
width=self.default_button_height_dlg * 1.3,
|
||||||
|
border=ft.border.all(1, 'black'),
|
||||||
|
border_radius=ft.border_radius.all(5),
|
||||||
|
on_click=self.reset,
|
||||||
|
bgcolor='yellow',
|
||||||
|
),
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Text("Cancel", size=self.font_size * 0.8),
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
height=self.default_button_height_dlg * 0.8,
|
||||||
|
width=self.default_button_height_dlg * 1.3,
|
||||||
|
border=ft.border.all(1, 'black'),
|
||||||
|
border_radius=ft.border_radius.all(5),
|
||||||
|
on_click=self.cancel,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
ft.Divider(),
|
||||||
|
WuttaKeyboard(self.config, on_keypress=self.keypress,
|
||||||
|
on_long_backspace=self.long_backspace),
|
||||||
|
ft.Divider(),
|
||||||
|
ft.Row(
|
||||||
|
[
|
||||||
|
ft.Column(
|
||||||
|
[
|
||||||
|
self.search_results,
|
||||||
|
self.no_results,
|
||||||
|
],
|
||||||
|
expand=True,
|
||||||
|
),
|
||||||
|
self.select_button,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_results_columns(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def did_mount(self):
|
||||||
|
if self.initial_search:
|
||||||
|
self.searchbox.value = self.initial_search
|
||||||
|
self.initial_search = None # only do it once
|
||||||
|
self.update()
|
||||||
|
self.lookup()
|
||||||
|
|
||||||
|
def make_cell_text(self, text):
|
||||||
|
return ft.Text(text, size=32)
|
||||||
|
|
||||||
|
def make_cell(self, text):
|
||||||
|
return ft.DataCell(self.make_cell_text(text))
|
||||||
|
|
||||||
|
def cancel(self, e):
|
||||||
|
if self.on_cancel:
|
||||||
|
self.on_cancel(e)
|
||||||
|
|
||||||
|
def keypress(self, key):
|
||||||
|
if key == '⏎':
|
||||||
|
self.lookup()
|
||||||
|
else:
|
||||||
|
if key == '⌫':
|
||||||
|
self.searchbox.value = self.searchbox.value[:-1]
|
||||||
|
else:
|
||||||
|
self.searchbox.value += key
|
||||||
|
self.searchbox.focus()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def long_backspace(self):
|
||||||
|
self.searchbox.value = self.searchbox.value[:-10]
|
||||||
|
self.searchbox.focus()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def get_results(self, session, entry):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def make_result_row(self, obj):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def lookup(self, e=None):
|
||||||
|
entry = self.searchbox.value
|
||||||
|
if not entry:
|
||||||
|
self.searchbox.focus()
|
||||||
|
self.update()
|
||||||
|
return
|
||||||
|
|
||||||
|
session = self.app.make_session()
|
||||||
|
results = self.get_results(session, entry)
|
||||||
|
|
||||||
|
self.search_results.rows.clear()
|
||||||
|
self.selected_uuid = None
|
||||||
|
self.select_button.disabled = True
|
||||||
|
self.select_button.bgcolor = self.disabled_bgcolor
|
||||||
|
|
||||||
|
if results:
|
||||||
|
for obj in results:
|
||||||
|
self.search_results.rows.append(ft.DataRow(
|
||||||
|
cells=[self.make_cell(row)
|
||||||
|
for row in self.make_result_row(obj)],
|
||||||
|
on_select_changed=self.select_changed,
|
||||||
|
data={'uuid': obj['uuid']},
|
||||||
|
))
|
||||||
|
self.no_results.visible = False
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.no_results.value = f"NO RESULTS FOR: {entry}"
|
||||||
|
self.no_results.visible = True
|
||||||
|
|
||||||
|
self.searchbox.focus()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def reset(self, e):
|
||||||
|
self.searchbox.value = ""
|
||||||
|
self.search_results.rows.clear()
|
||||||
|
self.no_results.visible = False
|
||||||
|
self.selected_uuid = None
|
||||||
|
self.select_button.disabled = True
|
||||||
|
self.select_button.bgcolor = self.disabled_bgcolor
|
||||||
|
self.searchbox.focus()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def select_changed(self, e):
|
||||||
|
|
||||||
|
if e.data: # selected
|
||||||
|
if self.selected_control:
|
||||||
|
self.selected_control.color = None
|
||||||
|
self.selected_uuid = e.control.data['uuid']
|
||||||
|
self.selected_control = e.control
|
||||||
|
self.selected_control.color = ft.colors.BLUE
|
||||||
|
self.select_button.disabled = False
|
||||||
|
self.select_button.bgcolor = 'blue'
|
||||||
|
else:
|
||||||
|
if self.selected_control:
|
||||||
|
self.selected_control.color = None
|
||||||
|
self.selected_control = None
|
||||||
|
self.selected_uuid = None
|
||||||
|
self.select_button.disabled = True
|
||||||
|
self.select_button.bgcolor = self.disabled_bgcolor
|
||||||
|
e.control.color = None
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def select_object(self, e):
|
||||||
|
if not self.selected_uuid:
|
||||||
|
raise RuntimeError("no record selected?")
|
||||||
|
if self.on_select:
|
||||||
|
self.on_select(self.selected_uuid)
|
|
@ -32,6 +32,7 @@ import flet as ft
|
||||||
|
|
||||||
from .base import WuttaView
|
from .base import WuttaView
|
||||||
from wuttapos.controls.custlookup import WuttaCustomerLookup
|
from wuttapos.controls.custlookup import WuttaCustomerLookup
|
||||||
|
from wuttapos.controls.itemlookup import WuttaProductLookup
|
||||||
from wuttapos.util import get_pos_batch_handler
|
from wuttapos.util import get_pos_batch_handler
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ class POSView(WuttaView):
|
||||||
def get_batch_handler(self):
|
def get_batch_handler(self):
|
||||||
return get_pos_batch_handler(self.config)
|
return get_pos_batch_handler(self.config)
|
||||||
|
|
||||||
def reset(self, e=None, update=True):
|
def reset(self, e=None, clear_quantity=True, update=True):
|
||||||
"""
|
"""
|
||||||
This is a convenience method, meant only to clear the main
|
This is a convenience method, meant only to clear the main
|
||||||
input and set focus to it. Will also update() the page
|
input and set focus to it. Will also update() the page
|
||||||
|
@ -75,8 +76,9 @@ class POSView(WuttaView):
|
||||||
The ``e`` arg is ignored and accepted only so this method may
|
The ``e`` arg is ignored and accepted only so this method may
|
||||||
be registered as an event handler, e.g. ``on_cancel``.
|
be registered as an event handler, e.g. ``on_cancel``.
|
||||||
"""
|
"""
|
||||||
self.set_quantity.data = None
|
if clear_quantity:
|
||||||
self.set_quantity.value = None
|
self.set_quantity.data = None
|
||||||
|
self.set_quantity.value = None
|
||||||
self.main_input.value = ''
|
self.main_input.value = ''
|
||||||
self.main_input.focus()
|
self.main_input.focus()
|
||||||
if update:
|
if update:
|
||||||
|
@ -102,9 +104,78 @@ class POSView(WuttaView):
|
||||||
duration=1500)
|
duration=1500)
|
||||||
self.page.snack_bar.open = True
|
self.page.snack_bar.open = True
|
||||||
|
|
||||||
|
def item_click(self, e):
|
||||||
|
|
||||||
|
value = self.main_input.value
|
||||||
|
if value:
|
||||||
|
if not self.attempt_add_product():
|
||||||
|
self.item_lookup(value)
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.item_lookup()
|
||||||
|
|
||||||
|
def attempt_add_product(self, uuid=None):
|
||||||
|
session = self.app.make_session()
|
||||||
|
handler = self.get_batch_handler()
|
||||||
|
batch = self.get_current_batch(session)
|
||||||
|
entry = self.main_input.value
|
||||||
|
|
||||||
|
kw = {}
|
||||||
|
if self.set_quantity.data is not None:
|
||||||
|
kw['quantity'] = self.set_quantity.data
|
||||||
|
|
||||||
|
product = None
|
||||||
|
if uuid:
|
||||||
|
product = session.get(self.model.Product, uuid)
|
||||||
|
assert product
|
||||||
|
|
||||||
|
row = handler.process_entry(batch, product or entry, **kw)
|
||||||
|
|
||||||
|
if row:
|
||||||
|
session.commit()
|
||||||
|
self.add_row_item(row)
|
||||||
|
self.items.scroll_to(offset=-1, duration=250)
|
||||||
|
self.txn_total.value = self.app.render_currency(batch.sales_total)
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.page.snack_bar = ft.SnackBar(ft.Text(f"PRODUCT NOT FOUND: {entry}",
|
||||||
|
color='black',
|
||||||
|
weight=ft.FontWeight.BOLD),
|
||||||
|
bgcolor='yellow',
|
||||||
|
duration=1500)
|
||||||
|
self.page.snack_bar.open = True
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
session.close()
|
||||||
|
self.page.update()
|
||||||
|
return bool(row)
|
||||||
|
|
||||||
|
def item_lookup(self, value=None):
|
||||||
|
|
||||||
|
def select(uuid):
|
||||||
|
self.attempt_add_product(uuid=uuid)
|
||||||
|
dlg.open = False
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def cancel(e):
|
||||||
|
dlg.open = False
|
||||||
|
self.reset(clear_quantity=False)
|
||||||
|
|
||||||
|
dlg = ft.AlertDialog(
|
||||||
|
modal=True,
|
||||||
|
title=ft.Text("Product Lookup"),
|
||||||
|
content=WuttaProductLookup(self.config, initial_search=value,
|
||||||
|
on_select=select, on_cancel=cancel),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.page.dialog = dlg
|
||||||
|
dlg.open = True
|
||||||
|
self.page.update()
|
||||||
|
|
||||||
def customer_lookup(self, value=None):
|
def customer_lookup(self, value=None):
|
||||||
|
|
||||||
def select_customer(uuid):
|
def select(uuid):
|
||||||
session = self.app.make_session()
|
session = self.app.make_session()
|
||||||
customer = session.get(self.model.Customer, uuid)
|
customer = session.get(self.model.Customer, uuid)
|
||||||
self.set_customer(customer)
|
self.set_customer(customer)
|
||||||
|
@ -122,7 +193,7 @@ class POSView(WuttaView):
|
||||||
modal=True,
|
modal=True,
|
||||||
title=ft.Text("Customer Lookup"),
|
title=ft.Text("Customer Lookup"),
|
||||||
content=WuttaCustomerLookup(self.config, initial_search=value,
|
content=WuttaCustomerLookup(self.config, initial_search=value,
|
||||||
on_customer=select_customer, on_cancel=cancel),
|
on_select=select, on_cancel=cancel),
|
||||||
)
|
)
|
||||||
|
|
||||||
self.page.dialog = dlg
|
self.page.dialog = dlg
|
||||||
|
@ -579,7 +650,7 @@ class POSView(WuttaView):
|
||||||
),
|
),
|
||||||
ft.Row(
|
ft.Row(
|
||||||
[
|
[
|
||||||
meta_button("ITEM", bgcolor='blue', on_click=self.not_supported),
|
meta_button("ITEM", bgcolor='blue', on_click=self.item_click),
|
||||||
meta_button("CUST", bgcolor='blue', on_click=self.customer_click),
|
meta_button("CUST", bgcolor='blue', on_click=self.customer_click),
|
||||||
],
|
],
|
||||||
spacing=0,
|
spacing=0,
|
||||||
|
@ -682,10 +753,18 @@ class POSView(WuttaView):
|
||||||
return ft.Text(*args, **kwargs)
|
return ft.Text(*args, **kwargs)
|
||||||
|
|
||||||
def get_current_batch(self, session, user=None, create=True):
|
def get_current_batch(self, session, user=None, create=True):
|
||||||
|
handler = self.get_batch_handler()
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
user = session.get(self.model.User, self.page.session.get('user_uuid'))
|
user = session.get(self.model.User, self.page.session.get('user_uuid'))
|
||||||
handler = self.get_batch_handler()
|
|
||||||
return handler.get_current_batch(user, create=create)
|
batch, created = handler.get_current_batch(user, create=create, return_created=True)
|
||||||
|
|
||||||
|
if created:
|
||||||
|
self.page.session.set('txn_display', handler.get_screen_txn_display(batch))
|
||||||
|
self.informed_refresh()
|
||||||
|
|
||||||
|
return batch
|
||||||
|
|
||||||
def did_mount(self):
|
def did_mount(self):
|
||||||
session = self.app.make_session()
|
session = self.app.make_session()
|
||||||
|
@ -850,40 +929,5 @@ class POSView(WuttaView):
|
||||||
self.informed_refresh()
|
self.informed_refresh()
|
||||||
|
|
||||||
def main_submit(self, e=None):
|
def main_submit(self, e=None):
|
||||||
value = self.main_input.value
|
self.attempt_add_product()
|
||||||
if not value:
|
|
||||||
self.main_input.focus()
|
|
||||||
self.items.scroll_to(offset=-1, duration=250)
|
|
||||||
self.page.update()
|
|
||||||
return
|
|
||||||
|
|
||||||
handler = self.get_batch_handler()
|
|
||||||
session = self.app.make_session()
|
|
||||||
model = self.model
|
|
||||||
|
|
||||||
user = session.get(model.User, self.page.session.get('user_uuid'))
|
|
||||||
batch, created = handler.get_current_batch(user, return_created=True)
|
|
||||||
if created:
|
|
||||||
self.page.session.set('txn_display', handler.get_screen_txn_display(batch))
|
|
||||||
self.informed_refresh()
|
|
||||||
|
|
||||||
kwargs = {}
|
|
||||||
if self.set_quantity.data is not None:
|
|
||||||
kwargs['quantity'] = self.set_quantity.data
|
|
||||||
row = handler.process_entry(batch, value, **kwargs)
|
|
||||||
if row:
|
|
||||||
self.add_row_item(row)
|
|
||||||
self.items.scroll_to(offset=-1, duration=250)
|
|
||||||
self.txn_total.value = self.app.render_currency(batch.sales_total)
|
|
||||||
|
|
||||||
else:
|
|
||||||
self.page.snack_bar = ft.SnackBar(ft.Text(f"UNRECOGNIZED: {value}",
|
|
||||||
color='black',
|
|
||||||
weight=ft.FontWeight.BOLD),
|
|
||||||
bgcolor='yellow',
|
|
||||||
duration=1500)
|
|
||||||
self.page.snack_bar.open = True
|
|
||||||
|
|
||||||
session.commit()
|
|
||||||
session.close()
|
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
Loading…
Reference in a new issue