lpStoreSvc.py (23062B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\station\loyaltyPointStore\lpStoreSvc.py 2 import copy 3 import blue 4 import evetypes 5 import localization 6 import log 7 import sys 8 import telemetry 9 import uthread 10 from featuremanagement.client.flag import flag_bool 11 from appConst import corpHeraldry 12 from carbon.client.script.util.misc import TryDel 13 from carbon.common.script.sys.service import Service 14 from carbonui import uiconst 15 from carbonui.util.bunch import Bunch 16 from caching.memoize import Memoize 17 from collections import defaultdict 18 from carbon.common.script.util.format import FmtAmt 19 from corporation.common import FLAG_CORP_LP_PURCHASES_KILLSWITCH, FLAG_CORP_LP_PURCHASES_KILLSWITCH_DEFAULT 20 from cosmetics.common import cosmeticsConst 21 from eve.client.script.ui.station.loyaltyPointStore.lpExchangeDialog import LPExhangeDialog 22 from eve.client.script.ui.station.loyaltyPointStore.lpStoreSignals import on_corp_lp_purchases_killswitch_changed 23 from eve.client.script.ui.station.loyaltyPointStore.lpStoreWindow import LPStoreWindow 24 from eve.client.script.ui.station.loyaltyPointStore.lpUtil import GetItemText 25 from eve.client.script.ui.station.loyaltyPointStore.paragonLpStoreConst import DEFAULT_PARAGON_FILTERS 26 from eve.client.script.ui.station.lpstoreRequirement import LpRequirement, ISKRequirement, AnalysisKreditsRequirement, EMRequirement 27 from eve.common.lib import appConst 28 from eve.common.script.sys import idCheckers 29 from eve.common.script.util.facwarCommon import GetFwFactionIDForNpcCorp, IsPirateFWFaction 30 from loyaltypoints.lpUtil import get_hardcoded_lp_stations_for_corp 31 from npcs.npccorporations import get_corporation_exchange_rates 32 from player_messaging.client.ui_message import prompt_player_fsd_dialog 33 from resourcewars.common.const import FACTION_TO_RW_LP_CORP 34 from uthread2 import BufferedCall 35 36 class LPStoreSvc(Service): 37 __guid__ = 'svc.lpstore' 38 __notifyevents__ = ['OnAccountChange', 39 'ProcessSessionChange', 40 'OnCharacterLPBalanceChange_Local', 41 'OnCorporationLPBalanceChange_Local', 42 'OnAnalysisKreditsChange', 43 'OnItemChangeProcessed'] 44 __dependencies__ = ['settings', 45 'clientPathfinderService', 46 'loyaltyPointsWalletSvc', 47 'wallet'] 48 settingsVersion = 4 49 50 def Run(self, *etc): 51 Service.Run(self, *etc) 52 self.cache = Bunch() 53 self._ClearCache() 54 self.LpOfferRequirements = {} 55 self.defaultPreset = localization.GetByLabel('UI/LPStore/PresetAll') 56 self.currentParagonFilters = {} 57 self.storesUsingCorpWalletMode = set() 58 self._corp_spending_killswitch = FLAG_CORP_LP_PURCHASES_KILLSWITCH_DEFAULT 59 flag_bool(key=FLAG_CORP_LP_PURCHASES_KILLSWITCH, default_value=FLAG_CORP_LP_PURCHASES_KILLSWITCH_DEFAULT, callback=self._on_corp_spending_killswitch_changed) 60 61 @staticmethod 62 def _GetRemoteLPService(): 63 return sm.RemoteSvc('LPSvc') 64 65 def _ClearCache(self): 66 self.cache.clear() 67 self.cache.offers = {} 68 69 def GetCurrentFilters(self): 70 return self.currentFilters.copy() 71 72 def GetCurrentParagonFilters(self): 73 return copy.deepcopy(self.currentParagonFilters) 74 75 def GetCurrentPresetLabel(self): 76 return self.currentPreset 77 78 def IsRWCorp(self, corpID): 79 return corpID in FACTION_TO_RW_LP_CORP.values() 80 81 def OpenConcordExchange(self, corpID): 82 exchangeRate = self.GetConcordLPExchangeRate(corpID) 83 myConcordLP = self.loyaltyPointsWalletSvc.GetCharacterConcordLPBalance() 84 corporationLPs = self.loyaltyPointsWalletSvc.GetCharacterWalletLPBalance(corpID) 85 LPExhangeDialog.CloseIfOpen(windowID='LPExhangeDialog_%s' % corpID) 86 LPExhangeDialog.Open(windowID='LPExhangeDialog_%s' % corpID, currentFromCorpLPs=myConcordLP, currentToCorpLPs=corporationLPs, exchangeRate=exchangeRate, toCorpID=corpID) 87 88 def GetConcordLPExchangeRate(self, corpID): 89 stationItem = sm.GetService('station').stationItem 90 if not corpID and idCheckers.IsNPC(stationItem.ownerID): 91 corpID = stationItem.ownerID 92 return get_corporation_exchange_rates(appConst.ownerCONCORD, default={}).get(corpID) 93 94 def GetOffers(self, corpID): 95 if self.cache.offers.get(corpID, None) is None: 96 self.cache.offers[corpID] = sm.RemoteSvc('LPStoreMgr').GetAvailableOffersFromCorp(corpID) 97 self._RefreshOfferSortValues(corpID) 98 return self.cache.offers[corpID] 99 100 def ConvertConcordLP(self, corpID, amount): 101 self._GetRemoteLPService().ExchangeConcordLP(corpID, amount) 102 103 def GetCorpName(self, corpID): 104 return cfg.eveowners.Get(corpID).name 105 106 def AddFilters(self, newFilters): 107 newFilters = dict(self.currentFilters, **newFilters) 108 self.ChangeFilters(newFilters) 109 110 def RemoveFilter(self, key): 111 TryDel(self.currentFilters, key) 112 self.ChangeFilters(self.currentFilters) 113 114 def ChangeFilters(self, newFilters): 115 self.currentFilters = newFilters 116 self.currentPreset = localization.GetByLabel('UI/LPStore/PresetNone') 117 self._PersistFilters() 118 sm.ScatterEvent('OnLPStoreCurrentPresetChange') 119 sm.ScatterEvent('OnLPStoreFilterChange') 120 121 def ChangeParagonFilters(self, newFilters): 122 self.currentParagonFilters = newFilters 123 self._PersistParagonFilters() 124 sm.ScatterEvent('OnLPStoreParagonFilterChange') 125 126 def ChangeCurrentPreset(self, newPreset): 127 self.currentPreset = newPreset 128 self.currentFilters = self._GetPresetFilters(newPreset) 129 self._PersistFilters() 130 sm.ScatterEvent('OnLPStoreCurrentPresetChange') 131 sm.ScatterEvent('OnLPStoreFilterChange') 132 133 def GetPresets(self): 134 ret = self._GetDefaultPresets() + self.userPresets 135 if self.currentPreset == localization.GetByLabel('UI/LPStore/PresetNone'): 136 ret.insert(0, Bunch(label=localization.GetByLabel('UI/LPStore/PresetNone'), filters=None, editable=False)) 137 return ret 138 139 def AddPreset(self, name, filters): 140 self.userPresets.append(Bunch(label=name, filters=filters, editable=True)) 141 self._PersistPresets() 142 sm.ScatterEvent('OnLPStorePresetsChange') 143 144 def OverwritePreset(self, label, filters): 145 for i, p in enumerate(self.userPresets): 146 if p.label == label: 147 self.userPresets[i] = Bunch(label=label, filters=filters.copy(), editable=True) 148 self.ChangeCurrentPreset(label) 149 self._PersistPresets() 150 return 151 else: 152 log.LogError('svc.lpstore.OverwritePreset: Preset not found.') 153 154 def DeletePreset(self, label): 155 if label == self.currentPreset: 156 self.ChangeCurrentPreset(self.defaultPreset) 157 for p in self.userPresets: 158 if p.label == label: 159 self.userPresets.remove(p) 160 self._PersistPresets() 161 sm.ScatterEvent('OnLPStorePresetsChange') 162 return 163 else: 164 log.LogError('svc.lpstore.DeletePreset: Preset not found.') 165 166 def _GetSetting(self, key, default): 167 return settings.user.ui.Get('%s_%s' % (key, self.settingsVersion), default) 168 169 def _SetSetting(self, key, value): 170 return settings.user.ui.Set('%s_%s' % (key, self.settingsVersion), value) 171 172 def _InitPresets(self): 173 if hasattr(self, 'initedPresets'): 174 return 175 self.userPresets = [ Bunch(**d) for d in self._GetSetting('lpStoreFilterPresets', []) ] 176 self.currentPreset = self._GetSetting('lpStoreCurrentPreset', self.defaultPreset) 177 if self.currentPreset == localization.GetByLabel('UI/LPStore/PresetNone'): 178 self.currentFilters = settings.user.ui.Get('lpStoreCurrentFilters', self._GetPresetFilters(self.defaultPreset)) 179 else: 180 self.currentFilters = self._GetPresetFilters(self.currentPreset) 181 self.currentParagonFilters = self._GetSetting('lpStoreCurrentParagonFilters', DEFAULT_PARAGON_FILTERS) 182 self.initedPresets = True 183 184 def _GetPresetFilters(self, label): 185 if label == localization.GetByLabel('UI/LPStore/PresetNone'): 186 return self.currentFilters 187 for preset in self.GetPresets(): 188 if preset.label == label: 189 return preset.filters 190 191 return self._GetPresetFilters(self.defaultPreset) 192 193 def _PersistPresets(self): 194 self._SetSetting('lpStoreFilterPresets', [ {'label': preset.label, 195 'filters': preset.filters, 196 'editable': True} for preset in self.userPresets ]) 197 self.settings.SaveSettings() 198 199 def _PersistFilters(self): 200 self._SetSetting('lpStoreCurrentPreset', self.currentPreset) 201 if self.currentPreset == localization.GetByLabel('UI/LPStore/PresetNone'): 202 self._SetSetting('lpStoreCurrentFilters', self.currentFilters) 203 self.settings.SaveSettings() 204 205 def _PersistParagonFilters(self): 206 self._SetSetting('lpStoreCurrentParagonFilters', self.currentParagonFilters) 207 self.settings.SaveSettings() 208 209 def _GetDefaultPresets(self): 210 affordableFilters = {'reqNotInHangar': True, 211 'dynamicMaxLP': True, 212 'dynamicMaxISK': True, 213 'dynamicMaxAnalysisKredits': True, 214 'dynamicStandings': True} 215 return [Bunch(label=localization.GetByLabel('UI/LPStore/PresetAffordable'), filters=affordableFilters, editable=False), Bunch(label=localization.GetByLabel('UI/LPStore/PresetAll'), filters={}, editable=False)] 216 217 def _RefreshOfferSortValues(self, corpID): 218 for offer in self.cache.offers[corpID]: 219 self._SetOfferDataSortOrder(offer) 220 221 def AcceptOffer(self, data, numberOfOffers = 1): 222 if getattr(self, 'acceptingOffer', False): 223 return uiconst.ID_NO 224 try: 225 self.acceptingOffer = True 226 message, args = self._GetConfirmMessage(data, numberOfOffers) 227 if prompt_player_fsd_dialog(message, args, uiconst.OKCANCEL, uiconst.ID_OK) != uiconst.ID_OK: 228 return uiconst.OKCANCEL 229 if self.IsUsingCharacterWallets(data.corpID): 230 ret = sm.RemoteSvc('LPStoreMgr').TakeOfferForCharacter(data.corpID, data.offerID, numberOfOffers) 231 elif self.IsUsingCorpWallets(data.corpID): 232 ret = sm.RemoteSvc('LPStoreMgr').TakeOfferForCorporation(data.corpID, data.offerID, numberOfOffers) 233 else: 234 raise RuntimeError('Invalid LPStoreSvc walletMode {0}'.format(self.walletMode)) 235 if ret: 236 prompt_player_fsd_dialog('LPStoreOfferAccepted', {'name': cfg.eveowners.Get(session.charid).name}) 237 if self.cache.analysisKredits: 238 del self.cache.analysisKredits 239 if len(data.reqItems) > 0 and self.cache.hangarInv: 240 del self.cache.hangarInv 241 self.DirtyWindow() 242 finally: 243 self.acceptingOffer = False 244 245 if ret: 246 return uiconst.ID_YES 247 return uiconst.ID_NO 248 249 def _GetConfirmMessage(self, data, numberOfOffers): 250 offer = GetItemText(data.typeID, data.qty, numberOfOffers).replace('<br>', ' ') 251 if evetypes.GetGroupID(data.typeID) == appConst.groupShipCosmeticLicense: 252 price = localization.GetByLabel('UI/LPStore/PriceInEMSimple', lpCost=FmtAmt(data.lpCost)) 253 return ('ConfirmAcceptEmblemLPOffer', {'offer': offer, 254 'price': price}) 255 else: 256 price = self._GetPrice(data, numberOfOffers) 257 if self.IsUsingCharacterWallets(data.corpID): 258 messageName = 'ConfirmAcceptLPOffer' 259 elif self.IsUsingCorpWallets(data.corpID): 260 messageName = 'ConfirmAcceptLPOfferUsingCorpWallet' 261 else: 262 raise RuntimeError('Invalid LPStoreSvc walletMode {0}'.format(self.walletMode)) 263 return (messageName, {'offer': offer, 264 'price': price}) 265 266 def _GetPrice(self, data, numberOfOffers): 267 price = '' 268 for requirement in self.LpOfferRequirements[data.corpID]: 269 requirementName = requirement.name 270 if requirementName: 271 cost = data.Get(requirementName, 0) 272 if cost > 0: 273 totalCost = requirement.formatAmount(cost * numberOfOffers) 274 if requirement.priceLabelPath: 275 keywords = {requirementName: totalCost} 276 price += localization.GetByLabel(requirement.priceLabelPath, **keywords) + '<br>' 277 else: 278 price += localization.GetByLabel('UI/LPStore/OfferItems', itemText=totalCost) + '<br>' 279 280 for item in data.reqItems: 281 price += localization.GetByLabel('UI/LPStore/OfferItems', itemText=GetItemText(item[0], item[1], numberOfOffers)) + '<br>' 282 283 return price 284 285 def HaveItem(self, typeID, qty): 286 return self.GetInvenoryItemQuantity(typeID) >= qty 287 288 def GetInvenoryItemQuantity(self, typeID): 289 if self.cache.hangarInv is None: 290 hi = {} 291 inv = sm.GetService('invCache').GetInventory(appConst.containerHangar).List(appConst.flagHangar) 292 for item in inv: 293 if not item.singleton: 294 hi[item.typeID] = max(hi.get(item.typeID, 0), item.stacksize) 295 296 self.cache.hangarInv = hi 297 return self.cache.hangarInv.get(typeID, 0) 298 299 def GetISKBalanceForStorePurchase(self, storeCorpID): 300 if self.IsUsingCharacterWallets(storeCorpID): 301 return self.wallet.GetWealth() 302 elif self.IsUsingCorpWallets(storeCorpID): 303 return self._GetCorpWealth_Memozied(accountKey=session.corpAccountKey) 304 else: 305 return None 306 307 @Memoize(1.0 / 60.0) 308 def _GetCorpWealth_Memozied(self, accountKey): 309 return self.wallet.GetCorpWealth(accountKey) 310 311 def GetLPBalanceForStorePurchase(self, storeCorpID): 312 if self.IsUsingCharacterWallets(storeCorpID): 313 return self.loyaltyPointsWalletSvc.GetCharacterWalletLPBalance(storeCorpID) 314 elif self.IsUsingCorpWallets(storeCorpID): 315 return self.loyaltyPointsWalletSvc.GetCorporationWalletLPBalance(storeCorpID) 316 else: 317 return None 318 319 def GetMyAnalysisKredits(self): 320 if self.cache.analysisKredits is None: 321 self.cache.analysisKredits = sm.RemoteSvc('ProjectDiscovery').get_player_analysis_kredits() 322 return self.cache.analysisKredits 323 324 def OpenLPStore(self, corpIDs): 325 for corpID in corpIDs: 326 self.GetOffers(corpID) 327 328 self._InitPresets() 329 self.cache.hangarInv = None 330 wnd = LPStoreWindow.GetIfOpen() 331 if wnd is None: 332 wnd = LPStoreWindow(corpIDs=corpIDs) 333 else: 334 wnd.ToggleOpenClose() 335 if wnd: 336 wnd.RefreshIfNotAlready() 337 wnd.RefreshOffers() 338 return wnd 339 340 def DirtyWindow(self): 341 if not getattr(self, 'refreshpending', False): 342 self.refreshpending = True 343 uthread.pool('lpStore::ReportDirtyWindow', self.__DirtyWindow) 344 345 def __DirtyWindow(self): 346 try: 347 blue.pyos.synchro.SleepWallclock(1000) 348 for corpID in self.cache.offers.keys(): 349 self._RefreshOfferSortValues(corpID) 350 351 w = self._GetWnd() 352 if w is not None: 353 w.Refresh() 354 finally: 355 self.refreshpending = False 356 357 def _GetWnd(self): 358 return LPStoreWindow.GetIfOpen() 359 360 def OnAccountChange(self, accountKey, ownerID, _balance): 361 if accountKey == 'cash' and ownerID == session.charid: 362 self.DirtyWindow() 363 364 def ProcessSessionChange(self, _isremote, _session, change): 365 if 'stationid' in change: 366 self._ClearCache() 367 w = self._GetWnd() 368 if w: 369 w.Close() 370 self.ResetWalletsSourceChoices() 371 if 'corprole' in change or 'corpAccountKey' in change: 372 self.ResetWalletsSourceChoices() 373 374 def OnCharacterLPBalanceChange_Local(self, issuerCorpID, lpBefore, lpAfter): 375 if self.IsUsingCharacterWallets(issuerCorpID): 376 self.DirtyWindow() 377 378 def OnCorporationLPBalanceChange_Local(self, issuerCorpID): 379 if self.IsUsingCorpWallets(issuerCorpID): 380 self.DirtyWindow() 381 382 def OnAnalysisKreditsChange(self): 383 currentAnalysisKredits = self.cache.analysisKredits 384 if self.cache.analysisKredits is not None: 385 del self.cache.analysisKredits 386 self.DirtyWindow() 387 if session.stationid and currentAnalysisKredits == 0: 388 sm.GetService('station').ReloadLobby() 389 390 def OnItemChangeProcessed(self, item = None, change = None): 391 self._on_item_change_processed_internal() 392 393 @BufferedCall(200) 394 def _on_item_change_processed_internal(self): 395 if self.cache.hangarInv is not None: 396 del self.cache.hangarInv 397 self.DirtyWindow() 398 399 def ResetWalletsSourceChoices(self): 400 self.storesUsingCorpWalletMode.clear() 401 self.DirtyWindow() 402 403 def UseCharacterWallets(self, storeCorpID): 404 self.storesUsingCorpWalletMode.discard(storeCorpID) 405 self.DirtyWindow() 406 407 def UseCorporationWallets(self, storeCorpID): 408 self.storesUsingCorpWalletMode.add(storeCorpID) 409 self.DirtyWindow() 410 411 def IsUsingCharacterWallets(self, storeCorpID): 412 return storeCorpID not in self.storesUsingCorpWalletMode 413 414 def IsUsingCorpWallets(self, storeCorpID): 415 return storeCorpID in self.storesUsingCorpWalletMode 416 417 def CanCharacterUseCorpWallets(self, storeCorpID): 418 if self._corp_spending_killswitch: 419 return False 420 if storeCorpID == corpHeraldry: 421 return False 422 return bool(session.corprole & appConst.corpRoleDirector) 423 424 def _SetOfferDataSortOrder(self, data): 425 offerData = [(localization.GetByLabel('UI/LPStore/Reward'), evetypes.GetName(data.typeID))] 426 for requirement in self.GetRequirements(data.corpID): 427 requirementName = requirement.name 428 cost = data.Get(requirementName, 0) 429 if requirement.costLabelPath: 430 costLabel = localization.GetByLabel(requirement.costLabelPath) 431 if not cost: 432 cost = 0 433 offerData.append((costLabel, cost)) 434 435 requiredStandings = data.Get('requiredStandings', None) 436 standingsValue = requiredStandings['value'] if requiredStandings else -11 437 offerData.append((localization.GetByLabel('UI/LPStore/StandingsRequired'), standingsValue)) 438 for label, sortval in offerData: 439 data.Set('sort_%s' % label, sortval) 440 441 def GetRequirements(self, corpID): 442 if corpID not in self.LpOfferRequirements: 443 self._CreateRequirements(corpID) 444 return self.LpOfferRequirements[corpID] 445 446 def _CreateRequirements(self, corpID): 447 if corpID == cosmeticsConst.LP_STORE_CORP: 448 self.LpOfferRequirements[corpID] = [EMRequirement(checkAmountFunction=lambda : self.loyaltyPointsWalletSvc.GetCharacterEvermarkBalance())] 449 else: 450 self.LpOfferRequirements[corpID] = [LpRequirement(checkAmountFunction=lambda : self.GetLPBalanceForStorePurchase(corpID)), ISKRequirement(checkAmountFunction=lambda : self.GetISKBalanceForStorePurchase(corpID)), AnalysisKreditsRequirement(checkAmountFunction=self.GetMyAnalysisKredits)] 451 452 def CanAcceptOffer(self, data): 453 requiredItems = data.Get('reqItems', []) 454 missingItems = [ 1 for typeID, qty in requiredItems if not self.HaveItem(typeID, qty) ] 455 areCostRequirementsFulfilled = self.AreRequirementsFulfilled(data) 456 return areCostRequirementsFulfilled and not missingItems and self.IsStandingsFulfilled(data) 457 458 def AreRequirementsFulfilled(self, data): 459 requirementList = self.LpOfferRequirements[data.corpID] 460 for requirement in requirementList: 461 if not self._IsRequirementFulfilled(data, requirement): 462 return False 463 464 return True 465 466 def _IsRequirementFulfilled(self, data, requirement): 467 requirementName = requirement.name 468 if not requirementName: 469 return True 470 cost = data.Get(requirementName, 0) 471 return requirement.checkAmount(cost) 472 473 def IsStandingsFulfilled(self, data): 474 requiredStandings = data.Get('requiredStandings', None) 475 if not requiredStandings: 476 return True 477 currentStanding = sm.GetService('standing').GetStandingWithSkillBonus(requiredStandings['ownerID'], session.charid) 478 return requiredStandings['value'] < currentStanding 479 480 @telemetry.ZONE_FUNCTION 481 def GetNearestDockableWithLPStoreForCorp(self, corpID): 482 if sm.GetService('lpstore').IsRWCorp(corpID): 483 rw_station_ids = sm.RemoteSvc('RWManager').get_closest_rw_stations(session.solarsystemid2) 484 nearestRWStationID = rw_station_ids.get(corpID, None) 485 return nearestRWStationID 486 stationsOwnedByCorp = sm.RemoteSvc('stationSvc').GetStationsForOwner(corpID) 487 stationsOwnedByCorpBySolarSystemID = defaultdict(list) 488 for station in stationsOwnedByCorp: 489 stationsOwnedByCorpBySolarSystemID[station.solarSystemID].append(station.stationID) 490 491 hardcoded_stations = get_hardcoded_lp_stations_for_corp(corpID) 492 for stationID in hardcoded_stations: 493 stationsOwnedByCorpBySolarSystemID[cfg.evelocations.Get(stationID).solarSystemID].append(stationID) 494 495 fwFactionID = GetFwFactionIDForNpcCorp(corpID) 496 if IsPirateFWFaction(fwFactionID): 497 structureID, solarSystemID = sm.GetService('insurgencyCampaignSvc').GetActiveFobStructureIdAndSystemIdForFaction(fwFactionID) 498 if structureID and solarSystemID: 499 stationsOwnedByCorpBySolarSystemID[solarSystemID].append(structureID) 500 nearestDockableLocation = None 501 jumpsToNearestStation = sys.maxint 502 for solarSystemID, stationIDs in stationsOwnedByCorpBySolarSystemID.iteritems(): 503 for dockableLocationID in stationIDs: 504 blue.pyos.BeNice() 505 if session.stationid == dockableLocationID: 506 return dockableLocationID 507 if session.structureid == dockableLocationID: 508 return dockableLocationID 509 dist = self.clientPathfinderService.GetJumpCount(session.solarsystemid2, solarSystemID) 510 if dist <= jumpsToNearestStation: 511 jumpsToNearestStation = dist 512 nearestDockableLocation = dockableLocationID 513 514 return nearestDockableLocation 515 516 def _on_corp_spending_killswitch_changed(self, evaluate_flag): 517 current_value = self._corp_spending_killswitch 518 self._corp_spending_killswitch = evaluate_flag() 519 if self._corp_spending_killswitch != current_value: 520 on_corp_lp_purchases_killswitch_changed(self._corp_spending_killswitch)