258 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			258 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# -*- 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 - header control
 | 
						|
"""
 | 
						|
 | 
						|
import rattail
 | 
						|
 | 
						|
import flet as ft
 | 
						|
 | 
						|
import wuttapos
 | 
						|
from .base import WuttaControl
 | 
						|
from .timestamp import WuttaTimestamp
 | 
						|
from .feedback import WuttaFeedback
 | 
						|
 | 
						|
 | 
						|
class WuttaHeader(WuttaControl):
 | 
						|
 | 
						|
    def __init__(self, *args, **kwargs):
 | 
						|
        self.terminal_id = kwargs.pop('terminal_id', None)
 | 
						|
        super().__init__(*args, **kwargs)
 | 
						|
 | 
						|
    def build(self):
 | 
						|
        self.txn_display = ft.Text("Txn: N", weight=ft.FontWeight.BOLD, size=20)
 | 
						|
        self.cust_display = ft.Text("Cust: N", weight=ft.FontWeight.BOLD, size=20)
 | 
						|
 | 
						|
        self.training_mode = ft.Text(size=40, weight=ft.FontWeight.BOLD)
 | 
						|
 | 
						|
        self.user_display = ft.Text("User: N", weight=ft.FontWeight.BOLD, size=20)
 | 
						|
        self.logout_button = ft.OutlinedButton("Logout", on_click=self.logout_click, visible=False)
 | 
						|
        self.logout_divider = ft.VerticalDivider(visible=False)
 | 
						|
        self.title_button = ft.FilledButton(self.app.get_title(), on_click=self.title_click)
 | 
						|
 | 
						|
        terminal_style = ft.TextStyle(size=20, weight=ft.FontWeight.BOLD)
 | 
						|
        if not self.terminal_id:
 | 
						|
            terminal_style.bgcolor = 'red'
 | 
						|
            terminal_style.color = 'white'
 | 
						|
 | 
						|
        return ft.Stack(
 | 
						|
            controls=[
 | 
						|
                ft.Container(
 | 
						|
                    content=ft.Row(
 | 
						|
                        [
 | 
						|
                            ft.Container(
 | 
						|
                                content=self.training_mode,
 | 
						|
                                bgcolor='yellow',
 | 
						|
                            ),
 | 
						|
                        ],
 | 
						|
                        alignment=ft.MainAxisAlignment.CENTER,
 | 
						|
                    ),
 | 
						|
                ),
 | 
						|
                ft.Row(
 | 
						|
                    [
 | 
						|
                        ft.Row(
 | 
						|
                            [
 | 
						|
                                self.txn_display,
 | 
						|
                                ft.VerticalDivider(),
 | 
						|
                                self.cust_display,
 | 
						|
                                ft.VerticalDivider(),
 | 
						|
                                WuttaTimestamp(self.config, weight=ft.FontWeight.BOLD, size=20),
 | 
						|
                            ],
 | 
						|
                        ),
 | 
						|
                        ft.Row(
 | 
						|
                            [
 | 
						|
                                self.user_display,
 | 
						|
                                ft.VerticalDivider(),
 | 
						|
                                self.logout_button,
 | 
						|
                                self.logout_divider,
 | 
						|
                                ft.Text(
 | 
						|
                                    spans=[
 | 
						|
                                        ft.TextSpan(style=terminal_style, text=f"Term: {self.terminal_id or '??'}"),
 | 
						|
                                    ],
 | 
						|
                                ),
 | 
						|
                                ft.VerticalDivider(),
 | 
						|
                                self.title_button,
 | 
						|
                            ],
 | 
						|
                        ),
 | 
						|
                    ],
 | 
						|
                    alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
 | 
						|
                ),
 | 
						|
 | 
						|
            ],
 | 
						|
        )
 | 
						|
 | 
						|
    def did_mount(self):
 | 
						|
        self.informed_refresh()
 | 
						|
 | 
						|
    def informed_refresh(self):
 | 
						|
        self.update_txn_display()
 | 
						|
        self.update_cust_display()
 | 
						|
        self.update_user_display()
 | 
						|
        self.update_training_display()
 | 
						|
        self.update()
 | 
						|
 | 
						|
    def update_txn_display(self):
 | 
						|
        txn_display = None
 | 
						|
        if self.page:
 | 
						|
            txn_display = self.page.session.get('txn_display')
 | 
						|
        self.txn_display.value = f"Txn: {txn_display or 'N'}"
 | 
						|
 | 
						|
    def update_cust_display(self):
 | 
						|
        cust_display = None
 | 
						|
        if self.page:
 | 
						|
            cust_display = self.page.session.get('cust_display')
 | 
						|
        self.cust_display.value = f"Cust: {cust_display or 'N'}"
 | 
						|
 | 
						|
    def update_training_display(self):
 | 
						|
        if self.page.session.get('training'):
 | 
						|
            self.training_mode.value = "  TRAINING MODE  "
 | 
						|
        else:
 | 
						|
            self.training_mode.value = ""
 | 
						|
 | 
						|
    def update_user_display(self):
 | 
						|
        user_display = None
 | 
						|
        if self.page:
 | 
						|
            user_display = self.page.session.get('user_display')
 | 
						|
        self.user_display.value = f"User: {user_display or 'N'}"
 | 
						|
 | 
						|
        if self.page and self.page.session.get('user_uuid'):
 | 
						|
            self.logout_button.visible = True
 | 
						|
            self.logout_divider.visible = True
 | 
						|
 | 
						|
    def logout_click(self, e):
 | 
						|
 | 
						|
        # TODO: hacky but works for now
 | 
						|
        if not self.config.production():
 | 
						|
            self.page.client_storage.set('user_uuid', '')
 | 
						|
 | 
						|
        self.page.session.clear()
 | 
						|
        self.page.go('/login')
 | 
						|
 | 
						|
    def title_click(self, e):
 | 
						|
        title = self.app.get_title()
 | 
						|
 | 
						|
        year = self.app.today().year
 | 
						|
        if year > 2023:
 | 
						|
            year_range = f'2023 - {year}'
 | 
						|
        else:
 | 
						|
            year_range = year
 | 
						|
 | 
						|
        license = f"""\
 | 
						|
