Initial commit, basic login working
This commit is contained in:
		
						commit
						cbab5ec976
					
				
					 18 changed files with 913 additions and 0 deletions
				
			
		
							
								
								
									
										27
									
								
								wuttapos/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								wuttapos/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| # -*- 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 - package root | ||||
| """ | ||||
| 
 | ||||
| from ._version import __version__ | ||||
							
								
								
									
										3
									
								
								wuttapos/_version.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								wuttapos/_version.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| # -*- coding: utf-8; -*- | ||||
| 
 | ||||
| __version__ = '0.1.0' | ||||
							
								
								
									
										115
									
								
								wuttapos/app.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								wuttapos/app.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,115 @@ | |||
| # -*- 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 app | ||||
| """ | ||||
| 
 | ||||
| import json | ||||
| import os | ||||
| 
 | ||||
| from rattail.config import make_config | ||||
| 
 | ||||
| import flet as ft | ||||
| 
 | ||||
| import wuttapos | ||||
| 
 | ||||
| 
 | ||||
| def main(page: ft.Page): | ||||
|     config = make_config() | ||||
| 
 | ||||
|     page.title = f"WuttaPOS v{wuttapos.__version__}" | ||||
|     page.window_full_screen = True | ||||
|     # page.vertical_alignment = ft.MainAxisAlignment.CENTER | ||||
| 
 | ||||
|     # nb. track current user, txn etc. | ||||
|     page.shared = {} | ||||
| 
 | ||||
|     # TODO: this may be too hacky but is useful for now/dev | ||||
|     if not config.production(): | ||||
|         path = os.path.join(config.appdir(), '.wuttapos.cache') | ||||
|         if os.path.exists(path): | ||||
|             with open(path, 'rt') as f: | ||||
|                 page.shared = json.loads(f.read()) | ||||
| 
 | ||||
|     def clean_exit(): | ||||
|         if not config.production(): | ||||
|             # TODO: this may be too hacky but is useful for now/dev | ||||
|             path = os.path.join(config.appdir(), '.wuttapos.cache') | ||||
|             with open(path, 'wt') as f: | ||||
|                 f.write(json.dumps(page.shared)) | ||||
|         page.window_destroy() | ||||
| 
 | ||||
|     def keyboard(e): | ||||
|         # exit on ctrl+Q | ||||
|         if e.ctrl and e.key == 'Q': | ||||
|             if not e.shift and not e.alt and not e.meta: | ||||
|                 clean_exit() | ||||
| 
 | ||||
|     page.on_keyboard_event = keyboard | ||||
| 
 | ||||
|     def window_event(e): | ||||
|         if e.data == 'close': | ||||
|             clean_exit() | ||||
| 
 | ||||
|     # cf. https://flet.dev/docs/controls/page/#window_destroy | ||||
|     page.window_prevent_close = True | ||||
|     page.on_window_event = window_event | ||||
| 
 | ||||
|     # TODO: probably these should be auto-loaded from spec | ||||
|     from wuttapos.views.pos import POSView | ||||
|     from wuttapos.views.login import LoginView | ||||
| 
 | ||||
|     # cf .https://flet.dev/docs/guides/python/navigation-and-routing#building-views-on-route-change | ||||
| 
 | ||||
|     def route_change(route): | ||||
|         page.views.clear() | ||||
|         if page.route == '/pos': | ||||
|             page.views.append(POSView(config, '/pos')) | ||||
|         elif page.route == '/login': | ||||
|             page.views.append(LoginView(config, '/login')) | ||||
|         page.update() | ||||
| 
 | ||||
|     # TODO: this was in example docs but not sure what it's for? | ||||
|     # def view_pop(view): | ||||
|     #     page.views.pop() | ||||
|     #     top_view = page.views[-1] | ||||
|     #     page.go(top_view.route) | ||||
| 
 | ||||
|     page.on_route_change = route_change | ||||
|     # page.on_view_pop = view_pop | ||||
| 
 | ||||
|     # TODO: this may be too hacky but is useful for now/dev | ||||
|     if not config.production() and page.shared.get('user_uuid'): | ||||
|         page.go('/pos') | ||||
|     else: | ||||
|         page.go('/login') | ||||
| 
 | ||||
| 
 | ||||
| # TODO: can we inject config to the main() via ft.app() kwargs somehow? | ||||
| # pretty sure the `wuttapos open` command is trying to anyway.. | ||||
| def run_app(config=None): | ||||
|     ft.app(target=main) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     run_app() | ||||
							
								
								
									
										74
									
								
								wuttapos/commands.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								wuttapos/commands.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,74 @@ | |||
