Use actual POS batch under the hood
This commit is contained in:
		
							parent
							
								
									c3c8ae7e94
								
							
						
					
					
						commit
						545f115dc8
					
				
					 3 changed files with 195 additions and 31 deletions
				
			
		|  | @ -36,6 +36,8 @@ import wuttapos | |||
| 
 | ||||
| def main(page: ft.Page): | ||||
|     config = make_config() | ||||
|     app = config.get_app() | ||||
|     model = app.model | ||||
| 
 | ||||
|     page.title = f"WuttaPOS v{wuttapos.__version__}" | ||||
|     page.window_full_screen = True | ||||
|  | @ -50,6 +52,16 @@ def main(page: ft.Page): | |||
|         if os.path.exists(path): | ||||
|             with open(path, 'rt') as f: | ||||
|                 page.shared = json.loads(f.read()) | ||||
|         page.shared.pop('txn_display', None) # TODO | ||||
|         if page.shared and page.shared.get('user_uuid'): | ||||
|             handler = app.get_batch_handler('pos') | ||||
|             session = app.make_session() | ||||
|             user = session.get(model.User, page.shared['user_uuid']) | ||||
|             # TODO: should also filter this by terminal | ||||
|             batch = handler.get_current_batch(user, create=False) | ||||
|             if batch: | ||||
|                 page.shared['txn_display'] = batch.id_str | ||||
|             session.close() | ||||
| 
 | ||||
|     def clean_exit(): | ||||
|         if not config.production(): | ||||
|  |  | |||
|  | @ -40,6 +40,7 @@ class WuttaView(ft.View): | |||
|         self.config = config | ||||
|         self.app = self.config.get_app() | ||||
|         self.model = self.app.model | ||||
|         self.enum = self.app.enum | ||||
| 
 | ||||
|         controls = self.build_controls() | ||||
|         self.controls = [ | ||||
|  | @ -52,7 +53,8 @@ class WuttaView(ft.View): | |||
|         return [self.build_header()] | ||||
| 
 | ||||
|     def build_header(self): | ||||
|         return WuttaHeader(self.config) | ||||
|         self.header = WuttaHeader(self.config) | ||||
|         return self.header | ||||
| 
 | ||||
| 
 | ||||
| class WuttaViewContainer(ft.Container): | ||||
|  |  | |||
|  | @ -43,9 +43,17 @@ class POSView(WuttaView): | |||
| 
 | ||||
|         self.items = ft.ListView() | ||||
| 
 | ||||
|         self.items_container = ft.Container(content=self.items, | ||||
|                                             padding=ft.padding.only(10, 0, 10, 0), | ||||
|                                             expand=1) | ||||
|         self.txn_total = ft.Text("", size=40) | ||||
| 
 | ||||
|         self.items_column = ft.Column( | ||||
|             controls=[ | ||||
|                 ft.Container(content=self.items, | ||||
|                              padding=ft.padding.only(10, 0, 10, 0)), | ||||
|                 ft.Row([self.txn_total], | ||||
|                        alignment=ft.MainAxisAlignment.END), | ||||
|             ], | ||||
|             expand=1, | ||||
|         ) | ||||
| 
 | ||||
|         def tenkey_click(e): | ||||
|             value = e.control.content.value | ||||
|  | @ -131,16 +139,17 @@ class POSView(WuttaView): | |||
|         meta_button_width = meta_button_height * 2 | ||||
|         meta_font_size = tenkey_font_size | ||||
| 
 | ||||
|         def meta_button(text): | ||||
|         def meta_button(text, on_click=None, bgcolor='yellow'): | ||||
|             return ft.Container(content=ft.Text(text, size=meta_font_size, | ||||
|                                                 weight=ft.FontWeight.BOLD), | ||||
|                                 height=meta_button_height, | ||||
|                                 width=meta_button_width, | ||||
|                                 # on_click=meta_click, | ||||
|                                 on_click=on_click, | ||||
|                                 alignment=ft.alignment.center, | ||||
|                                 border=ft.border.all(1, 'black'), | ||||
|                                 border_radius=ft.border_radius.all(5), | ||||
|                                 bgcolor='orange') | ||||
|                                 bgcolor=bgcolor) | ||||
| 
 | ||||
|         self.meta_menu = ft.Container( | ||||
|             content=ft.Column( | ||||
|  | @ -148,7 +157,7 @@ class POSView(WuttaView): | |||
|                     ft.Row( | ||||
|                         [ | ||||
|                             meta_button("MGR"), | ||||
|                             meta_button("VOID"), | ||||
|                             meta_button("VOID", bgcolor='red', on_click=self.void_click), | ||||
|                         ], | ||||
|                         spacing=0, | ||||
|                     ), | ||||
|  | @ -178,6 +187,36 @@ class POSView(WuttaView): | |||
|             ), | ||||
|             expand=0) | ||||
| 
 | ||||
