| 
				
			 | 
			
			
				@@ -15,6 +15,7 @@ from PySide2.QtWidgets import ( 
			 | 
		
	
		
			
			| 
				15
			 | 
			
				15
			 | 
			
			
				     QApplication, 
			 | 
		
	
		
			
			| 
				16
			 | 
			
				16
			 | 
			
			
				     QGridLayout, 
			 | 
		
	
		
			
			| 
				17
			 | 
			
				17
			 | 
			
			
				     QInputDialog, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				18
			 | 
			
			
				+    QLineEdit, 
			 | 
		
	
		
			
			| 
				18
			 | 
			
				19
			 | 
			
			
				     QMainWindow, 
			 | 
		
	
		
			
			| 
				19
			 | 
			
				20
			 | 
			
			
				     QMessageBox, 
			 | 
		
	
		
			
			| 
				20
			 | 
			
				21
			 | 
			
			
				     QPushButton, 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -33,7 +34,7 @@ except ImportError: 
			 | 
		
	
		
			
			| 
				33
			 | 
			
				34
			 | 
			
			
				     dbus = None 
			 | 
		
	
		
			
			| 
				34
			 | 
			
				35
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				35
			 | 
			
				36
			 | 
			
			
				 from piket_client.sound import PLOP_WAVE, UNDO_WAVE 
			 | 
		
	
		
			
			| 
				36
			 | 
			
				
			 | 
			
			
				-from piket_client.model import Person, ConsumptionType, Consumption, ServerStatus 
			 | 
		
	
		
			
			| 
				
			 | 
			
				37
			 | 
			
			
				+from piket_client.model import Person, ConsumptionType, Consumption, ServerStatus, Settlement 
			 | 
		
	
		
			
			| 
				37
			 | 
			
				38
			 | 
			
			
				 import piket_client.logger 
			 | 
		
	
		
			
			| 
				38
			 | 
			
				39
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				39
			 | 
			
				40
			 | 
			
			
				 LOG = logging.getLogger(__name__) 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -86,15 +87,18 @@ class NameButton(QPushButton): 
			 | 
		
	
		
			
			| 
				86
			 | 
			
				87
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				87
			 | 
			
				88
			 | 
			
			
				     def process_click(self) -> None: 
			 | 
		
	
		
			
			| 
				88
			 | 
			
				89
			 | 
			
			
				         """ Process a click on this button. """ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				90
			 | 
			
			
				+        LOG.debug('Button clicked.') 
			 | 
		
	
		
			
			| 
				89
			 | 
			
				91
			 | 
			
			
				         result = self.person.add_consumption(self.active_id) 
			 | 
		
	
		
			
			| 
				90
			 | 
			
				92
			 | 
			
			
				         if result: 
			 | 
		
	
		
			
			| 
				91
			 | 
			
				93
			 | 
			
			
				             plop() 
			 | 
		
	
		
			
			| 
				92
			 | 
			
				94
			 | 
			
			
				             self.setText(self.current_label) 
			 | 
		
	
		
			
			| 
				93
			 | 
			
				95
			 | 
			
			
				             self.consumption_created.emit(result) 
			 | 
		
	
		
			
			| 
				94
			 | 
			
				96
			 | 
			
			
				         else: 
			 | 
		
	
		
			
			| 
				95
			 | 
			
				
			 | 
			
			
				-            print("Jantoeternuitje, kapot") 
			 | 
		
	
		
			
			| 
				
			 | 
			
				97
			 | 
			
			
				+            LOG.error("Failed to add consumption", extra={'person': 
			 | 
		
	
		
			
			| 
				
			 | 
			
				98
			 | 
			
			
				+                self.person}) 
			 | 
		
	
		
			
			| 
				96
			 | 
			
				99
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				97
			 | 
			
				100
			 | 
			
			
				     def confirm_hide(self) -> None: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				101
			 | 
			
			
				+        LOG.debug('Button right-clicked.') 
			 | 
		
	
		
			
			| 
				98
			 | 
			
				102
			 | 
			
			
				         ok = QMessageBox.warning( 
			 | 
		
	
		
			
			| 
				99
			 | 
			
				103
			 | 
			
			
				             self.window(), 
			 | 
		
	
		
			
			| 
				100
			 | 
			
				104
			 | 
			
			
				             "Persoon verbergen?", 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -128,6 +132,8 @@ class NameButtons(QWidget): 
			 | 
		
	
		
			
			| 
				128
			 | 
			
				132
			 | 
			
			
				     def consumption_type_changed(self, new_id: str): 
			 | 
		
	
		
			
			| 
				129
			 | 
			
				133
			 | 
			
			
				         """ Process a change of the consumption type and propagate to the 
			 | 
		
	
		
			
			| 
				130
			 | 
			
				134
			 | 
			
			
				         contained buttons. """ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				135
			 | 
			
			
				+        LOG.debug('Consumption type updated in NameButtons.', 
			 | 
		
	
		
			
			| 
				
			 | 
			
				136
			 | 
			
			
				+                extra={'new_id': new_id}) 
			 | 
		
	
		
			
			| 
				131
			 | 
			
				137
			 | 
			
			
				         self.active_consumption_type_id = new_id 
			 | 
		
	
		
			
			| 
				132
			 | 
			
				138
			 | 
			
			
				         self.new_id_set.emit(new_id) 
			 | 
		
	
		
			
			| 
				133
			 | 
			
				139
			 | 
			
			
				  
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -135,6 +141,8 @@ class NameButtons(QWidget): 
			 | 
		
	
		
			
			| 
				135
			 | 
			
				141
			 | 
			
			
				         """ Initialize UI: build GridLayout, retrieve People and build a button 
			 | 
		
	
		
			
			| 
				136
			 | 
			
				142
			 | 
			
			
				         for each. """ 
			 | 
		
	
		
			
			| 
				137
			 | 
			
				143
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				144
			 | 
			
			
				+        LOG.debug('Initializing NameButtons.') 
			 | 
		
	
		
			
			| 
				
			 | 
			
				145
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				138
			 | 
			
				146
			 | 
			
			
				         ps = Person.get_all(True) 
			 | 
		
	
		
			
			| 
				139
			 | 
			
				147
			 | 
			
			
				         num_columns = round(len(ps) / 10) + 1 
			 | 
		
	
		
			
			| 
				140
			 | 
			
				148
			 | 
			
			
				  
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -162,6 +170,7 @@ class PiketMainWindow(QMainWindow): 
			 | 
		
	
		
			
			| 
				162
			 | 
			
				170
			 | 
			
			
				     consumption_type_changed = Signal(str) 
			 | 
		
	
		
			
			| 
				163
			 | 
			
				171
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				164
			 | 
			
				172
			 | 
			
			
				     def __init__(self) -> None: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				173
			 | 
			
			
				+        LOG.debug('Initializing PiketMainWindow.') 
			 | 
		
	
		
			
			| 
				165
			 | 
			
				174
			 | 
			
			
				         super().__init__() 
			 | 
		
	
		
			
			| 
				166
			 | 
			
				175
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				167
			 | 
			
				176
			 | 
			
			
				         self.main_widget = None 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -169,7 +178,7 @@ class PiketMainWindow(QMainWindow): 
			 | 
		
	
		
			
			| 
				169
			 | 
			
				178
			 | 
			
			
				         self.toolbar = None 
			 | 
		
	
		
			
			| 
				170
			 | 
			
				179
			 | 
			
			
				         self.osk = None 
			 | 
		
	
		
			
			| 
				171
			 | 
			
				180
			 | 
			
			
				         self.undo_action = None 
			 | 
		
	
		
			
			| 
				172
			 | 
			
				
			 | 
			
			
				-        self.undo_queue = collections.deque([], 20) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				181
			 | 
			
			
				+        self.undo_queue = collections.deque([], 15) 
			 | 
		
	
		
			
			| 
				173
			 | 
			
				182
			 | 
			
			
				         self.init_ui() 
			 | 
		
	
		
			
			| 
				174
			 | 
			
				183
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				175
			 | 
			
				184
			 | 
			
			
				     def init_ui(self) -> None: 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -429,6 +438,48 @@ def main() -> None: 
			 | 
		
	
		
			
			| 
				429
			 | 
			
				438
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				430
			 | 
			
				439
			 | 
			
			
				     # Load main window 
			 | 
		
	
		
			
			| 
				431
			 | 
			
				440
			 | 
			
			
				     main_window = PiketMainWindow() 
			 | 
		
	
		
			
			| 
				
			 | 
			
				441
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				442
			 | 
			
			
				+    # Test unsettled consumptions 
			 | 
		
	
		
			
			| 
				
			 | 
			
				443
			 | 
			
			
				+    status = ServerStatus.unsettled_consumptions() 
			 | 
		
	
		
			
			| 
				
			 | 
			
				444
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				445
			 | 
			
			
				+    unsettled = status['unsettled']['amount'] 
			 | 
		
	
		
			
			| 
				
			 | 
			
				446
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				447
			 | 
			
			
				+    if unsettled > 0: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				448
			 | 
			
			
				+        first = status['unsettled']['first'] 
			 | 
		
	
		
			
			| 
				
			 | 
			
				449
			 | 
			
			
				+        first_date = first.strftime('%c') 
			 | 
		
	
		
			
			| 
				
			 | 
			
				450
			 | 
			
			
				+        ok = QMessageBox.information( 
			 | 
		
	
		
			
			| 
				
			 | 
			
				451
			 | 
			
			
				+            None, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				452
			 | 
			
			
				+            "Onafgesloten lijst", 
			 | 
		
	
		
			
			| 
				
			 | 
			
				453
			 | 
			
			
				+            f"Wil je verdergaan met een lijst met {unsettled} onafgesloten " 
			 | 
		
	
		
			
			| 
				
			 | 
			
				454
			 | 
			
			
				+            f"consumpties sinds {first_date}?", 
			 | 
		
	
		
			
			| 
				
			 | 
			
				455
			 | 
			
			
				+            QMessageBox.Yes, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				456
			 | 
			
			
				+            QMessageBox.No 
			 | 
		
	
		
			
			| 
				
			 | 
			
				457
			 | 
			
			
				+        ) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				458
			 | 
			
			
				+        if ok == QMessageBox.No: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				459
			 | 
			
			
				+            main_window.show_keyboard() 
			 | 
		
	
		
			
			| 
				
			 | 
			
				460
			 | 
			
			
				+            name, ok = QInputDialog.getText( 
			 | 
		
	
		
			
			| 
				
			 | 
			
				461
			 | 
			
			
				+                None, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				462
			 | 
			
			
				+                "Lijst afsluiten", 
			 | 
		
	
		
			
			| 
				
			 | 
			
				463
			 | 
			
			
				+                "Voer een naam in voor de lijst of druk op OK. Laat de datum " 
			 | 
		
	
		
			
			| 
				
			 | 
			
				464
			 | 
			
			
				+                "staan.", 
			 | 
		
	
		
			
			| 
				
			 | 
			
				465
			 | 
			
			
				+                QLineEdit.Normal, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				466
			 | 
			
			
				+                f"{first.strftime('%Y-%m-%d')}" 
			 | 
		
	
		
			
			| 
				
			 | 
			
				467
			 | 
			
			
				+            ) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				468
			 | 
			
			
				+            main_window.hide_keyboard() 
			 | 
		
	
		
			
			| 
				
			 | 
			
				469
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				470
			 | 
			
			
				+            if name and ok: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				471
			 | 
			
			
				+                settlement = Settlement.create(name) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				472
			 | 
			
			
				+                info = [f'{item["count"]} {item["name"]}' for item in 
			 | 
		
	
		
			
			| 
				
			 | 
			
				473
			 | 
			
			
				+                settlement.consumption_summary.values()] 
			 | 
		
	
		
			
			| 
				
			 | 
			
				474
			 | 
			
			
				+                info = ', '.join(info) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				475
			 | 
			
			
				+                QMessageBox.information( 
			 | 
		
	
		
			
			| 
				
			 | 
			
				476
			 | 
			
			
				+                    None, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				477
			 | 
			
			
				+                    "Lijst afgesloten", 
			 | 
		
	
		
			
			| 
				
			 | 
			
				478
			 | 
			
			
				+                    f"VO! Op deze lijst stonden: {info}" 
			 | 
		
	
		
			
			| 
				
			 | 
			
				479
			 | 
			
			
				+                ) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				480
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				481
			 | 
			
			
				+                main_window = PiketMainWindow() 
			 | 
		
	
		
			
			| 
				
			 | 
			
				482
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				432
			 | 
			
				483
			 | 
			
			
				     main_window.show() 
			 | 
		
	
		
			
			| 
				433
			 | 
			
				484
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				434
			 | 
			
				485
			 | 
			
			
				     # Let's go 
			 |