| # -*- 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 commands | ||||
| """ | ||||
| 
 | ||||
| import sys | ||||
| 
 | ||||
| from rattail import commands | ||||
| 
 | ||||
| from wuttapos import __version__ | ||||
| 
 | ||||
| 
 | ||||
| def main(*args): | ||||
|     """ | ||||
|     Main entry point for WuttaPOS command system | ||||
|     """ | ||||
|     args = list(args or sys.argv[1:]) | ||||
|     cmd = Command() | ||||
|     cmd.run(*args) | ||||
| 
 | ||||
| 
 | ||||
| class Command(commands.Command): | ||||
|     """ | ||||
|     Top-level command for WuttaPOS | ||||
|     """ | ||||
|     name = 'wuttapos' | ||||
|     version = __version__ | ||||
|     description = "WuttaPOS (point of sale)" | ||||
|     long_description = '' | ||||
| 
 | ||||
| 
 | ||||
| class Open(commands.Subcommand): | ||||
|     """ | ||||
|     Open the Point of Sale app | ||||
|     """ | ||||
|     name = 'open' | ||||
|     description = __doc__.strip() | ||||
| 
 | ||||
|     def run(self, args): | ||||
|         from wuttapos.app import run_app | ||||
| 
 | ||||
|         run_app(self.config) | ||||
| 
 | ||||
| 
 | ||||
| class Status(commands.Subcommand): | ||||
|     """ | ||||
|     Show status of the POS lane | ||||
|     """ | ||||
|     name = 'status' | ||||
|     description = __doc__.strip() | ||||
| 
 | ||||
|     def run(self, args): | ||||
|         print("TODO: show status") | ||||
							
								
								
									
										25
									
								
								wuttapos/controls/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								wuttapos/controls/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| # -*- 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 - flet controls | ||||
| """ | ||||
							
								
								
									
										35
									
								
								wuttapos/controls/base.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								wuttapos/controls/base.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | |||
| # -*- 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 - custom controls (base class) | ||||
| """ | ||||
| 
 | ||||
| import flet as ft | ||||
| 
 | ||||
| 
 | ||||
| class WuttaControl(ft.UserControl): | ||||
| 
 | ||||
|     def __init__(self, config, *args, **kwargs): | ||||
|         super().__init__(*args, **kwargs) | ||||
|         self.config = config | ||||
|         self.app = config.get_app() | ||||
							
								
								
									
										88
									
								
								wuttapos/controls/header.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								wuttapos/controls/header.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,88 @@ | |||
| # -*- 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 - header control | ||||
| """ | ||||
| 
 | ||||
| import flet as ft | ||||
| 
 | ||||
| from .base import WuttaControl | ||||
| from .timestamp import WuttaTimestamp | ||||
| 
 | ||||
| 
 | ||||
| class WuttaHeader(WuttaControl): | ||||
| 
 | ||||
|     def build(self): | ||||
|         self.txn_display = ft.Text("Txn: N", weight=ft.FontWeight.BOLD, size=20) | ||||
|         self.user_display = ft.Text("User: N", weight=ft.FontWeight.BOLD, size=20) | ||||
|         self.logout_button = ft.FilledButton("Logout", on_click=self.logout_click, visible=False) | ||||
|         self.logout_divider = ft.VerticalDivider(visible=False) | ||||
| 
 | ||||
|         controls = [ | ||||
|             self.txn_display, | ||||
|             ft.VerticalDivider(), | ||||
|             ft.Text(f"Cust: N", weight=ft.FontWeight.BOLD, size=20), | ||||
|             ft.VerticalDivider(), | ||||
|             WuttaTimestamp(self.config, expand=True, | ||||
|                            weight=ft.FontWeight.BOLD, size=20), | ||||
|             self.user_display, | ||||
|             ft.VerticalDivider(), | ||||
|             self.logout_button, | ||||
|             self.logout_divider, | ||||
|             ft.Text(f"WuttaPOS", weight=ft.FontWeight.BOLD, size=20), | ||||
|         ] | ||||
| 
 | ||||
|         return ft.Row(controls) | ||||
| 
 | ||||
|     def did_mount(self): | ||||
|         self.update_txn_display() | ||||
|         self.update_user_display() | ||||
|         self.update() | ||||
| 
 | ||||
