checkout_page.py (13808B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\omega\upsell\pages\checkout_page.py 2 import carbonui 3 import carbonui.text.styles 4 import eveicon 5 import uthread2 6 from carbonui import Align, ButtonVariant, ButtonStyle, Density, AxisAlignment, TextColor, uiconst, TextAlign 7 from carbonui.button.const import HEIGHT_EXPANDED 8 from carbonui.button.group import ButtonGroup 9 from carbonui.control.button import Button 10 from carbonui.primitives.container import Container 11 from carbonui.primitives.containerAutoSize import ContainerAutoSize 12 from carbonui.primitives.layoutGrid import LayoutGrid 13 from carbonui.primitives.line import Line 14 from carbonui.primitives.sprite import Sprite 15 from carbonui.uianimations import animations 16 from eve.client.script.ui import eveColor 17 from eve.client.script.ui.control.eveLoadingWheel import LoadingWheel 18 from eve.client.script.ui.control.infoIcon import InfoIcon 19 from eve.client.script.ui.omega.upsell import omegaUpsellSignals 20 from eve.client.script.ui.omega.upsell.omegaUpsellConst import OmegaUpsellPage 21 from localization import GetByLabel 22 from player_messaging.client.ui_message import prompt_player_fsd_dialog 23 from stackless_response_router.exceptions import TimeoutException 24 from store.client.offers.offer_provider_svc import get_offer_provider_svc 25 from store.client.payment.purchase.errors import InsufficientFunds, PurchaseFailed 26 from store.client.payment.signal import on_quick_pay_cache_invalidated 27 from store.client.payment.store_payment_svc import get_store_payment_svc 28 from store.client.payment.token.errors import RedirectRequired 29 from vgs.client.currency import get_price_text 30 31 class CheckoutPage(Container): 32 33 def __init__(self, offer_id, use_plex = False, **kw): 34 super(CheckoutPage, self).__init__(**kw) 35 self.offer_id = offer_id 36 self.use_plex = use_plex 37 self._quick_pay_details_cont = None 38 self._quick_pay_details_loading_wheel = None 39 self.offer = get_offer_provider_svc().get_omega_subscription_offer(self.offer_id) 40 self.construct_base_layout() 41 self.reconstruct_layout() 42 on_quick_pay_cache_invalidated.connect(self._on_cache_invalidated) 43 44 def __del__(self): 45 on_quick_pay_cache_invalidated.disconnect(self._on_cache_invalidated) 46 get_store_payment_svc().clear_cache() 47 48 def construct_base_layout(self): 49 content = Container(parent=self, align=Align.HORIZONTALLY_CENTERED, width=0.7, minWidth=800) 50 inner_content = Container(parent=content, align=Align.TOLEFT_PROP, width=0.3, minWidth=500) 51 self.left_cont = ContainerAutoSize(name='left_cont', parent=inner_content, align=Align.VERTICALLY_CENTERED, alignMode=Align.TOTOP) 52 omegaUpsellSignals.set_hero_image('res:/UI/Texture/Classes/OmegaUpsell/checkout_hero_image.png', allow_crop=True) 53 54 def reconstruct_layout(self): 55 store_payment_svc = get_store_payment_svc() 56 if store_payment_svc.is_quick_pay_enabled() or self.use_plex: 57 self.reconstruct_layout_quick_pay() 58 uthread2.start_tasklet(self.update_quick_pay) 59 if not self.use_plex: 60 uthread2.start_tasklet(self._load_quick_pay_details_text) 61 else: 62 self.reconstruct_layout_web_checkout() 63 store_payment_svc.open_offer_checkout_page_in_browser(self.offer_id) 64 65 def reconstruct_layout_web_checkout(self): 66 self.left_cont.Flush() 67 carbonui.text.styles.TextHeadline(parent=self.left_cont, align=Align.TOTOP, bold=True, color=TextColor.SECONDARY, text=GetByLabel('UI/OmegaUpsell/CompletePurchaseInBrowser')) 68 button_group = ButtonGroup(parent=self.left_cont, padTop=64, align=Align.TOTOP, button_alignment=AxisAlignment.START) 69 Button(parent=button_group, label=GetByLabel('UI/Common/Buttons/Cancel'), func=self.on_cancel_button, variant=ButtonVariant.NORMAL, density=Density.EXPANDED) 70 71 def reconstruct_layout_quick_pay(self): 72 self.left_cont.Flush() 73 carbonui.text.styles.TextHeadline(parent=self.left_cont, align=Align.TOTOP, bold=True, color=eveColor.OMEGA_YELLOW, text=GetByLabel('UI/OmegaUpsell/OrderSummary')) 74 self.construct_offer_entry() 75 self.construct_tax_entry() 76 Line(parent=self.left_cont, align=Align.TOTOP, padTop=32, color=eveColor.WHITE, opacity=0.5) 77 self.construct_total_entry() 78 if not self.use_plex: 79 self.construct_quick_pay_details_entry() 80 if self.is_recurring(): 81 self.construct_recurring_warning_text() 82 self.construct_buttons() 83 84 def is_recurring(self): 85 if self.use_plex: 86 return False 87 return self.offer.is_recurring() 88 89 def construct_buttons(self): 90 button_cont = Container(parent=self.left_cont, align=Align.TOTOP, height=HEIGHT_EXPANDED, padTop=48) 91 self.activate_btn = Button(parent=button_cont, label=GetByLabel('UI/OmegaUpsell/Activate'), func=self.on_activate_button, variant=ButtonVariant.PRIMARY, density=Density.EXPANDED, style=ButtonStyle.MONETIZATION) 92 self.payment_processing_cont = ContainerAutoSize(name='payment_processing_cont', parent=button_cont, align=Align.CENTERRIGHT, display=False) 93 LoadingWheel(parent=self.payment_processing_cont, align=Align.CENTERLEFT, width=32, height=32) 94 carbonui.text.styles.TextHeader(parent=self.payment_processing_cont, color=eveColor.OMEGA_YELLOW, align=Align.CENTERLEFT, text=GetByLabel('UI/OmegaUpsell/PaymentProcessing'), left=44) 95 96 def construct_recurring_warning_text(self): 97 recurring_warning_cont = LayoutGrid(name='recurring_warning_cont', parent=self.left_cont, align=Align.TOTOP, padding=(0, 12, 0, 0), columns=2, cellSpacing=(8, 0)) 98 carbonui.text.styles.TextBody(parent=recurring_warning_cont, align=Align.CENTERLEFT, text=GetByLabel('UI/OmegaUpsell/RecurringWarningHeader'), color=TextColor.NORMAL) 99 InfoIcon(parent=recurring_warning_cont, align=Align.CENTERLEFT, hint=GetByLabel('UI/OmegaUpsell/RecurringWarningText')) 100 101 def construct_tax_entry(self): 102 self.tax_entry = ContainerAutoSize(parent=self.left_cont, align=Align.TOTOP, alignMode=Align.CENTERLEFT, padTop=8, display=False) 103 carbonui.text.styles.TextHeader(parent=self.tax_entry, align=Align.CENTERLEFT, color=TextColor.NORMAL, text=GetByLabel('UI/OmegaUpsell/TaxAmount')) 104 self.tax_amount_label = carbonui.text.styles.TextHeader(parent=self.tax_entry, align=Align.CENTERRIGHT, color=TextColor.NORMAL) 105 106 def construct_offer_entry(self): 107 offer_cont = ContainerAutoSize(parent=self.left_cont, align=Align.TOTOP, alignMode=Align.CENTERLEFT, padTop=48) 108 self.offer_name_label = carbonui.text.styles.TextHeader(parent=offer_cont, align=Align.CENTERLEFT, color=eveColor.OMEGA_YELLOW) 109 if self.use_plex: 110 layout_grid = LayoutGrid(parent=offer_cont, align=Align.CENTERRIGHT, columns=2) 111 Sprite(parent=layout_grid, pos=(0, 0, 16, 16), align=Align.CENTERLEFT, texturePath=eveicon.plex, color=eveColor.PLEX_YELLOW) 112 self.offer_price_label = carbonui.text.styles.TextHeader(parent=layout_grid, align=Align.CENTERLEFT, color=eveColor.WHITE) 113 else: 114 self.offer_price_label = carbonui.text.styles.TextHeader(parent=offer_cont, align=Align.CENTERRIGHT, color=eveColor.WHITE) 115 116 def construct_quick_pay_details_entry(self): 117 self._quick_pay_details_cont = Container(parent=self.left_cont, align=Align.TOTOP, padTop=32, height=40, bgColor=tuple(eveColor.OMEGA_SECONDARY[:3]) + (0.8,)) 118 self._quick_pay_details_loading_wheel = LoadingWheel(parent=self._quick_pay_details_cont, align=Align.CENTER, width=32, height=32, display=True) 119 left_cont = Container(parent=self._quick_pay_details_cont, align=Align.TOLEFT_PROP, width=0.5) 120 self._card_number_text = carbonui.text.styles.TextBody(parent=left_cont, align=Align.VERTICALLY_CENTERED, color=TextColor.HIGHLIGHT, padLeft=8) 121 right_cont = Container(parent=self._quick_pay_details_cont, align=Align.TORIGHT_PROP, width=0.5) 122 self._card_exp_text = carbonui.text.styles.TextBody(parent=right_cont, align=Align.VERTICALLY_CENTERED, color=TextColor.HIGHLIGHT, textAlign=TextAlign.RIGHT, padRight=8) 123 124 def _load_quick_pay_details_text(self): 125 if not self._quick_pay_details_loading_wheel or not self._quick_pay_details_cont: 126 return 127 try: 128 self._quick_pay_details_loading_wheel.opacity = 1.0 129 token_id = self.get_token_id() 130 token_details = None 131 if token_id: 132 token_details = get_store_payment_svc().get_quick_pay_token(token_id) 133 if token_details: 134 self._card_number_text.text = GetByLabel('UI/OmegaUpsell/CreditCardNumber', card_number=token_details.formatted_card_alias) 135 self._card_exp_text.text = GetByLabel('UI/OmegaUpsell/CreditCardExpiry', expiry_date=token_details.formatted_card_expiry) 136 else: 137 self._quick_pay_details_cont.opacity = 0.0 138 except TimeoutException: 139 self._quick_pay_details_cont.opacity = 0.0 140 finally: 141 animations.FadeOut(self._quick_pay_details_loading_wheel) 142 143 def construct_total_entry(self): 144 total_cont = ContainerAutoSize(parent=self.left_cont, align=Align.TOTOP, alignMode=Align.CENTERLEFT, padTop=32) 145 carbonui.text.styles.TextDisplay(parent=total_cont, align=Align.CENTERLEFT, color=eveColor.WHITE, text=GetByLabel('UI/OmegaUpsell/Total')) 146 if self.use_plex: 147 layout_grid = LayoutGrid(parent=total_cont, align=Align.CENTERRIGHT, columns=2) 148 Sprite(parent=layout_grid, pos=(0, 0, 32, 32), align=Align.CENTERLEFT, texturePath=eveicon.plex, color=eveColor.PLEX_YELLOW) 149 self.total_price_label = carbonui.text.styles.TextDisplay(parent=layout_grid, align=Align.CENTERRIGHT, color=eveColor.WHITE) 150 else: 151 self.total_price_label = carbonui.text.styles.TextDisplay(parent=total_cont, align=Align.CENTERRIGHT, color=eveColor.OMEGA_YELLOW) 152 153 def update_quick_pay(self): 154 offer = get_offer_provider_svc().get_omega_subscription_offer(offer_id=self.offer_id) 155 self.offer_name_label.text = offer.localized_name 156 if self.use_plex: 157 self.offer_price_label.text = offer.total_price_in_plex_text 158 self.total_price_label.text = offer.total_price_in_plex_text 159 else: 160 taxed_price = get_store_payment_svc().get_taxed_price_info(self.offer.price_before_tax, self.get_token_id()) 161 if taxed_price is not None: 162 self.update_offer_price_entry(taxed_price) 163 self.update_tax_entry(taxed_price) 164 self.update_total_price(taxed_price) 165 166 def update_total_price(self, taxed_price): 167 total_price = get_price_text(taxed_price.total_price_in_cents / 100.0, taxed_price.currency_code, useSpace=not self.use_plex) 168 self.total_price_label.text = total_price 169 170 def update_offer_price_entry(self, taxed_price): 171 offer_price_text = get_price_text(taxed_price.price_in_cents_before_tax / 100.0, taxed_price.currency_code) 172 self.offer_price_label.text = offer_price_text 173 174 def update_tax_entry(self, taxed_price): 175 tax_amount = taxed_price.tax_amount_in_cents 176 if tax_amount > 0: 177 self.tax_entry.display = True 178 tax_text = get_price_text(tax_amount / 100.0, taxed_price.currency_code) 179 self.tax_amount_label.text = tax_text 180 181 def on_activate_button(self, *args): 182 try: 183 self.activate_btn.disabled = True 184 self.activate_btn.busy = True 185 self.payment_processing_cont.display = True 186 if self.use_plex: 187 self.activate_with_plex() 188 else: 189 self.activate_with_money() 190 finally: 191 self.activate_btn.disabled = False 192 self.activate_btn.busy = False 193 self.payment_processing_cont.display = False 194 195 def activate_with_money(self): 196 payment_svc = get_store_payment_svc() 197 try: 198 token_id = self.get_token_id() 199 cost_info = payment_svc.get_taxed_price_info(self.offer.price_before_tax, token_id) 200 if cost_info is None: 201 raise RedirectRequired 202 payment_svc.purchase_with_token(self.offer_id, quantity=1, cost_information=cost_info, token_id=token_id) 203 except RedirectRequired: 204 prompt_player_fsd_dialog('PurchaseWebCheckoutRequired') 205 get_store_payment_svc().open_offer_checkout_page_in_browser(self.offer_id) 206 self.reconstruct_layout_web_checkout() 207 except PurchaseFailed as e: 208 prompt_player_fsd_dialog(e.get_localized_error_dialog_key()) 209 omegaUpsellSignals.load_page(OmegaUpsellPage.LANDING) 210 except: 211 prompt_player_fsd_dialog('OmegaUpsellPurchaseFailed') 212 omegaUpsellSignals.load_page(OmegaUpsellPage.LANDING) 213 raise 214 215 def get_token_id(self): 216 return get_store_payment_svc().get_default_quick_pay_token_identifier() 217 218 def activate_with_plex(self): 219 payment_svc = get_store_payment_svc() 220 try: 221 payment_svc.purchase_with_plex(self.offer_id, 1) 222 except InsufficientFunds: 223 prompt_player_fsd_dialog('PurchaseFailedInsufficientFunds') 224 omegaUpsellSignals.load_page(OmegaUpsellPage.LANDING) 225 except: 226 prompt_player_fsd_dialog('OmegaUpsellPurchaseFailed') 227 omegaUpsellSignals.load_page(OmegaUpsellPage.LANDING) 228 raise 229 230 def on_cancel_button(self, *args): 231 omegaUpsellSignals.load_page(OmegaUpsellPage.LANDING) 232 233 def _on_cache_invalidated(self, *args): 234 self.reconstruct_layout()