feat: add support for dynamic context menu

also add pos cmd, `item_menu_dept` - so a custom button can present
list of items for a given department
This commit is contained in:
Lance Edgar 2024-07-09 19:37:42 -05:00
parent 8fe4c94005
commit e2e4df4721
9 changed files with 162 additions and 66 deletions

View file

@ -1,27 +0,0 @@
# -*- coding: utf-8; -*-
################################################################################
#
# WuttaPOS -- Pythonic Point of Sale System
# Copyright © 2023-2024 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 - buttons
"""
from .base import make_button, WuttaButton, WuttaButtonRow

View file

@ -0,0 +1,69 @@
# -*- coding: utf-8; -*-
################################################################################
#
# WuttaPOS -- Pythonic Point of Sale System
# Copyright © 2023-2024 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 for department
"""
from .itemlookup import WuttaProductLookup
class WuttaProductLookupByDepartment(WuttaProductLookup):
def __init__(self, config, department, *args, **kwargs):
# nb. this forces first query
kwargs.setdefault('initial_search', True)
kwargs.setdefault('show_search', False)
super().__init__(config, *args, **kwargs)
model = self.app.model
if isinstance(department, model.Department):
self.department_key = department.uuid
else:
self.department_key = department
# TODO: should somehow combine these 2 approaches, so the user can
# still filter items within a department
# def get_results(self, session, entry):
# return self.app.get_products_handler().search_products(session, entry)
def get_results(self, session, entry):
org = self.app.get_org_handler()
prod = self.app.get_products_handler()
model = self.app.model
department = org.get_department(session, self.department_key)
if not department:
raise ValueError(f"department not found: {self.department_key}")
products = session.query(model.Product)\
.filter(model.Product.department == department)\
.all()
products = [prod.normalize_product(p)
for p in products]
return products

View file

@ -26,7 +26,7 @@ WuttaPOS - button menus
import flet as ft import flet as ft
from wuttapos.controls.buttons import make_button from wuttapos.controls.buttons import make_button, WuttaButtonRow
class WuttaMenu(ft.Container): class WuttaMenu(ft.Container):
@ -58,3 +58,6 @@ class WuttaMenu(ft.Container):
kwargs.setdefault('width', self.default_button_size * 2) kwargs.setdefault('width', self.default_button_size * 2)
kwargs.setdefault('pos', self.pos) kwargs.setdefault('pos', self.pos)
return make_button(*args, **kwargs) return make_button(*args, **kwargs)
def make_button_row(self, *args, **kwargs):
return WuttaButtonRow(*args, **kwargs)

View file

@ -25,33 +25,9 @@ WuttaPOS - "context" menu
""" """
from .base import WuttaMenu from .base import WuttaMenu
from wuttapos.controls.buttons import WuttaButtonRow
class WuttaContextMenu(WuttaMenu): class WuttaContextMenu(WuttaMenu):
def build_controls(self): def build_controls(self):
return [ return []
WuttaButtonRow([
self.make_button("Cash",
bgcolor='orange',
pos_cmd='tender',
pos_cmd_kwargs={'tender': {'code': 'CA'}}),
self.make_button("Check",
bgcolor='orange',
pos_cmd='tender',
pos_cmd_kwargs={'tender': {'code': 'CK'}}),
]),
WuttaButtonRow([
self.make_button("Food Stamps",
bgcolor='orange',
font_size=34,
pos_cmd='tender',
pos_cmd_kwargs={'tender': {'code': 'FS'}}),
]),
]

View file

