diff --git a/src/plugins/index.ts b/src/plugins/index.ts index 4e7f9dc4..00e8958a 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -7,16 +7,15 @@ import { EmailDeliverability as emailDeliverability } from './email-deliverabili import { HighVelocitySalesSettings as highVelocitySalesSettings } from './high-velocity-sales-settings'; import { HomePageLayouts as homePageLayouts } from './home-page-layouts'; import { LightningExperienceSettings as lightningExperienceSettings } from './lightning-experience-settings'; +import { OpportunitySplits as opportunitySplits } from './opportunity-splits'; import { Picklists as picklists } from './picklists'; import { RecordTypes as recordTypes } from './record-types'; +import { RelateContactToMultipleAccounts as relateContactToMultipleAccounts } from './relate-contact-to-multiple-accounts'; import { ReportsAndDashboards as reportsAndDashboards } from './reports-and-dashboards'; import { SalesforceToSalesforce as salesforceToSalesforce } from './salesforce-to-salesforce'; import { Security as security } from './security'; -import { RelateContactToMultipleAccounts as relateContactToMultipleAccounts } from './relate-contact-to-multiple-accounts'; - export { - relateContactToMultipleAccounts, activitySettings, communities, customerPortal, @@ -26,8 +25,10 @@ export { highVelocitySalesSettings, homePageLayouts, lightningExperienceSettings, + opportunitySplits, picklists, recordTypes, + relateContactToMultipleAccounts, reportsAndDashboards, salesforceToSalesforce, security diff --git a/src/plugins/opportunity-splits/disable.json b/src/plugins/opportunity-splits/disable.json new file mode 100644 index 00000000..51024fce --- /dev/null +++ b/src/plugins/opportunity-splits/disable.json @@ -0,0 +1,8 @@ +{ + "$schema": "../schema.json", + "settings": { + "opportunitySplits": { + "enabled": false + } + } +} diff --git a/src/plugins/opportunity-splits/enable.json b/src/plugins/opportunity-splits/enable.json new file mode 100644 index 00000000..ca55c713 --- /dev/null +++ b/src/plugins/opportunity-splits/enable.json @@ -0,0 +1,8 @@ +{ + "$schema": "../schema.json", + "settings": { + "opportunitySplits": { + "enabled": true + } + } +} diff --git a/src/plugins/opportunity-splits/index.e2e-spec.ts b/src/plugins/opportunity-splits/index.e2e-spec.ts new file mode 100644 index 00000000..a169ffcb --- /dev/null +++ b/src/plugins/opportunity-splits/index.e2e-spec.ts @@ -0,0 +1,70 @@ +import assert from 'assert'; +import * as child from 'child_process'; +import * as path from 'path'; +import { OpportunitySplits } from '.'; + +describe(OpportunitySplits.name, function () { + this.slow('30s'); + this.timeout('2m'); + it('should enable Opportunity Teams as prerequisite', () => { + const sourceDeployCmd = child.spawnSync('sfdx', [ + 'force:source:deploy', + '-p', + path.join(__dirname, 'sfdx-source'), + '--json' + ]); + assert.deepStrictEqual( + sourceDeployCmd.status, + 0, + sourceDeployCmd.output.toString() + ); + }); + it('should enable', () => { + const enableCmd = child.spawnSync(path.resolve('bin', 'run'), [ + 'browserforce:apply', + '-f', + path.resolve(path.join(__dirname, 'enable.json')) + ]); + assert.deepStrictEqual(enableCmd.status, 0, enableCmd.output.toString()); + assert.ok( + /to 'true'/.test(enableCmd.output.toString()), + enableCmd.output.toString() + ); + }); + it('should already be enabled', () => { + const enableCmd = child.spawnSync(path.resolve('bin', 'run'), [ + 'browserforce:apply', + '-f', + path.join(__dirname, 'enable.json') + ]); + assert.deepStrictEqual(enableCmd.status, 0, enableCmd.output.toString()); + assert.ok( + /no action necessary/.test(enableCmd.output.toString()), + enableCmd.output.toString() + ); + }); + it('should disable', () => { + const disableCmd = child.spawnSync(path.resolve('bin', 'run'), [ + 'browserforce:apply', + '-f', + path.resolve(path.join(__dirname, 'disable.json')) + ]); + assert.deepStrictEqual(disableCmd.status, 0, disableCmd.output.toString()); + assert.ok( + /to 'false'/.test(disableCmd.output.toString()), + disableCmd.output.toString() + ); + }); + it('should already be disabled', () => { + const disableCmd = child.spawnSync(path.resolve('bin', 'run'), [ + 'browserforce:apply', + '-f', + path.join(__dirname, 'disable.json') + ]); + assert.deepStrictEqual(disableCmd.status, 0, disableCmd.output.toString()); + assert.ok( + /no action necessary/.test(disableCmd.output.toString()), + disableCmd.output.toString() + ); + }); +}); diff --git a/src/plugins/opportunity-splits/index.ts b/src/plugins/opportunity-splits/index.ts new file mode 100644 index 00000000..6a045d1f --- /dev/null +++ b/src/plugins/opportunity-splits/index.ts @@ -0,0 +1,33 @@ +import { BrowserforcePlugin } from '../../plugin'; +import { OverviewPage } from './pages/overview'; +import { SetupPage } from './pages/setup'; + +type Config = { + enabled: boolean; +}; + +export class OpportunitySplits extends BrowserforcePlugin { + public async retrieve(definition?: Config): Promise { + const page = await this.browserforce.openPage(OverviewPage.PATH); + const overviewPage = new OverviewPage(page); + const response = { + enabled: await overviewPage.isEnabled() + }; + return response; + } + + public async apply(config: Config): Promise { + if (config.enabled) { + const page = await this.browserforce.openPage(SetupPage.PATH); + const setupPage = new SetupPage(page); + const layoutSelectionPage = await setupPage.enable(); + const overviewPage = await layoutSelectionPage.choose(); + await overviewPage.waitUntilEnabled(); + } else { + const page = await this.browserforce.openPage(OverviewPage.PATH); + const overviewPage = new OverviewPage(page); + await overviewPage.disable(); + await overviewPage.waitUntilDisabled(); + } + } +} diff --git a/src/plugins/opportunity-splits/pages/layout-selection.ts b/src/plugins/opportunity-splits/pages/layout-selection.ts new file mode 100644 index 00000000..f8bc75b8 --- /dev/null +++ b/src/plugins/opportunity-splits/pages/layout-selection.ts @@ -0,0 +1,23 @@ +import { Page } from 'puppeteer'; +import { OverviewPage } from './overview'; + +const SAVE_BUTTON = 'input[id$=":save"]'; + +export class LayoutSelectionPage { + static PATH = + 'opp/opportunitySplitSetupLayout.apexp?setupid=OpportunitySplitSetup'; + private page; + + constructor(page: Page) { + this.page = page; + } + + public async choose(): Promise { + await this.page.waitForSelector(SAVE_BUTTON); + await Promise.all([ + this.page.waitForNavigation(), + this.page.click(SAVE_BUTTON) + ]); + return new OverviewPage(this.page); + } +} diff --git a/src/plugins/opportunity-splits/pages/overview.ts b/src/plugins/opportunity-splits/pages/overview.ts new file mode 100644 index 00000000..0087d935 --- /dev/null +++ b/src/plugins/opportunity-splits/pages/overview.ts @@ -0,0 +1,45 @@ +import { Page } from 'puppeteer'; + +const IN_PRGOGRESS = '#enablingInProgress'; +const COMPLETED = '#prefSettingSucceeded'; +const DISABLE_LINK = 'div[id*=":disable_form:"] a'; +const DISABLE_CONFIRM_CHECKBOX = 'input#dis_confirm'; +const DISABLE_CONFIRM_BUTTON = + 'input#splitsDisableConfirmDialog_overlayConfirmButton'; + +export class OverviewPage { + static PATH = + 'opp/opportunitySplitSetupOverview.apexp?setupid=OpportunitySplitSetup'; + private page; + + constructor(page: Page) { + this.page = page; + } + + public async isEnabled(): Promise { + return (await this.page.$(DISABLE_LINK)) !== null; + } + + public async waitUntilEnabled(): Promise { + await this.page.waitForSelector(IN_PRGOGRESS); + // 10 minutes + await this.page.waitForSelector(COMPLETED, { timeout: 10 * 60 * 1000 }); + } + + public async disable(): Promise { + await this.page.waitForSelector(DISABLE_LINK); + await this.page.click(DISABLE_LINK); + await this.page.waitForSelector(DISABLE_CONFIRM_CHECKBOX); + await this.page.click(DISABLE_CONFIRM_CHECKBOX); + await this.page.waitForSelector(DISABLE_CONFIRM_BUTTON); + await Promise.all([ + this.page.waitForNavigation(), + this.page.click(DISABLE_CONFIRM_BUTTON) + ]); + return this; + } + + public async waitUntilDisabled(): Promise { + await this.page.waitForSelector(COMPLETED); + } +} diff --git a/src/plugins/opportunity-splits/pages/setup.ts b/src/plugins/opportunity-splits/pages/setup.ts new file mode 100644 index 00000000..d47f9267 --- /dev/null +++ b/src/plugins/opportunity-splits/pages/setup.ts @@ -0,0 +1,27 @@ +import { Page } from 'puppeteer'; +import { LayoutSelectionPage } from './layout-selection'; + +const SAVE_BUTTON = 'input[id$=":form:SaveButton"]'; +const MODAL_CONFIRM_BUTTON = + 'input[id="splitsMassOperationConfirmDialog_overlayConfirmButton"]'; + +export class SetupPage { + static PATH = + 'opp/opportunitySplitSetupEdit.apexp?setupid=OpportunitySplitSetup'; + private page; + + constructor(page: Page) { + this.page = page; + } + + public async enable(): Promise { + await this.page.waitForSelector(SAVE_BUTTON); + await this.page.click(SAVE_BUTTON); + await this.page.waitForSelector(MODAL_CONFIRM_BUTTON); + await Promise.all([ + this.page.waitForNavigation(), + this.page.click(MODAL_CONFIRM_BUTTON) + ]); + return new LayoutSelectionPage(this.page); + } +} diff --git a/src/plugins/opportunity-splits/schema.json b/src/plugins/opportunity-splits/schema.json new file mode 100644 index 00000000..04499958 --- /dev/null +++ b/src/plugins/opportunity-splits/schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "https://github.com/amtrack/sfdx-browserforce-plugin/src/plugins/opportunity-splits/schema.json", + "title": "OpportunitySplits Settings", + "type": "object", + "properties": { + "enabled": { + "title": "Enable Opportunity Splits", + "description": "Prerequisite: Opportunity Teams must be enabled e.g. by deploying 'Settings:Opportunity' containing `true`.", + "type": "boolean" + } + } +} diff --git a/src/plugins/opportunity-splits/sfdx-source/settings/Opportunity.settings-meta.xml b/src/plugins/opportunity-splits/sfdx-source/settings/Opportunity.settings-meta.xml new file mode 100644 index 00000000..8b467fc0 --- /dev/null +++ b/src/plugins/opportunity-splits/sfdx-source/settings/Opportunity.settings-meta.xml @@ -0,0 +1,4 @@ + + + true + diff --git a/src/plugins/schema.json b/src/plugins/schema.json index 59866143..bd46c290 100644 --- a/src/plugins/schema.json +++ b/src/plugins/schema.json @@ -7,6 +7,9 @@ "properties": { "settings": { "properties": { + "opportunitySplits": { + "$ref": "./opportunity-splits/schema.json" + }, "relateContactToMultipleAccounts": { "$ref": "./relate-contact-to-multiple-accounts/schema.json" },