NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

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()