WuttaPOS -- Pythonic Point of Sale System
 | 
						|
Copyright © {year_range} Lance Edgar
 | 
						|
 | 
						|
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/>.
 | 
						|
"""
 | 
						|
 | 
						|
        buttons = []
 | 
						|
 | 
						|
        user_uuid = self.page.session.get('user_uuid')
 | 
						|
        if user_uuid:
 | 
						|
 | 
						|
            session = self.app.make_session()
 | 
						|
            model = self.app.model
 | 
						|
            user = session.get(model.User, user_uuid)
 | 
						|
            auth = self.app.get_auth_handler()
 | 
						|
            has_perm = auth.has_permission(session, user, 'pos.test_error')
 | 
						|
            session.close()
 | 
						|
            if has_perm:
 | 
						|
                test_error = self.make_button("TEST ERROR", font_size=24,
 | 
						|
                                              height=60,
 | 
						|
                                              width=60 * 3,
 | 
						|
                                              bgcolor='red',
 | 
						|
                                              on_click=self.test_error_click)
 | 
						|
                buttons.append(test_error)
 | 
						|
 | 
						|
            feedback = WuttaFeedback(self.config, page=self.page,
 | 
						|
                                     on_send=self.reset, on_cancel=self.reset)
 | 
						|
            buttons.append(feedback)
 | 
						|
 | 
						|
        self.dlg = ft.AlertDialog(
 | 
						|
            title=ft.Text(title),
 | 
						|
            content=ft.Container(
 | 
						|
                content=ft.Column(
 | 
						|
                    [
 | 
						|
                        ft.Divider(),
 | 
						|
                        ft.Text(f"{title} v{wuttapos.__version__}"),
 | 
						|
                        ft.Text(f"rattail v{rattail.__version__}"),
 | 
						|
                        ft.Divider(),
 | 
						|
                        ft.Text(license),
 | 
						|
                        ft.Container(
 | 
						|
                            content=ft.Row(
 | 
						|
                                controls=buttons,
 | 
						|
                                alignment=ft.MainAxisAlignment.CENTER,
 | 
						|
                            ),
 | 
						|
                            alignment=ft.alignment.center,
 | 
						|
                            expand=True,
 | 
						|
                        ),
 | 
						|
                    ],
 | 
						|
                    expand=True,
 | 
						|
                ),
 | 
						|
                height=600,
 | 
						|
            ),
 | 
						|
            actions=[
 | 
						|
                ft.Row(
 | 
						|
                    [
 | 
						|
                        ft.Container(content=ft.Text("Close", size=20,
 | 
						|
                                                     weight=ft.FontWeight.BOLD),
 | 
						|
                                     height=60,
 | 
						|
                                     width=60 * 2.5,
 | 
						|
                                     alignment=ft.alignment.center,
 | 
						|
                                     border=ft.border.all(1, 'black'),
 | 
						|
                                     border_radius=ft.border_radius.all(5),
 | 
						|
                                     on_click=self.close_dlg),
 | 
						|
                    ],
 | 
						|
                    alignment=ft.MainAxisAlignment.CENTER,
 | 
						|
                ),
 | 
						|
            ],
 | 
						|
        )
 | 
						|
 | 
						|
        self.page.dialog = self.dlg
 | 
						|
        self.dlg.open = True
 | 
						|
        self.page.update()
 | 
						|
 | 
						|
    def test_error_click(self, e):
 | 
						|
 | 
						|
        # first get the dialog out of the way
 | 
						|
        self.dlg.open = False
 | 
						|
        self.reset()
 | 
						|
        self.page.update()
 | 
						|
 | 
						|
        raise RuntimeError("FAKE ERROR - to test error handling")
 | 
						|
 | 
						|
    def close_dlg(self, e):
 | 
						|
        self.dlg.open = False
 | 
						|
        self.reset()
 | 
						|
        self.page.update()
 |