|     def update_txn_display(self): | ||||
|         txn_display = "N" | ||||
| 
 | ||||
|         if self.page and self.page.shared and self.page.shared.get('txn_display'): | ||||
|             txn_display = self.page.shared['txn_display'] | ||||
| 
 | ||||
|         self.txn_display.value = f"Txn: {txn_display}" | ||||
| 
 | ||||
|     def update_user_display(self): | ||||
|         user_display = "N" | ||||
| 
 | ||||
|         if self.page and self.page.shared and self.page.shared.get('user_display'): | ||||
|             user_display = self.page.shared['user_display'] | ||||
| 
 | ||||
|         self.user_display.value = f"User: {user_display}" | ||||
| 
 | ||||
|         if self.page and self.page.shared.get('user_uuid'): | ||||
|             self.logout_button.visible = True | ||||
|             self.logout_divider.visible = True | ||||
| 
 | ||||
|     def logout_click(self, e): | ||||
|         self.page.shared.update({ | ||||
|             'user_uuid': None, | ||||
|             'user_display': None, | ||||
|             'txn_display': None, | ||||
|         }) | ||||
|         self.page.go('/login') | ||||
							
								
								
									
										59
									
								
								wuttapos/controls/timestamp.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								wuttapos/controls/timestamp.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | |||
| # -*- 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 - timestamp control | ||||
| """ | ||||
| 
 | ||||
| import threading | ||||
| import time | ||||
| 
 | ||||
| import flet as ft | ||||
| 
 | ||||
| from .base import WuttaControl | ||||
| 
 | ||||
| 
 | ||||
| class WuttaTimestamp(WuttaControl): | ||||
| 
 | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         self.weight = kwargs.pop('weight', None) | ||||
|         self.size = kwargs.pop('size', None) | ||||
|         super().__init__(*args, **kwargs) | ||||
| 
 | ||||
|     def build(self): | ||||
|         text = self.render_time(self.app.localtime()) | ||||
|         self.display = ft.Text(text, weight=self.weight, size=self.size) | ||||
| 
 | ||||
|         thread = threading.Thread(target=self.update_display) | ||||
|         thread.start() | ||||
| 
 | ||||
|         return self.display | ||||
| 
 | ||||
|     def render_time(self, value): | ||||
|         return value.strftime('%a %d %b %Y %I:%M:%S %p') | ||||
| 
 | ||||
|     def update_display(self): | ||||
|         while True: | ||||
|             if self.page: | ||||
|                 self.display.value = self.render_time(self.app.localtime()) | ||||
|                 self.update() | ||||
|             time.sleep(0.5) | ||||
							
								
								
									
										25
									
								
								wuttapos/views/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								wuttapos/views/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| # -*- 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 - flet views | ||||
| """ | ||||
							
								
								
									
										74
									
								
								wuttapos/views/base.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								wuttapos/views/base.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,74 @@ | |||
| # -*- 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 - flet views (base class) | ||||
| """ | ||||
| 
 | ||||
| import flet as ft | ||||
| 
 | ||||
| from wuttapos.controls.header import WuttaHeader | ||||
| 
 | ||||
| 
 | ||||
| class WuttaView(ft.View): | ||||
|     """ | ||||
|     Base class for all Flet views used in WuttaPOS | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, config, *args, **kwargs): | ||||
|         super().__init__(*args, **kwargs) | ||||
| 
 | ||||
|         self.config = config | ||||
|         self.app = self.config.get_app() | ||||
|         self.model = self.app.model | ||||
| 
 | ||||
|         controls = self.build_controls() | ||||
|         self.controls = [ | ||||
|             WuttaViewContainer(self.config, | ||||
|                                content=ft.Column(controls=controls), | ||||
|                                expand=True), | ||||
|         ] | ||||
| 
 | ||||
|     def build_controls(self): | ||||
|         return [self.build_header()] | ||||
| 
 | ||||
|     def build_header(self): | ||||
|         return WuttaHeader(self.config) | ||||
| 
 | ||||
| 
 | ||||