@ -21,18 +21,17 @@
# #
################################################################################ ################################################################################
""" """
WuttaPOS - buttons WuttaPOS - menus master control
""" """
import flet as ft import flet as ft
from wuttapos.controls.menus.tenkey import WuttaTenkeyMenu from wuttapos.controls.menus.tenkey import WuttaTenkeyMenu
from wuttapos.controls.menus.meta import WuttaMetaMenu from wuttapos.controls.menus.meta import WuttaMetaMenu
from wuttapos.controls.menus.context import WuttaContextMenu
from wuttapos.controls.menus.suspend import WuttaSuspendMenu from wuttapos.controls.menus.suspend import WuttaSuspendMenu
class WuttaButtonsMaster(ft.Column): class WuttaMenuMaster(ft.Column):
""" """
Base class and default implementation for "buttons master" Base class and default implementation for "buttons master"
control. This represents the overall button area in POS view. control. This represents the overall button area in POS view.
@ -113,7 +112,15 @@ class WuttaButtonsMaster(ft.Column):
############################## ##############################
def build_context_menu(self): def build_context_menu(self):
return WuttaContextMenu(self.config, pos=self.pos) spec = self.config.get('wuttapos.menus.context.spec',
default='wuttapos.controls.menus.context:WuttaContextMenu')
factory = self.app.load_object(spec)
return factory(self.config, pos=self.pos)
def replace_context_menu(self, menu):
controls = menu.build_controls()
self.context_menu.content.controls = controls
self.update()
############################## ##############################
# suspend # suspend

View file

