Skip to content

Commit

Permalink
Merge pull request #524 from amtrack/feat/opportunity-splits
Browse files Browse the repository at this point in the history
feat: Opportunity Splits
  • Loading branch information
amtrack authored Dec 2, 2022
2 parents 9f562e8 + cd1e60e commit 18aca00
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 3 deletions.
7 changes: 4 additions & 3 deletions src/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -26,8 +25,10 @@ export {
highVelocitySalesSettings,
homePageLayouts,
lightningExperienceSettings,
opportunitySplits,
picklists,
recordTypes,
relateContactToMultipleAccounts,
reportsAndDashboards,
salesforceToSalesforce,
security
Expand Down
8 changes: 8 additions & 0 deletions src/plugins/opportunity-splits/disable.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "../schema.json",
"settings": {
"opportunitySplits": {
"enabled": false
}
}
}
8 changes: 8 additions & 0 deletions src/plugins/opportunity-splits/enable.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "../schema.json",
"settings": {
"opportunitySplits": {
"enabled": true
}
}
}
70 changes: 70 additions & 0 deletions src/plugins/opportunity-splits/index.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -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()
);
});
});
33 changes: 33 additions & 0 deletions src/plugins/opportunity-splits/index.ts
Original file line number Diff line number Diff line change
@@ -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<Config> {
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<void> {
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();
}
}
}
23 changes: 23 additions & 0 deletions src/plugins/opportunity-splits/pages/layout-selection.ts
Original file line number Diff line number Diff line change
@@ -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<OverviewPage> {
await this.page.waitForSelector(SAVE_BUTTON);
await Promise.all([
this.page.waitForNavigation(),
this.page.click(SAVE_BUTTON)
]);
return new OverviewPage(this.page);
}
}
45 changes: 45 additions & 0 deletions src/plugins/opportunity-splits/pages/overview.ts
Original file line number Diff line number Diff line change
@@ -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<boolean> {
return (await this.page.$(DISABLE_LINK)) !== null;
}

public async waitUntilEnabled(): Promise<void> {
await this.page.waitForSelector(IN_PRGOGRESS);
// 10 minutes
await this.page.waitForSelector(COMPLETED, { timeout: 10 * 60 * 1000 });
}

public async disable(): Promise<OverviewPage> {
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<void> {
await this.page.waitForSelector(COMPLETED);
}
}
27 changes: 27 additions & 0 deletions src/plugins/opportunity-splits/pages/setup.ts
Original file line number Diff line number Diff line change
@@ -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<LayoutSelectionPage> {
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);
}
}
13 changes: 13 additions & 0 deletions src/plugins/opportunity-splits/schema.json
Original file line number Diff line number Diff line change
@@ -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 `<enableOpportunityTeam>true</enableOpportunityTeam>`.",
"type": "boolean"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<OpportunitySettings xmlns="http://soap.sforce.com/2006/04/metadata">
<enableOpportunityTeam>true</enableOpportunityTeam>
</OpportunitySettings>
3 changes: 3 additions & 0 deletions src/plugins/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
"properties": {
"settings": {
"properties": {
"opportunitySplits": {
"$ref": "./opportunity-splits/schema.json"
},
"relateContactToMultipleAccounts": {
"$ref": "./relate-contact-to-multiple-accounts/schema.json"
},
Expand Down

0 comments on commit 18aca00

Please sign in to comment.