| class WuttaViewContainer(ft.Container): | ||||
|     """ | ||||
|     Main container class to wrap all controls for a view.  Used for | ||||
|     displaying background image etc. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, config, *args, **kwargs): | ||||
|         self.config = config | ||||
| 
 | ||||
|         if 'image_src' not in kwargs and not self.config.production(): | ||||
|             # TODO: host a local testing image? where *should* this come from? | ||||
|             image = self.config.get('rattail', 'testing_watermark') | ||||
|             if image: | ||||
|                 kwargs['image_src'] = image | ||||
|                 kwargs.setdefault('image_repeat', ft.ImageRepeat.REPEAT) | ||||
| 
 | ||||
|         super().__init__(*args, **kwargs) | ||||
							
								
								
									
										150
									
								
								wuttapos/views/login.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								wuttapos/views/login.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,150 @@ | |||
| # -*- 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 - login view | ||||
| """ | ||||
| 
 | ||||
| import flet as ft | ||||
| 
 | ||||
| from .base import WuttaView | ||||
| 
 | ||||
| 
 | ||||
| class LoginView(WuttaView): | ||||
|     """ | ||||
|     Main POS view for WuttaPOS | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, *args, **kwargs): | ||||
| 
 | ||||
|         # TODO: maybe support setting this to False?  for now that's not 100% supported | ||||
|         self.show_username = kwargs.pop('show_username', True) | ||||
| 
 | ||||
|         super().__init__(*args, **kwargs) | ||||
| 
 | ||||
|     def build_controls(self): | ||||
|         controls = [ | ||||
|             ft.Row( | ||||
|                 [ft.Text(value="Welcome to WuttaPOS", weight=ft.FontWeight.BOLD, size=28)], | ||||
|                 alignment=ft.MainAxisAlignment.CENTER, | ||||
|             ), | ||||
|             ft.Row(), | ||||
|             ft.Row(), | ||||
|             ft.Row(), | ||||
|         ] | ||||
| 
 | ||||
|         if self.show_username: | ||||
|             self.username = ft.TextField(label="Login", width=200, | ||||
|                                          on_submit=self.username_submit, | ||||
|                                          autofocus=True) | ||||
|             controls.extend([ | ||||
|                 ft.Row( | ||||
|                     [self.username], | ||||
|                     alignment=ft.MainAxisAlignment.CENTER, | ||||
|                 ), | ||||
|             ]) | ||||
| 
 | ||||
|         self.password = ft.TextField(label="Password", width=200, password=True, | ||||
|                                      on_submit=self.password_submit, | ||||
|                                      autofocus=not self.show_username) | ||||
| 
 | ||||
|         controls.extend([ | ||||
|             ft.Row( | ||||
|                 [self.password], | ||||
|                 alignment=ft.MainAxisAlignment.CENTER, | ||||
|             ), | ||||
|             ft.Row( | ||||
|                 [ | ||||
|                     ft.FilledButton("Login", on_click=self.attempt_login), | ||||
|                     ft.ElevatedButton("Clear", on_click=self.clear_login), | ||||
|                 ], | ||||
|                 alignment=ft.MainAxisAlignment.CENTER, | ||||
|             ), | ||||
|             ft.Row(), | ||||
|             ft.Row( | ||||
|                 [ft.Text("TODO: should have on-screen keyboard (at least 10-key pad?) " | ||||
|                             "for use with login etc.", italic=True)], | ||||
|                 alignment=ft.MainAxisAlignment.CENTER, | ||||
|             ), | ||||
|         ]) | ||||
| 
 | ||||
|         return [ | ||||
|             self.build_header(), | ||||
|             ft.Column(controls=controls, | ||||
|                       expand=True, | ||||
|                       alignment=ft.MainAxisAlignment.CENTER), | ||||
|         ] | ||||
| 
 | ||||
|     def username_submit(self, e): | ||||
|         if self.username.value: | ||||
|             self.password.focus() | ||||
|         else: | ||||
|             self.username.focus() | ||||
| 
 | ||||
|     def password_submit(self, e): | ||||
|         if self.password.value: | ||||
|             self.attempt_login() | ||||
|         else: | ||||
|             self.password.focus() | ||||
| 
 | ||||
|     def clear_login(self, e): | ||||
|         if self.show_username: | ||||
|             self.username.value = "" | ||||
|         self.password.value = "" | ||||
|         if self.show_username: | ||||
|             self.username.focus() | ||||
|         else: | ||||
|             self.password.focus() | ||||
|         self.page.update() | ||||
| 
 | ||||
|     def attempt_login(self, e=None): | ||||
|         if self.show_username and not self.username.value: | ||||
|             self.username.focus() | ||||
|             return | ||||
|         if not self.password.value: | ||||
|             self.password.focus() | ||||
|             return | ||||
| 
 | ||||
|         session = self.app.make_session() | ||||
|         auth = self.app.get_auth_handler() | ||||
|         user = auth.authenticate_user(session, self.username.value, self.password.value) | ||||
|         user_display = str(user) if user else None | ||||
|         session.close() | ||||
| 
 | ||||
|         if user: | ||||
|             # handle success | ||||
|             self.page.shared.update({ | ||||
|                 'user_uuid': user.uuid, | ||||
|                 'user_display': user_display, | ||||
|             }) | ||||
|             self.page.go('/pos') | ||||
| 
 | ||||
|         else: | ||||
|             # handle failure | ||||
|             self.page.snack_bar = ft.SnackBar(ft.Text("Login failed!", | ||||
|                                                       color='black', | ||||
|                                                       weight=ft.FontWeight.BOLD), | ||||
|                                               bgcolor='yellow', | ||||
|                                               duration=1500) | ||||
|             self.page.snack_bar.open = True | ||||
|             self.password.focus() | ||||
|             self.page.update() | ||||
							
								
								
									
										102
									
								
								wuttapos/views/pos.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								wuttapos/views/pos.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,102 @@ | |||
| # -*- 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 - POS view | ||||
| """ | ||||
| 
 | ||||