@ -25,7 +25,6 @@ WuttaPOS - "meta" menu
""" """
from .base import WuttaMenu from .base import WuttaMenu
from wuttapos.controls.buttons import WuttaButtonRow
class WuttaMetaMenu(WuttaMenu): class WuttaMetaMenu(WuttaMenu):
@ -33,7 +32,7 @@ class WuttaMetaMenu(WuttaMenu):
def build_controls(self): def build_controls(self):
return [ return [
WuttaButtonRow([ self.make_button_row([
self.make_button("CUST", self.make_button("CUST",
bgcolor='blue', bgcolor='blue',
@ -44,7 +43,7 @@ class WuttaMetaMenu(WuttaMenu):
pos_cmd='void_dwim'), pos_cmd='void_dwim'),
]), ]),
WuttaButtonRow([ self.make_button_row([
self.make_button("ITEM", self.make_button("ITEM",
bgcolor='blue', bgcolor='blue',
@ -55,7 +54,7 @@ class WuttaMetaMenu(WuttaMenu):
pos_cmd='manager_dwim'), pos_cmd='manager_dwim'),
]), ]),
WuttaButtonRow([ self.make_button_row([
self.make_button("OPEN RING", self.make_button("OPEN RING",
font_size=32, font_size=32,
@ -67,7 +66,7 @@ class WuttaMetaMenu(WuttaMenu):
pos_cmd='no_sale_dwim'), pos_cmd='no_sale_dwim'),
]), ]),
WuttaButtonRow([ self.make_button_row([
self.make_button("Adjust\nPrice", self.make_button("Adjust\nPrice",
font_size=30, font_size=30,

View file

@ -25,7 +25,6 @@ WuttaPOS - "suspend" menu
""" """
from .base import WuttaMenu from .base import WuttaMenu
from wuttapos.controls.buttons import WuttaButtonRow
class WuttaSuspendMenu(WuttaMenu): class WuttaSuspendMenu(WuttaMenu):
@ -33,7 +32,7 @@ class WuttaSuspendMenu(WuttaMenu):
def build_controls(self): def build_controls(self):
return [ return [
WuttaButtonRow([ self.make_button_row([
self.make_button("SUSPEND", self.make_button("SUSPEND",
bgcolor='purple', bgcolor='purple',
@ -43,4 +42,26 @@ class WuttaSuspendMenu(WuttaMenu):
bgcolor='purple', bgcolor='purple',
pos_cmd='resume_txn'), pos_cmd='resume_txn'),
]), ]),
self.make_button_row([
self.make_button("Cash",
bgcolor='orange',
pos_cmd='tender',
pos_cmd_kwargs={'tender': {'code': 'CA'}}),
self.make_button("Check",
bgcolor='orange',
pos_cmd='tender',
pos_cmd_kwargs={'tender': {'code': 'CK'}}),
]),
self.make_button_row([
self.make_button("Food Stamps",
bgcolor='orange',
font_size=34,
pos_cmd='tender',
pos_cmd_kwargs={'tender': {'code': 'FS'}}),
]),
] ]

View file

@ -34,11 +34,11 @@ from .base import WuttaView
from wuttapos.controls.loginform import WuttaLoginForm from wuttapos.controls.loginform import WuttaLoginForm
from wuttapos.controls.custlookup import WuttaCustomerLookup from wuttapos.controls.custlookup import WuttaCustomerLookup
from wuttapos.controls.itemlookup import WuttaProductLookup from wuttapos.controls.itemlookup import WuttaProductLookup
from wuttapos.controls.itemlookup_dept import WuttaProductLookupByDepartment
from wuttapos.controls.deptlookup import WuttaDepartmentLookup from wuttapos.controls.deptlookup import WuttaDepartmentLookup
from wuttapos.controls.txnlookup import WuttaTransactionLookup from wuttapos.controls.txnlookup import WuttaTransactionLookup
from wuttapos.controls.txnitem import WuttaTxnItem from wuttapos.controls.txnitem import WuttaTxnItem
from wuttapos.controls.menus.tenkey import WuttaTenkeyMenu from wuttapos.controls.menus.tenkey import WuttaTenkeyMenu
from wuttapos.controls.buttons.master import WuttaButtonsMaster
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -568,6 +568,11 @@ class POSView(WuttaView):
bgcolor='green', bgcolor='green',
on_click=self.set_quantity_click) on_click=self.set_quantity_click)
spec = self.config.get('wuttapos.menus.master.spec',
default='wuttapos.controls.menus.master:WuttaMenuMaster')
factory = self.app.load_object(spec)
self.menu_master = factory(self.config, pos=self)
return [ return [
self.build_header(), self.build_header(),
@ -603,7 +608,7 @@ class POSView(WuttaView):
ft.Row( ft.Row(
[ [
self.items_column, self.items_column,
WuttaButtonsMaster(self.config, pos=self), self.menu_master,
], ],
vertical_alignment=ft.CrossAxisAlignment.START, vertical_alignment=ft.CrossAxisAlignment.START,
), ),
@ -1091,6 +1096,15 @@ class POSView(WuttaView):
self.authorized_action('pos.override_price', self.adjust_price, self.authorized_action('pos.override_price', self.adjust_price,
message="Adjust Price") message="Adjust Price")
def cmd_context_menu(self, entry=None, **kwargs):
"""
Swap out which context menu is currently shown.
"""
spec = self.config.require(f'wuttapos.menus.{entry}.spec')
factory = self.app.load_object(spec)
menu = factory(self.config, pos=self)
self.menu_master.replace_context_menu(menu)
def cmd_customer_dwim(self, entry=None, **kwargs): def cmd_customer_dwim(self, entry=None, **kwargs):
# prompt user to replace customer if already set # prompt user to replace customer if already set
@ -1139,6 +1153,40 @@ class POSView(WuttaView):
else: else:
self.item_lookup() self.item_lookup()
def cmd_item_menu_dept(self, entry=None, **kwargs):
"""
Show item lookup dialog, restricted to the given department.
"""
key = entry
if not key:
raise ValueError("must specify department key")
org = self.app.get_org_handler()
session = self.app.make_session()
department = org.get_department(session, key)
session.close()
if not department:
raise ValueError(f"department not found: {key}")
def select(uuid):
self.attempt_add_product(uuid=uuid)
dlg.open = False
self.reset()
def cancel(e):
dlg.open = False
self.reset()
dlg = ft.AlertDialog(
title=ft.Text(f"Item from Department: {department.name}"),
content=WuttaProductLookupByDepartment(self.config, department,
page=self.page,
on_select=select,
on_cancel=cancel),
)
self.page.open(dlg)
def cmd_manager_dwim(self, entry=None, **kwargs): def cmd_manager_dwim(self, entry=None, **kwargs):
def toggle_training(e): def toggle_training(e):