Updated invoice generation / client updates

This commit is contained in:
Your Name 2025-04-10 11:39:57 +01:00
parent 4fa15681b1
commit 4b616da939

View file

@ -48,7 +48,7 @@ profile_observer = ProfileObserver()
class WorkerThread(QThread): class WorkerThread(QThread):
text_output = pyqtSignal(str) text_output = pyqtSignal(str)
sync_output = pyqtSignal(list, bool, bool, list, bool) sync_output = pyqtSignal(list, bool, bool, list, bool)
invoice_output = pyqtSignal(dict, str) invoice_output = pyqtSignal(object, str)
invoice_finished = pyqtSignal(bool) invoice_finished = pyqtSignal(bool)
profiles_output = pyqtSignal(dict) profiles_output = pyqtSignal(dict)
special_output = pyqtSignal(str) special_output = pyqtSignal(str)
@ -95,6 +95,24 @@ class WorkerThread(QThread):
self.check_for_update() self.check_for_update()
elif self.action == 'DOWNLOAD_UPDATE': elif self.action == 'DOWNLOAD_UPDATE':
self.download_update() self.download_update()
elif self.action == 'CHECK_INVOICE_STATUS':
self.check_invoice_status()
def check_invoice_status(self):
try:
invoice = InvoiceController.get(self.profile_data['billing_code'])
if invoice:
status = invoice.status
if status == "expired":
self.invoice_finished.emit(False)
else:
self.invoice_finished.emit(True)
else:
self.invoice_finished.emit(False)
except Exception as e:
print(f"Error retrieving invoice: {str(e)}")
self.invoice_finished.emit(False)
def download_update(self): def download_update(self):
self.text_output.emit("Starting update process...") self.text_output.emit("Starting update process...")
@ -106,6 +124,7 @@ class WorkerThread(QThread):
def check_for_update(self): def check_for_update(self):
self.text_output.emit("Checking for updates...") self.text_output.emit("Checking for updates...")
ClientController.sync(client_observer=client_observer, connection_observer=connection_observer)
update_available = ClientController.can_be_updated() update_available = ClientController.can_be_updated()
if update_available: if update_available:
self.text_output.emit("An update is available. Downloading...") self.text_output.emit("An update is available. Downloading...")
@ -214,7 +233,6 @@ class WorkerThread(QThread):
ConfigurationController.set_connection('system') ConfigurationController.set_connection('system')
ClientController.sync(client_observer=client_observer, connection_observer=connection_observer) ClientController.sync(client_observer=client_observer, connection_observer=connection_observer)
locations = LocationController.get_all() locations = LocationController.get_all()
print(f'locations: {locations}')
all_location_codes = [location.country_name for location in locations] all_location_codes = [location.country_name for location in locations]
self.sync_output.emit(all_location_codes, True, False, locations, False) self.sync_output.emit(all_location_codes, True, False, locations, False)
except Exception as e: except Exception as e:
@ -275,29 +293,17 @@ class WorkerThread(QThread):
self.text_output.emit('An unknown error occurred') self.text_output.emit('An unknown error occurred')
self.invoice_finished.emit(False) self.invoice_finished.emit(False)
def _get_billing_details(self, invoice, currency_code):
for payment_method in invoice.payment_methods:
if payment_method.code == currency_code:
return {
'billing_code': invoice.billing_code,
'due_amount': payment_method.due,
'address': payment_method.address
}
return f"Payment method for currency '{currency_code}' not found."
def handle_connection_events(self, event): def handle_connection_events(self, event):
self.text_output.emit(f'Profile disabled') self.text_output.emit(f'Profile disabled')
def handle_event(self, event, currency): def handle_event(self, event, currency=None):
invoice = event.subject invoice = event.subject
billing_details = self._get_billing_details(invoice, currency) if isinstance(invoice, object):
if isinstance(billing_details, dict): self.invoice_output.emit(invoice, '')
self.invoice_output.emit(billing_details, '')
self.text_output.emit("Invoice generated. Awaiting payment...") self.text_output.emit("Invoice generated. Awaiting payment...")
else: else:
self.text_output.emit("No payment method found for the selected currency.") self.text_output.emit("Invalid invoice data received.")
class CustomWindow(QMainWindow): class CustomWindow(QMainWindow):
@ -507,7 +513,6 @@ class CustomWindow(QMainWindow):
self.animation_timer = QTimer() self.animation_timer = QTimer()
self.animation_timer.timeout.connect(self.animate_toggle) self.animation_timer.timeout.connect(self.animate_toggle)
# Create background
self.toggle_bg = QLabel(self.toggle_button) self.toggle_bg = QLabel(self.toggle_button)
self.toggle_bg.setGeometry(0, 0, 50, 22) self.toggle_bg.setGeometry(0, 0, 50, 22)
@ -521,14 +526,12 @@ class CustomWindow(QMainWindow):
} }
""") """)
# Create ON/OFF labels
self.on_label = QLabel("ON", self.toggle_button) self.on_label = QLabel("ON", self.toggle_button)
self.on_label.setGeometry(8, 4, 15, 14) self.on_label.setGeometry(8, 4, 15, 14)
self.off_label = QLabel("OFF", self.toggle_button) self.off_label = QLabel("OFF", self.toggle_button)
self.off_label.setGeometry(25, 4, 40, 14) self.off_label.setGeometry(25, 4, 40, 14)
# Apply colors
self._update_toggle_colors(colors) self._update_toggle_colors(colors)
if is_tor_mode: if is_tor_mode:
self.set_tor_icon() self.set_tor_icon()
@ -1022,13 +1025,14 @@ class Worker(QObject):
self.update_signal.emit("Application version file integrity could not be verified.", False, None, None, None) self.update_signal.emit("Application version file integrity could not be verified.", False, None, None, None)
except ProfileModificationError: except ProfileModificationError:
self.update_signal.emit("WireGuard configuration could not be attached.", False, None, None, None) self.update_signal.emit("WireGuard configuration could not be attached.", False, None, None, None)
except OSError: #except OSError:
self.update_signal.emit("Connection could not be established.", False, None, None, None) # self.update_signal.emit("Connection could not be established.", False, None, None, None)
except ProfileStateConflictError: except ProfileStateConflictError:
self.update_signal.emit("The profile is already being enabled...", False, None, None, None) self.update_signal.emit("The profile is already being enabled...", False, None, None, None)
except CommandNotFoundError as e : except CommandNotFoundError as e :
self.update_signal.emit(str(e), False, -1, None, None) self.update_signal.emit(str(e), False, -1, None, None)
except Exception as e: except Exception as e:
print(e)
self.update_signal.emit("An unknown error occurred", False, None, None, None) self.update_signal.emit("An unknown error occurred", False, None, None, None)
else: else:
@ -4619,8 +4623,12 @@ class Settings(Page):
if profile and hasattr(profile, 'subscription') and profile.subscription: if profile and hasattr(profile, 'subscription') and profile.subscription:
try: try:
self.subscription_info["billing_code"].setText(str(profile.subscription.billing_code)) self.subscription_info["billing_code"].setText(str(profile.subscription.billing_code))
if hasattr(profile.subscription, 'expires_at') and profile.subscription.expires_at:
expires_at = profile.subscription.expires_at.strftime("%Y-%m-%d %H:%M:%S UTC") expires_at = profile.subscription.expires_at.strftime("%Y-%m-%d %H:%M:%S UTC")
self.subscription_info["expires_at"].setText(expires_at) self.subscription_info["expires_at"].setText(expires_at)
else:
self.subscription_info["expires_at"].setText("Not available")
except Exception as e: except Exception as e:
print(f"Error updating subscription info: {e}") print(f"Error updating subscription info: {e}")
else: else:
@ -5048,31 +5056,39 @@ class PaymentPage(Page):
super().__init__("Payment", page_stack, main_window, parent) super().__init__("Payment", page_stack, main_window, parent)
self.update_status = main_window self.update_status = main_window
self.text_fields = [] self.text_fields = []
self.invoice_data = {}
self.create_interface_elements() self.create_interface_elements()
self.button_reverse.setVisible(True) self.button_reverse.setVisible(True)
def fetch_invoice_duration(self):
def on_request_invoice(self):
selected_currency = self.get_selected_currency()
selected_time = self.get_selected_time_length() selected_time = self.get_selected_time_length()
if selected_currency:
self.currency = selected_currency
else:
self.update_status.update_status('No currency selected')
return
duration_month_num = int(selected_time.split()[0]) duration_month_num = int(selected_time.split()[0])
if duration_month_num == 12: if duration_month_num == 12:
total_hours = 365 * 24 total_hours = 365 * 24
else: else:
total_hours = duration_month_num * (30 * 24) total_hours = duration_month_num * (30 * 24)
return total_hours
def check_invoice(self):
total_hours = self.fetch_invoice_duration()
if self.invoice_data and self.invoice_data['duration'] == total_hours:
self.update_status.update_status('Checking invoice status...')
self.check_invoice_status(self.invoice_data['billing_details'].billing_code)
else:
self.on_request_invoice()
def on_request_invoice(self):
total_hours = self.fetch_invoice_duration()
selected_currency = self.get_selected_currency()
if selected_currency is None:
self.update_status.update_status('No currency selected')
return
profile_data = { profile_data = {
'id': int(self.update_status.current_profile_id), 'id': int(self.update_status.current_profile_id),
'duration': total_hours, 'duration': total_hours,
'currency': 'xmr' if self.currency == 'monero' else 'btc' if self.currency == 'bitcoin' else 'btc-ln' if self.currency == 'lightning' else 'ltc' if self.currency == 'litecoin' else None 'currency': 'xmr' if selected_currency == 'monero' else 'btc' if selected_currency == 'bitcoin' else 'btc-ln' if selected_currency == 'lightning' else 'ltc' if selected_currency == 'litecoin' else None
} }
self.update_status.update_status('Generating Invoice...') self.update_status.update_status('Generating Invoice...')
self.worker_thread = WorkerThread('GET_SUBSCRIPTION', profile_data=profile_data) self.worker_thread = WorkerThread('GET_SUBSCRIPTION', profile_data=profile_data)
@ -5083,13 +5099,57 @@ class PaymentPage(Page):
def invoice_update_text_output(self, text): def invoice_update_text_output(self, text):
self.update_status.update_status(text) self.update_status.update_status(text)
if text == "No payment method found for the selected currency.":
for field in self.text_fields:
field.setText('')
else:
self.text_fields[3].setText(text) self.text_fields[3].setText(text)
def on_invoice_generation_finished(self, billing_details: dict, text: str): if 'No compatible' in text:
for line in self.text_fields:
line.setText('')
def store_invoice_data(self, billing_details: dict, duration: int):
self.invoice_data = {
'billing_details': billing_details,
'duration': duration
}
def check_invoice_status(self, billing_code: str):
self.worker_thread = WorkerThread('CHECK_INVOICE_STATUS', profile_data={'billing_code': billing_code})
self.worker_thread.invoice_finished.connect(self.on_invoice_status_finished)
self.worker_thread.start()
def on_invoice_status_finished(self, result):
if result:
self.update_status.update_status('Invoice is still valid. Parsing invoice data...')
self.parse_invoice_data(self.invoice_data['billing_details'])
else:
self.update_status.update_status('Invoice has expired. Generating new invoice...')
self.on_request_invoice()
def on_invoice_generation_finished(self, billing_details: object, text: str):
total_hours = self.fetch_invoice_duration()
self.store_invoice_data(billing_details, duration=total_hours)
self.parse_invoice_data(billing_details)
def parse_invoice_data(self, invoice_data: object):
currency = self.get_selected_currency()
billing_details = {
'billing_code': invoice_data.billing_code
}
if currency.lower() == 'lightning':
currency = 'Bitcoin Lightning'
preferred_method = next((pm for pm in invoice_data.payment_methods if pm.name.lower() == currency.lower()), None)
if preferred_method:
billing_details['due_amount'] = preferred_method.due
billing_details['address'] = preferred_method.address
else:
self.update_status.update_status('No payment method found for the selected currency.')
return
billing_values = list(billing_details.values()) billing_values = list(billing_details.values())
for i, dict_value in enumerate(billing_values): for i, dict_value in enumerate(billing_values):
if i < 3: if i < 3:
@ -5103,11 +5163,10 @@ class PaymentPage(Page):
else: else:
self.text_fields[i].setProperty("fullText", str(dict_value)) self.text_fields[i].setProperty("fullText", str(dict_value))
self.text_fields[i].setText(str(dict_value)) self.text_fields[i].setText(str(dict_value))
self.text_fields[3].setText(text)
def on_invoice_finished(self, result): def on_invoice_finished(self, result):
if result: if result:
self.invoice_data.clear()
self.show_payment_confirmed(self.text_fields[0].text()) self.show_payment_confirmed(self.text_fields[0].text())
return return
self.update_status.update_status('An error occurred when generating invoice') self.update_status.update_status('An error occurred when generating invoice')
@ -5230,7 +5289,7 @@ class PaymentPage(Page):
self.buttonGroup.addButton(boton, j) self.buttonGroup.addButton(boton, j)
boton.setIcon(QIcon(os.path.join(self.btn_path, f"{icon_name}.png"))) boton.setIcon(QIcon(os.path.join(self.btn_path, f"{icon_name}.png")))
#boton.clicked.connect(lambda _, func=function: func()) #boton.clicked.connect(lambda _, func=function: func())
boton.clicked.connect(self.on_request_invoice) boton.clicked.connect(self.check_invoice)
# Establecer la exclusividad de los botones # Establecer la exclusividad de los botones