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
from wuttapos.controls.buttons import make_button
from wuttapos.controls.buttons import make_button, WuttaButtonRow
class WuttaMenu(ft.Container):
@ -58,3 +58,6 @@ class WuttaMenu(ft.Container):
kwargs.setdefault('width', self.default_button_size * 2)
kwargs.setdefault('pos', self.pos)
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 wuttapos.controls.buttons import WuttaButtonRow
class WuttaContextMenu(WuttaMenu):
def build_controls(self):
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'}}),
]),
]
return []

View file

@ -21,18 +21,17 @@
#
################################################################################
"""
WuttaPOS - buttons
WuttaPOS - menus master control
"""
import flet as ft
from wuttapos.controls.menus.tenkey import WuttaTenkeyMenu
from wuttapos.controls.menus.meta import WuttaMetaMenu
from wuttapos.controls.menus.context import WuttaContextMenu
from wuttapos.controls.menus.suspend import WuttaSuspendMenu
class WuttaButtonsMaster(ft.Column):
class WuttaMenuMaster(ft.Column):
"""
Base class and default implementation for "buttons master"
control. This represents the overall button area in POS view.
@ -113,7 +112,15 @@ class WuttaButtonsMaster(ft.Column):
##############################
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

View file

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

View file

@ -25,7 +25,6 @@ WuttaPOS - "suspend" menu
"""
from .base import WuttaMenu
from wuttapos.controls.buttons import WuttaButtonRow
class WuttaSuspendMenu(WuttaMenu):
@ -33,7 +32,7 @@ class WuttaSuspendMenu(WuttaMenu):
def build_controls(self):
return [
WuttaButtonRow([
self.make_button_row([
self.make_button("SUSPEND",
bgcolor='purple',
@ -43,4 +42,26 @@ class WuttaSuspendMenu(WuttaMenu):
bgcolor='purple',
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.custlookup import WuttaCustomerLookup
from wuttapos.controls.itemlookup import WuttaProductLookup
from wuttapos.controls.itemlookup_dept import WuttaProductLookupByDepartment
from wuttapos.controls.deptlookup import WuttaDepartmentLookup
from wuttapos.controls.txnlookup import WuttaTransactionLookup
from wuttapos.controls.txnitem import WuttaTxnItem
from wuttapos.controls.menus.tenkey import WuttaTenkeyMenu
from wuttapos.controls.buttons.master import WuttaButtonsMaster
log = logging.getLogger(__name__)
@ -568,6 +568,11 @@ class POSView(WuttaView):
bgcolor='green',
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 [
self.build_header(),
@ -603,7 +608,7 @@ class POSView(WuttaView):
ft.Row(
[
self.items_column,
WuttaButtonsMaster(self.config, pos=self),
self.menu_master,
],
vertical_alignment=ft.CrossAxisAlignment.START,
),
@ -1091,6 +1096,15 @@ class POSView(WuttaView):
self.authorized_action('pos.override_price', self.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):
# prompt user to replace customer if already set
@ -1139,6 +1153,40 @@ class POSView(WuttaView):
else:
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 toggle_training(e):