|         context_button_height = tenkey_button_size | ||||
|         context_button_width = context_button_height * 2 | ||||
|         context_font_size = tenkey_font_size | ||||
| 
 | ||||
|         def context_button(text, on_click=None): | ||||
|             return ft.Container(content=ft.Text(text, size=context_font_size, | ||||
|                                                 weight=ft.FontWeight.BOLD), | ||||
|                                 height=context_button_height, | ||||
|                                 width=context_button_width, | ||||
|                                 on_click=on_click, | ||||
|                                 alignment=ft.alignment.center, | ||||
|                                 border=ft.border.all(1, 'black'), | ||||
|                                 border_radius=ft.border_radius.all(5), | ||||
|                                 bgcolor='orange') | ||||
| 
 | ||||
|         self.context_menu = ft.Container( | ||||
|             content=ft.Column( | ||||
|                 [ | ||||
|                     ft.Row( | ||||
|                         [ | ||||
|                             context_button("CASH", on_click=self.tender_click), | ||||
|                             context_button("CHECK", on_click=self.tender_click), | ||||
|                         ], | ||||
|                         spacing=0, | ||||
|                     ), | ||||
|                 ], | ||||
|                 spacing=0, | ||||
|             ), | ||||
|             expand=0) | ||||
| 
 | ||||
