import { AcquisitionClient } from '../clients/AcquisitionClient'; import { UserDataState } from '../state/UserDataState'; import { SuccessState } from '../entities/SuccessState'; import { AcquisitionRequest, Meter, AcquisitionBundle, AcquisitionResponse } from '../entities/Acquisition'; import { Quote } from '../entities/Quote'; import { Campaign, ReferredFrom, Utility } from '../entities/Enums'; import * as _ from "lodash"; import { AnalyticsService } from './AnalyticsService'; import { OnboardingService } from './OnboardingService'; import { HostExtractor } from "../util/HostExtractor"; import { acquisitionResponse, acquisitionRequest } from '../entities/Acquisition.fixture'; import { OnboardingStatusResponse } from '../entities/Onboarding'; export class AcquisitionService { successState: SuccessState; constructor( private acquisitionClient: AcquisitionClient, private userDataState: UserDataState, private analyticsService: AnalyticsService, private host: HostExtractor, private onboardingService: OnboardingService, private $q: QService) { } acquisition(quote: Quote, params: AcquisitionParameters): Promise { this.analyticsService.push({ event: 'SubmitAcquisition', marketingOptIn: this.userDataState.marketingOptIn, serviceOptIn: false }); const acquisitionRequest = this.convertToAcquisitionRequest(quote, params); return this.acquisitionClient.acquisition(acquisitionRequest) .then(acquisitionResponse => { this.analyticsService.push({ customerId: acquisitionResponse.data.customerId }); return this.shouldPollOnboarding(acquisitionResponse.data, params.password) ? this.pollOnboarding(acquisitionResponse.data, params, quote) : this.convertToSuccessState(acquisitionResponse.data, quote); }) .then(successState => this.successState = successState); } shouldPollOnboarding(acquisitionResponse: AcquisitionResponse, password: string): boolean { return acquisitionResponse.customerId && this.host.retailer === 'OVO'; } pollOnboarding(acquisitionResponse: AcquisitionResponse, params: AcquisitionParameters, quote: Quote): Promise { const onboardingRequest = { email: this.userDataState.emailAddress, customerId: acquisitionResponse.customerId, accountId: acquisitionResponse.accountId, checkForSMB: false, csaMode: this.host.isAgentMode, password: params.password }; return this.onboardingService.pollOnboarding(onboardingRequest) .then(onboardingResponse => this.convertToSuccessState(acquisitionResponse, quote, onboardingResponse)) .catch(() => this.convertToSuccessState(acquisitionResponse, quote)); } convertToSuccessState(acquisitionResponse: AcquisitionResponse, quote: Quote, onboardingResponse?: OnboardingStatusResponse): SuccessState { const successState = { customerId: acquisitionResponse.customerId, tariff: quote.tariffs[this.userDataState.tariffId], salesReference: acquisitionResponse.salesReference, onboarded: false }; return onboardingResponse ? { ...successState, forwardUrl: onboardingResponse.forwardUrl, onboarded: true } : successState; } getBundleFromQuote(quote: Quote): AcquisitionBundle { const bundle = quote.bundles.find(bundle => bundle.name === this.userDataState.bundleName); return { name: bundle.name, boltons: !bundle ? [] : bundle.boltons.map(bundleBolton => { const quoteBolton = quote.boltons.find(quoteBolton => bundleBolton.name === quoteBolton.name); return { name: bundleBolton.name, discountPercentage: bundleBolton.discountPercentage, cost: quoteBolton.cost, }; }), } } private convertToAcquisitionRequest(quote: Quote, params: AcquisitionParameters): AcquisitionRequest { const tariff = quote.tariffs[this.userDataState.tariffId]; // For now we are unable to submit multiple MPANs/MPRNs so there will only be one of each let electricMeters: Meter[] = []; let gasMeters: Meter[] = []; // TODO This endpoint structure needs reviewing, because we can't submit the usage, the economy7 etc. if there is no MPAN if (this.userDataState.supplyAddress.mpans.length > 0) { electricMeters.push({ utility: 'Electricity', meterPointNumber: this.userDataState.supplyAddress.mpans[0], estimatedAnnualUsage: tariff.tils['Electricity'].annualUsage, economy7: this.userDataState.economy7, // This needs to be filled in for MoveIn only registers: [] }); } if (quote.fuel === 'Dual' && this.userDataState.supplyAddress.mprns.length > 0) { gasMeters.push({ utility: 'Gas', meterPointNumber: this.userDataState.supplyAddress.mprns[0], estimatedAnnualUsage: tariff.tils['Gas'].annualUsage, registers: [] }); } // Find the bundle we have selected const bundle = quote.bundles.find(bundle => bundle.name === this.userDataState.bundleName); return { account: { electricityRegion: quote.region, fuel: this.userDataState.fuel, tariff: this.userDataState.tariffId, tariffName: tariff.name, tariffRates: Object.keys(tariff.tils).map(utility => { const til = tariff.tils[utility]; return { fuel: utility as Utility, unitRate: til.unitRate, ...(til.nightUnitRate ? { unitRateNight: til.nightUnitRate } : {}), standingCharge: til.standingCharge } }), renewableFuelPercentage: tariff.renewableFuelPercentage, contractLength: tariff.contractLength, foundation: this.userDataState.foundation, paymentMethod: this.userDataState.paymentMethod, payInArrears: params.payInArrears, supplyAddress: this.userDataState.supplyAddress, boltons: [], ...(!bundle ? {} : { bundle: this.getBundleFromQuote(quote) }), ...(this.userDataState.serviceType ? { serviceType: this.userDataState.serviceType } : {}), ...(this.userDataState.billingAddress ? { billingAddress: this.userDataState.billingAddress } : {}), ...(this.userDataState.paymentMethod === 'Payg' ? {} : { bankAccount: { accountName: params.accountName, accountNumber: params.accountNumber, sortCode: params.sortCode, directDebitAmount: _.round(tariff.expectedAnnualSpend / 12, 0) } }) }, customer: { firstName: this.userDataState.firstName, lastName: this.userDataState.lastName, dateOfBirth: this.userDataState.dateOfBirth, phone: this.userDataState.phone, serviceOptIn: this.userDataState.serviceOptIn, marketingOptIn: false, ...(this.userDataState.title ? { title: this.userDataState.title } : {}), ...(this.userDataState.emailAddress ? { emailAddress: this.userDataState.emailAddress } : {}), ...(params.password ? { password: params.password } : {}), ...(this.userDataState.criticalCode ? { criticalCode: this.userDataState.criticalCode } : {}), }, sale: { saleType: this.userDataState.quoteType === 'MoveIn' ? 'MoveIn' : 'Switch', ...(this.userDataState.moveInDate ? { moveInDate: this.userDataState.moveInDate } : {}), brokerId: 'OVO', quoteDate: quote.dateCreated, annualQuotedAmount: tariff.expectedAnnualSpend, quotedSaving: tariff.expectedAnnualSavings, ...(params.agentId ? { agentId: params.agentId } : {}), ...(params.campaign ? { campaign: params.campaign } : {}), ...(params.referredFrom ? { referredFrom: params.referredFrom } : {}) }, meters: [ ...electricMeters, ...gasMeters ] } } } export interface AcquisitionParameters { accountName?: string; accountNumber?: string; agentId?: string; password?: string; payInArrears: boolean; sortCode?: string; campaign?: Campaign, referredFrom?: ReferredFrom }