Updated invoice generation / client updates
This commit is contained in:
parent
4fa15681b1
commit
4b616da939
1 changed files with 105 additions and 46 deletions
151
gui/__main__.py
151
gui/__main__.py
|
@ -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))
|
||||||
expires_at = profile.subscription.expires_at.strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
||||||
self.subscription_info["expires_at"].setText(expires_at)
|
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")
|
||||||
|
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.":
|
self.text_fields[3].setText(text)
|
||||||
for field in self.text_fields:
|
|
||||||
field.setText('')
|
|
||||||
else:
|
|
||||||
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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue