Add initial support for Open Ring
This commit is contained in:
parent
fb4206e5a9
commit
2c9f3cd41a
67
wuttapos/controls/deptlookup.py
Normal file
67
wuttapos/controls/deptlookup.py
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# -*- 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 - department lookup control
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .lookup import WuttaLookup
|
||||||
|
|
||||||
|
|
||||||
|
class WuttaDepartmentLookup(WuttaLookup):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
# nb. this forces first query
|
||||||
|
kwargs.setdefault('initial_search', '')
|
||||||
|
kwargs.setdefault('allow_empty_query', True)
|
||||||
|
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_results_columns(self):
|
||||||
|
return [
|
||||||
|
"Number",
|
||||||
|
"Name",
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_results(self, session, entry):
|
||||||
|
model = self.app.model
|
||||||
|
query = session.query(model.Department)\
|
||||||
|
.order_by(model.Department.number)
|
||||||
|
|
||||||
|
if entry:
|
||||||
|
query = query.filter(model.Department.name.ilike(f'%{entry}%'))
|
||||||
|
|
||||||
|
departments = []
|
||||||
|
for dept in query:
|
||||||
|
departments.append({
|
||||||
|
'uuid': dept.uuid,
|
||||||
|
'number': str(dept.number),
|
||||||
|
'name': dept.name,
|
||||||
|
})
|
||||||
|
return departments
|
||||||
|
|
||||||
|
def make_result_row(self, dept):
|
||||||
|
return [
|
||||||
|
dept['number'],
|
||||||
|
dept['name'],
|
||||||
|
]
|
|
@ -41,6 +41,7 @@ class WuttaLookup(WuttaControl):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.initial_search = kwargs.pop('initial_search', None)
|
self.initial_search = kwargs.pop('initial_search', None)
|
||||||
|
self.allow_empty_query = kwargs.pop('allow_empty_query', False)
|
||||||
self.on_select = kwargs.pop('on_select', None)
|
self.on_select = kwargs.pop('on_select', None)
|
||||||
self.on_cancel = kwargs.pop('on_cancel', None)
|
self.on_cancel = kwargs.pop('on_cancel', None)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
@ -165,7 +166,7 @@ class WuttaLookup(WuttaControl):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def did_mount(self):
|
def did_mount(self):
|
||||||
if self.initial_search:
|
if self.initial_search is not None:
|
||||||
self.searchbox.value = self.initial_search
|
self.searchbox.value = self.initial_search
|
||||||
self.initial_search = None # only do it once
|
self.initial_search = None # only do it once
|
||||||
self.update()
|
self.update()
|
||||||
|
@ -201,11 +202,11 @@ class WuttaLookup(WuttaControl):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def make_result_row(self, obj):
|
def make_result_row(self, obj):
|
||||||
raise NotImplementedError
|
return obj
|
||||||
|
|
||||||
def lookup(self, e=None):
|
def lookup(self, e=None):
|
||||||
entry = self.searchbox.value
|
entry = self.searchbox.value
|
||||||
if not entry:
|
if not entry and not self.allow_empty_query:
|
||||||
self.searchbox.focus()
|
self.searchbox.focus()
|
||||||
self.update()
|
self.update()
|
||||||
return
|
return
|
||||||
|
|
|
@ -48,7 +48,8 @@ class WuttaTxnItem(WuttaControl):
|
||||||
self.minor_style = ft.TextStyle(size=int(self.font_size * 0.8),
|
self.minor_style = ft.TextStyle(size=int(self.font_size * 0.8),
|
||||||
italic=True)
|
italic=True)
|
||||||
|
|
||||||
if self.row.row_type == self.enum.POS_ROW_TYPE_SELL:
|
if self.row.row_type in (self.enum.POS_ROW_TYPE_SELL,
|
||||||
|
self.enum.POS_ROW_TYPE_OPEN_RING):
|
||||||
return self.build_item_sell()
|
return self.build_item_sell()
|
||||||
|
|
||||||
elif self.row.row_type in (self.enum.POS_ROW_TYPE_TENDER,
|
elif self.row.row_type in (self.enum.POS_ROW_TYPE_TENDER,
|
||||||
|
@ -129,7 +130,8 @@ class WuttaTxnItem(WuttaControl):
|
||||||
self.minor_style.color = None
|
self.minor_style.color = None
|
||||||
self.minor_style.decoration = None
|
self.minor_style.decoration = None
|
||||||
|
|
||||||
if self.row.row_type == self.enum.POS_ROW_TYPE_SELL:
|
if self.row.row_type in (self.enum.POS_ROW_TYPE_SELL,
|
||||||
|
self.enum.POS_ROW_TYPE_OPEN_RING):
|
||||||
self.quantity.text = self.app.render_quantity(self.row.quantity)
|
self.quantity.text = self.app.render_quantity(self.row.quantity)
|
||||||
self.txn_price.text = self.app.render_currency(self.row.txn_price)
|
self.txn_price.text = self.app.render_currency(self.row.txn_price)
|
||||||
self.sales_total.text = self.app.render_currency(self.row.sales_total)
|
self.sales_total.text = self.app.render_currency(self.row.sales_total)
|
||||||
|
@ -140,7 +142,8 @@ class WuttaTxnItem(WuttaControl):
|
||||||
self.sales_total_style.decoration = ft.TextDecoration.LINE_THROUGH
|
self.sales_total_style.decoration = ft.TextDecoration.LINE_THROUGH
|
||||||
self.sales_total_style.weight = None
|
self.sales_total_style.weight = None
|
||||||
else:
|
else:
|
||||||
if self.row.txn_price < self.row.reg_price:
|
if (self.row.row_type == self.enum.POS_ROW_TYPE_SELL
|
||||||
|
and self.row.txn_price < self.row.reg_price):
|
||||||
self.sales_total_style.color = 'blue'
|
self.sales_total_style.color = 'blue'
|
||||||
else:
|
else:
|
||||||
self.sales_total_style.color = None
|
self.sales_total_style.color = None
|
||||||
|
|
|
@ -34,6 +34,7 @@ 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.deptlookup import WuttaDepartmentLookup
|
||||||
from wuttapos.controls.txnitem import WuttaTxnItem
|
from wuttapos.controls.txnitem import WuttaTxnItem
|
||||||
from wuttapos.controls.tenkey import WuttaTenkeyMenu
|
from wuttapos.controls.tenkey import WuttaTenkeyMenu
|
||||||
|
|
||||||
|
@ -168,8 +169,7 @@ class POSView(WuttaView):
|
||||||
bgcolor='yellow')
|
bgcolor='yellow')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.add_row_item(row)
|
self.add_row_item(row, scroll=True)
|
||||||
self.items.scroll_to(offset=-1, duration=100)
|
|
||||||
self.refresh_totals(batch)
|
self.refresh_totals(batch)
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
|
@ -657,15 +657,16 @@ class POSView(WuttaView):
|
||||||
),
|
),
|
||||||
ft.Row(
|
ft.Row(
|
||||||
[
|
[
|
||||||
meta_button("Adjust\nPrice", font_size=30, bgcolor='yellow',
|
meta_button("OPEN RING", font_size=32, bgcolor='blue',
|
||||||
on_click=self.adjust_price_click),
|
on_click=self.open_ring_click),
|
||||||
meta_button("NO SALE", bgcolor='yellow', on_click=self.nosale_click),
|
meta_button("NO SALE", bgcolor='yellow', on_click=self.nosale_click),
|
||||||
],
|
],
|
||||||
spacing=0,
|
spacing=0,
|
||||||
),
|
),
|
||||||
ft.Row(
|
ft.Row(
|
||||||
[
|
[
|
||||||
meta_button("TODO", bgcolor='blue', on_click=self.not_supported),
|
meta_button("Adjust\nPrice", font_size=30, bgcolor='yellow',
|
||||||
|
on_click=self.adjust_price_click),
|
||||||
meta_button("(TEST ERROR)", bgcolor='red', on_click=self.not_supported,
|
meta_button("(TEST ERROR)", bgcolor='red', on_click=self.not_supported,
|
||||||
font_size=24, data={'error': True}),
|
font_size=24, data={'error': True}),
|
||||||
],
|
],
|
||||||
|
@ -856,6 +857,54 @@ class POSView(WuttaView):
|
||||||
self.show_snackbar(text, bgcolor='yellow')
|
self.show_snackbar(text, bgcolor='yellow')
|
||||||
self.page.update()
|
self.page.update()
|
||||||
|
|
||||||
|
def open_ring_click(self, e):
|
||||||
|
value = self.main_input.value or None
|
||||||
|
if not value:
|
||||||
|
self.show_snackbar("Must first enter an amount")
|
||||||
|
self.reset()
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
amount = decimal.Decimal(value)
|
||||||
|
except decimal.InvalidOperation:
|
||||||
|
self.show_snackbar("Amount is not valid")
|
||||||
|
self.reset()
|
||||||
|
return
|
||||||
|
|
||||||
|
def select(uuid):
|
||||||
|
session = self.app.make_session()
|
||||||
|
user = self.get_current_user(session)
|
||||||
|
batch = self.get_current_batch(session, user=user)
|
||||||
|
handler = self.get_batch_handler()
|
||||||
|
|
||||||
|
quantity = 1
|
||||||
|
if self.set_quantity.data is not None:
|
||||||
|
quantity = self.set_quantity.data
|
||||||
|
|
||||||
|
row = handler.add_open_ring(batch, uuid, amount, quantity=quantity, user=user)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
self.add_row_item(row, scroll=True)
|
||||||
|
self.refresh_totals(batch)
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
dlg.open = False
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def cancel(e):
|
||||||
|
dlg.open = False
|
||||||
|
self.reset(clear_quantity=False)
|
||||||
|
|
||||||
|
dlg = ft.AlertDialog(
|
||||||
|
modal=True,
|
||||||
|
title=ft.Text(f"Department Lookup - for {self.app.render_currency(amount)} OPEN RING"),
|
||||||
|
content=WuttaDepartmentLookup(self.config, on_select=select, on_cancel=cancel),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.page.dialog = dlg
|
||||||
|
dlg.open = True
|
||||||
|
self.page.update()
|
||||||
|
|
||||||
def adjust_price_click(self, e):
|
def adjust_price_click(self, e):
|
||||||
|
|
||||||
if not len(self.items.controls):
|
if not len(self.items.controls):
|
||||||
|
@ -1014,10 +1063,11 @@ class POSView(WuttaView):
|
||||||
self.show_snackbar("TODO: Drawer Kick", bgcolor='yellow')
|
self.show_snackbar("TODO: Drawer Kick", bgcolor='yellow')
|
||||||
self.page.update()
|
self.page.update()
|
||||||
|
|
||||||
def add_row_item(self, row):
|
def add_row_item(self, row, scroll=False):
|
||||||
|
|
||||||
# TODO: row types ugh
|
# TODO: row types ugh
|
||||||
if row.row_type not in (self.enum.POS_ROW_TYPE_SELL,
|
if row.row_type not in (self.enum.POS_ROW_TYPE_SELL,
|
||||||
|
self.enum.POS_ROW_TYPE_OPEN_RING,
|
||||||
self.enum.POS_ROW_TYPE_TENDER,
|
self.enum.POS_ROW_TYPE_TENDER,
|
||||||
self.enum.POS_ROW_TYPE_CHANGE_BACK):
|
self.enum.POS_ROW_TYPE_CHANGE_BACK):
|
||||||
return
|
return
|
||||||
|
@ -1032,6 +1082,9 @@ class POSView(WuttaView):
|
||||||
key=row.uuid,
|
key=row.uuid,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
if scroll:
|
||||||
|
self.items.scroll_to(offset=-1, duration=100)
|
||||||
|
|
||||||
def list_item_click(self, e):
|
def list_item_click(self, e):
|
||||||
self.select_txn_item(e.control)
|
self.select_txn_item(e.control)
|
||||||
|
|
||||||
|
@ -1142,7 +1195,8 @@ class POSView(WuttaView):
|
||||||
# cannot void an already void line
|
# cannot void an already void line
|
||||||
self.show_snackbar("LINE ALREADY VOID", bgcolor='yellow')
|
self.show_snackbar("LINE ALREADY VOID", bgcolor='yellow')
|
||||||
|
|
||||||
elif row.row_type != self.enum.POS_ROW_TYPE_SELL:
|
elif row.row_type not in (self.enum.POS_ROW_TYPE_SELL,
|
||||||
|
self.enum.POS_ROW_TYPE_OPEN_RING):
|
||||||
# cannot void line unless of type 'sell'
|
# cannot void line unless of type 'sell'
|
||||||
self.show_snackbar("LINE DOES NOT ALLOW VOID", bgcolor='yellow')
|
self.show_snackbar("LINE DOES NOT ALLOW VOID", bgcolor='yellow')
|
||||||
|
|
||||||
|
@ -1275,7 +1329,7 @@ class POSView(WuttaView):
|
||||||
|
|
||||||
# update screen to reflect new items/balance
|
# update screen to reflect new items/balance
|
||||||
for row in rows:
|
for row in rows:
|
||||||
self.add_row_item(row)
|
self.add_row_item(row, scroll=True)
|
||||||
self.refresh_totals(batch)
|
self.refresh_totals(batch)
|
||||||
|
|
||||||
# executed batch means txn was finalized
|
# executed batch means txn was finalized
|
||||||
|
|
Loading…
Reference in a new issue