|         return [ | ||||
|             self.build_header(), | ||||
| 
 | ||||
|  | @ -192,9 +231,18 @@ class POSView(WuttaView): | |||
| 
 | ||||
|             ft.Row( | ||||
|                 [ | ||||
|                     self.items_container, | ||||
|                     self.tenkey_menu, | ||||
|                     self.meta_menu, | ||||
|                     self.items_column, | ||||
|                     ft.Column( | ||||
|                         [ | ||||
|                             ft.Row( | ||||
|                                 [ | ||||
|                                     self.tenkey_menu, | ||||
|                                     self.meta_menu, | ||||
|                                 ], | ||||
|                             ), | ||||
|                             self.context_menu, | ||||
|                         ], | ||||
|                     ), | ||||
|                 ], | ||||
|                 vertical_alignment=ft.CrossAxisAlignment.START, | ||||
|             ), | ||||
|  | @ -205,29 +253,130 @@ class POSView(WuttaView): | |||
|         kwargs.setdefault('size', 24) | ||||
|         return ft.Text(*args, **kwargs) | ||||
| 
 | ||||
|     def main_submit(self, e): | ||||
|         value = self.main_input.value | ||||
| 
 | ||||
|     def did_mount(self): | ||||
|         model = self.model | ||||
|         session = self.app.make_session() | ||||
|         product = self.app.get_products_handler().locate_product_for_entry(session, value) | ||||
|         if product: | ||||
|             price = product.current_price or product.regular_price | ||||
|             pretty_price = self.app.render_currency(price.price) | ||||
|         handler = self.app.get_batch_handler('pos') | ||||
|         user = session.get(model.User, self.page.shared['user_uuid']) | ||||
|         batch = handler.get_current_batch(user, create=True) | ||||
|         self.page.shared['txn_display'] = batch.id_str | ||||
| 
 | ||||
|             self.items.controls.append( | ||||
|                 ft.Container( | ||||
|                     content=ft.Row( | ||||
|                         [ | ||||
|                             ft.Row([ | ||||
|                                 self.make_text(f"{product}"), | ||||
|                                 self.make_text(f"× 1 @ {pretty_price}", weight=None, italic=True), | ||||
|                             ]), | ||||
|                             self.make_text(pretty_price), | ||||
|                         ], | ||||
|                         alignment=ft.MainAxisAlignment.SPACE_BETWEEN, | ||||
|                     ), | ||||
|                     border=ft.border.only(bottom=ft.border.BorderSide(1, 'gray')), | ||||
|                     padding=ft.padding.only(0, 5, 0, 5))) | ||||
|         self.items.controls.clear() | ||||
|         for row in batch.active_rows(): | ||||
|             self.add_row_item(row) | ||||
| 
 | ||||
|         self.txn_total.value = self.app.render_currency(batch.sales_total) | ||||
| 
 | ||||
|         session.commit() | ||||
|         session.close() | ||||
| 
 | ||||
|     def add_row_item(self, row): | ||||
|         quantity = self.app.render_quantity(row.quantity) | ||||
|         pretty_price = self.app.render_currency(row.txn_price) | ||||
|         self.items.controls.append( | ||||
|             ft.Container( | ||||
|                 content=ft.Row( | ||||
|                     [ | ||||
|                         ft.Row([ | ||||
|                             self.make_text(f"{row.description}"), | ||||
|                             self.make_text(f"× {quantity} @ {pretty_price}", | ||||
|                                            weight=None, italic=True, size=20), | ||||
|                         ]), | ||||
|                         self.make_text(pretty_price), | ||||
|                     ], | ||||
|                     alignment=ft.MainAxisAlignment.SPACE_BETWEEN, | ||||
|                 ), | ||||
|                 border=ft.border.only(bottom=ft.border.BorderSide(1, 'gray')), | ||||
|                 padding=ft.padding.only(0, 5, 0, 5))) | ||||
| 
 | ||||
|     def void_click(self, e): | ||||
| 
 | ||||
|         def confirm(e): | ||||
|             dlg.open = False | ||||
| 
 | ||||
|             model = self.model | ||||
|             session = self.app.make_session() | ||||
|             handler = self.app.get_batch_handler('pos') | ||||
|             user = session.get(model.User, self.page.shared['user_uuid']) | ||||
|             batch = handler.get_current_batch(user, create=True) | ||||
| 
 | ||||
|             # void current batch | ||||
|             handler.void_batch(batch, user) | ||||
|             session.flush() | ||||
| 
 | ||||
|             # make new batch | ||||
|             batch = handler.get_current_batch(user, create=True) | ||||
| 
 | ||||
|             # commit changes | ||||
|             session.commit() | ||||
|             session.close() | ||||
| 
 | ||||
|             # reset txn display | ||||
|             self.items.controls.clear() | ||||
|             self.txn_total.value = None | ||||
|             self.page.shared['txn_display'] = batch.id_str | ||||
|             self.header.update_txn_display() | ||||
|             # TODO: not clear why must call update() for header too? | ||||
|             self.header.update() | ||||
|             self.page.update() | ||||
| 
 | ||||
|         def cancel(e): | ||||
|             dlg.open = False | ||||
|             self.page.update() | ||||
| 
 | ||||
|         dlg = ft.AlertDialog( | ||||
|             modal=True, | ||||
|             title=ft.Text("Confirm VOID"), | ||||
|             content=ft.Text("Really VOID this transaction?"), | ||||
|             actions=[ | ||||
|                 ft.TextButton("Yes", on_click=confirm), | ||||
|                 ft.TextButton("No", on_click=cancel), | ||||
|             ]) | ||||
| 
 | ||||
|         self.page.dialog = dlg | ||||
|         dlg.open = True | ||||
|         self.page.update() | ||||
| 
 | ||||
|     def tender_click(self, e): | ||||
|         model = self.model | ||||
|         session = self.app.make_session() | ||||
|         handler = self.app.get_batch_handler('pos') | ||||
|         user = session.get(model.User, self.page.shared['user_uuid']) | ||||
|         batch = handler.get_current_batch(user) | ||||
| 
 | ||||
|         # tender / execute batch | ||||
|         tender = e.control.content.value | ||||
|         handler.tender_and_execute(batch, user, tender) | ||||
| 
 | ||||
|         # make new batch | ||||
|         batch = handler.get_current_batch(user, create=True) | ||||
| 
 | ||||
|         session.commit() | ||||
|         session.close() | ||||
| 
 | ||||
|         # reset txn display | ||||
|         self.items.controls.clear() | ||||
|         self.txn_total.value = None | ||||
|         self.page.shared['txn_display'] = batch.id_str | ||||
|         self.header.update_txn_display() | ||||
|         # TODO: not clear why must call update() for header too? | ||||
|         self.header.update() | ||||
|         self.main_input.focus() | ||||
|         self.page.update() | ||||
| 
 | ||||
|     def main_submit(self, e): | ||||
|         handler = self.app.get_batch_handler('pos') | ||||
|         session = self.app.make_session() | ||||
|         model = self.model | ||||
| 
 | ||||
|         user = session.get(model.User, self.page.shared['user_uuid']) | ||||
|         batch = handler.get_current_batch(user) | ||||
| 
 | ||||
|         value = self.main_input.value | ||||
|         row = handler.process_entry(batch, value) | ||||
|         if row: | ||||
|             self.add_row_item(row) | ||||
|             self.txn_total.value = self.app.render_currency(batch.sales_total) | ||||
| 
 | ||||
|         else: | ||||
|             self.page.snack_bar = ft.SnackBar(ft.Text(f"UNRECOGNIZED: {value}", | ||||
|  | @ -237,6 +386,7 @@ class POSView(WuttaView): | |||
|                                               duration=1500) | ||||
|             self.page.snack_bar.open = True | ||||
| 
 | ||||
|         session.commit() | ||||
|         session.close() | ||||
| 
 | ||||
|         self.main_input.value = "" | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lance Edgar
						Lance Edgar