# core from core.services.subscriptions.subscriptions_by_protocol import start_billing_state from core.models.enum_models import PaymentCategory # gui # from gui.v2.actions.payment_actions import start_billing_state from gui.v2.ui.pages.Page import Page from gui.v2.ui.styles.styles import TERMINAL_LIST_QSS from gui.v2.workers.ticketing_worker_thread import TicketingWorkerThread # generic from PyQt6.QtWidgets import QLabel, QListWidget, QListWidgetItem from PyQt6 import QtCore class PlanPickerPage(Page): def __init__(self, page_stack, main_window=None, parent=None): super().__init__("PickPlan", page_stack, main_window, parent) self.update_status = main_window # this page only, immediate pricing display: self.pricing_data = None # cross page cache overall data: self.billing_data = None self.worker = None self.title.setText("Pick a Plan") self.title.setGeometry(QtCore.QRect(290, 30, 220, 40)) self.title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.button_reverse.setVisible(True) self.button_reverse.clicked.connect(self.reverse) self.intro_label = QLabel( "All members of the group expire at the same time. How much you pay depends on when you join.", self) self.intro_label.setGeometry(40, 90, 720, 40) self.intro_label.setStyleSheet("color: white; font-size: 13px;") self.intro_label.setWordWrap(True) self.intro_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.plan_list = QListWidget(self) self.plan_list.setGeometry(60, 140, 680, 320) self.plan_list.setStyleSheet(TERMINAL_LIST_QSS) self.plan_list.itemClicked.connect(self.on_plan_clicked) self.status_label = QLabel("", self) self.status_label.setGeometry(60, 470, 680, 30) self.status_label.setStyleSheet("color: #cccccc; font-size: 13px;") self.status_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) def start_sync(self): # STATE result = start_billing_state(category=PaymentCategory.TICKET) if not result.valid: error_msg = result.message if error_msg: self.show_a_popup(str(error_msg)) else: self.show_a_popup("Error with Starting Billing") # cache data to save the choice to it: self.billing_data = result.data # Begin Tickets: self.plan_list.clear() self.status_label.setText("Syncing prices...") self.update_status.update_status("Syncing ticket prices...") self.worker = TicketingWorkerThread('SYNC_PRICES') self.worker.sync_done.connect(self.on_sync_done) self.worker.error.connect(self.on_error) self.worker.start() def on_sync_done(self, pricing_data): if isinstance(pricing_data, dict) and pricing_data.get('valid') is False: err = pricing_data.get('error_code', 'unknown') self.status_label.setText(f"Sync failed: {err}") self.update_status.update_status(f"Sync failed: {err}") return if isinstance(pricing_data, dict) and isinstance(pricing_data.get('data'), dict): plans = pricing_data['data'] elif isinstance(pricing_data, dict): plans = pricing_data else: self.status_label.setText("Unexpected pricing data.") return self.pricing_data = plans self.populate_plans(plans) self.status_label.setText("Pick a plan above.") self.update_status.update_status("Plans loaded.") def populate_plans(self, pricing_data): self.plan_list.clear() if not isinstance(pricing_data, dict): self.status_label.setText("Unexpected pricing data.") return for plan_key, plan_data in pricing_data.items(): if not isinstance(plan_data, dict): continue cost = plan_data.get('cost', '?') months = plan_data.get('months', '?') days = plan_data.get('days', '?') profiles = plan_data.get('profiles', '?') label = f" Plan {plan_key} | €{cost} | {months}months {days}d left | {profiles} profiles" item = QListWidgetItem(label) item.setData(QtCore.Qt.ItemDataRole.UserRole, plan_key) self.plan_list.addItem(item) def on_plan_clicked(self, item): plan_key = item.data(QtCore.Qt.ItemDataRole.UserRole) if not plan_key: return print(f"plan_key is {plan_key}") # in temp cache save choice: self.billing_data.which_key = plan_key # go to next page: currency_page = self.custom_window.navigator.get_cached("currency_selection") if currency_page is not None: self.custom_window.navigator.navigate("currency_selection") # self.custom_window.navigator.navigate("ticket_crypto_picker") # crypto_page = self.custom_window.navigator.get_cached("ticket_crypto_picker") # if crypto_page is not None: # crypto_page.set_selected_plan(plan_key) def on_error(self, msg): self.status_label.setText(f"Error: {msg}") self.update_status.update_status(f"Sync error: {msg}") def reverse(self): self.custom_window.navigator.navigate("id")