| import flet as ft | ||||
| 
 | ||||
| from .base import WuttaView | ||||
| 
 | ||||
| 
 | ||||
| class POSView(WuttaView): | ||||
|     """ | ||||
|     Main POS view for WuttaPOS | ||||
|     """ | ||||
| 
 | ||||
|     def build_controls(self): | ||||
| 
 | ||||
|         self.main_input = ft.TextField(on_submit=self.main_submit, | ||||
|                                        autofocus=True) | ||||
| 
 | ||||
|         def make_text(*args, **kwargs): | ||||
|             kwargs['weight'] = ft.FontWeight.BOLD | ||||
|             kwargs['size'] = 20 | ||||
|             return ft.Text(*args, **kwargs) | ||||
| 
 | ||||
|         return [ | ||||
|             self.build_header(), | ||||
| 
 | ||||
|             ft.Row( | ||||
|                 [self.main_input], | ||||
|                 alignment=ft.MainAxisAlignment.CENTER, | ||||
|             ), | ||||
| 
 | ||||
|             ft.Row(), | ||||
|             ft.Row(), | ||||
|             ft.Row(), | ||||
| 
 | ||||
|             ft.Row( | ||||
|                 [ft.Text("TODO: need lots of things yet here...somewhere..")], | ||||
|                 alignment=ft.MainAxisAlignment.CENTER, | ||||
|             ), | ||||
| 
 | ||||
|             ft.Row( | ||||
|                 [ft.Text("TODO: for instance, items rang up might go here")], | ||||
|             ), | ||||
| 
 | ||||
|             ft.DataTable( | ||||
|                 columns=[ | ||||
|                     ft.DataColumn(make_text("UPC")), | ||||
|                     ft.DataColumn(make_text("Description")), | ||||
|                     ft.DataColumn(make_text("Price"), numeric=True), | ||||
|                 ], | ||||
|                 rows=[ | ||||
|                     ft.DataRow( | ||||
|                         cells=[ | ||||
|                             ft.DataCell(make_text("0007430500132-1")), | ||||
|                             ft.DataCell(make_text("Apple Cider Vinegar 32oz")), | ||||
|                             ft.DataCell(make_text("$5.99")), | ||||
|                         ], | ||||
|                     ), | ||||
|                     ft.DataRow( | ||||
|                         cells=[ | ||||
|                             ft.DataCell(make_text("0007430500116-1")), | ||||
|                             ft.DataCell(make_text("Apple Cider Vinegar 16oz")), | ||||
|                             ft.DataCell(make_text("$3.59")), | ||||
|                         ], | ||||
|                     ), | ||||
|                 ], | ||||
|             ), | ||||
|         ] | ||||
| 
 | ||||
|     def main_submit(self, e): | ||||
|         value = self.main_input.value.upper() | ||||
|         self.page.snack_bar = ft.SnackBar(ft.Text(f"submit: {value}", color='black', | ||||
|                                                   weight=ft.FontWeight.BOLD), | ||||
|                                           bgcolor='yellow', | ||||
|                                           duration=1500) | ||||
|         self.page.snack_bar.open = True | ||||
|         self.main_input.value = "" | ||||
|         self.main_input.focus() | ||||
|         self.page.update() | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lance Edgar
						Lance Edgar