Conga Digital Commerce SDK

Pre-requisite

Digital Commerce packages must be already installed on your Salesforce org. For package and installation assistance, contact Conga Support.

Create your first Storefront

The Digital Commerce SDK works with the unified data model of the underlying Quote-to-Cash platform. This means that there are no additional data setup procedures for creating and maintaining your storefront catalog.

To create your first storefront

  1. Using CPQ, you must already have the existing data:
    • Categories
    • Products
    • Price List
  1. Set up a community - Digital Commerce leverages a Salesforce Community to provide authentication and hosting features for guest users. After the Digital Commerce package is installed in your org, you must create a Salesforce Community. For details on setting up a community, refer to Setting Up Communities in the Digital Commerce Implementation and Deployment Guide.
    At a minimum, you just need the community URL. However, if you intend to support guest users, you can enable it within the community settings. After deployment, the angular library provides a Visualforce page that you can set as the default page for all page settings within the community. For example Home, Login, Forgot Password, Change Password, and so on. Being a single page application, it is designed to handle all incoming requests.

  2. Create a storefront record - Digital Commerce package consists of a Storefront object, an underlying Catalog, and a Tab to map the storefront to the Catalog. You must create a storefront record. For details on creating a storefront record, refer to Adding a Storefront Record in the Digital Commerce Implementation and Deployment Guide.
    The storefront record consists of a Storefront Banner related list. For details on adding a promotional banner to your storefront, refer to Adding Storefront Promotional Banners in the Digital Commerce Implementation and Deployment Guide.

    If you are using an MDO org, there may already be a Store object installed. This Store object is deprecated in favor of the Storefront object that comes with the Digital Commerce package.
  3. Assigning Digital Commerce Permission Set - The Digital Commerce package comes with basic permission set for providing the necessary access to users. For more details on assigning permission sets, see Conga E-Commerce Permission Set in the Digital Commerce Implementation and Deployment Guide.

Installing the Angular Library

Ensure you have access to the Digital Commerce libraries. Contact Conga Support for obtaining access to these libraries. After you have access, to install all the required libraries, run:

npm install --save @apttus/core @apttus/ecommerce @apttus/elements

AppModule.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { ApttusModule } from '@apttus/core';
import { CommerceModule, TranslatorLoaderService } from '@apttus/ecommerce';

import { environment } from '../environments/environment';
import { ComponentModule } from './components/component.module';
import { RouteGuard } from './services/route.guard';
import { AuthGuard } from './services/auth.guard';
import { ConfigureGuard } from './services/configure.guard';
import { ConstraintRuleGuard } from './services/constraint-rule.guard';

// Register locale data
import localeMx from '@angular/common/locales/es-MX';
import localeMxExtra from '@angular/common/locales/extra/es-MX';
import localeFr from '@angular/common/locales/fr';
import localeFrExtra from '@angular/common/locales/extra/fr';
import { registerLocaleData } from '@angular/common';
import { ServiceWorkerModule } from '@angular/service-worker';
import { ModalModule } from 'ngx-bootstrap/modal';
import { HttpClientModule } from '@angular/common/http';

import { ProductDrawerModule, ApttusModalModule } from '@apttus/elements';
// If using additional locales, register the locale data here
registerLocaleData(localeMx, 'es-MX', localeMxExtra);
registerLocaleData(localeFr, 'fr-FR', localeFrExtra);

// Translations
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { AboGuard } from './services/aboGuard';
import { OrderDetailsGuard } from '@apttus/ecommerce';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    AppRoutingModule,
    // Pass environment file to ApttusModule.
    ApttusModule.forRoot(environment),
    // Pass the string name of the APTSMD_Store__c record you want to use to the CommerceModule.
    CommerceModule.forRoot('My Store'),
    ProductDrawerModule,
    ModalModule.forRoot(),
    ApttusModalModule,
    TranslateModule.forRoot({
      loader: { provide: TranslateLoader, useClass: TranslatorLoaderService }
    }),
    HttpClientModule,
    ComponentModule,
    ServiceWorkerModule,
    ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })
  ],
  providers: [RouteGuard, AuthGuard, AboGuard, ConfigureGuard, ConstraintRuleGuard, OrderDetailsGuard],
  bootstrap: [AppComponent]
})
export class AppModule { }

After the library is imported, you can use its components, directives, and pipes in your Angular application:

Defining a model

Proper state management is crucial to a successful Angular PWA (Progressive Web Application). For this, accessing data within Salesforce requires you to define your model within a Typescript class. Behind the scenes, @apttus/core is managing how your components access and interact with that data to avoid unnecessary operations and maintain synchronicity.

See the example illustrated below that defines the account and contact relationship for a component.

import { AObject, ATable, AField } from '@apttus/core';

// We use the decorator ATable to tell @apttus/core this class maps to the 'Account' object.
// In order to access standard sObject fields, our Account class must extend 'AObject' (a subclass of 'SObject).
// The class name can be anything, but the sobjectName and aqlName properties in the ATable decorator must map
// to an object API name within Salesforce or AIC respectively.
@ATable({
  sobjectName : 'Account',
  aqlName: 'crm_Account'
})
export class Account extends AObject {

  // Similar to how the ATable decorator is used on model objects the AField decorator is used for fields within the model.
  // The soql and aql properties must map to a field API name in Salesforce or AIC respectively.
  @AField({
    soql: 'Name',
    aql: 'Name'
  })
  public Name: string = null;

  @AField({
    soql: 'BillingStreet',
    aql: 'BillingStreet'
  })
  BillingStreet: string = null;

  @AField({
    soql: 'My_Custom_Field__c'
  })
  public MyCustomField: number = null;

  //Related Lists
  @AField({
    soql: 'PriceListId__r',
    aql: 'DefaultPriceListId'
  })
  PriceList: PriceList = new PriceList();
}

Defining a Service

After defining your model, you can access the data by creating a service for the models. The AObjectService class contains many of the standard DML and query operations to access the data. However, you can add any convenient methods you want to your service. The core service methods are usually very simple.

import { AObjectService } from '@apttus/core';
import { Injectable } from '@angular/core';
import { Account } from './account.model.ts'  // This is a reference to the account model created in the previous section


@Injectable({
    providedIn : 'root'
})
export class AccountService extends AObjectService{
  //Add service methods here
  type = Account;
}

Access the data in your component

import { Component, OnOnit } from '@angular/core';
import { AccountService } from './account.service.ts';
import { Account } from './account.model.ts';

@Component({
  selector : 'app-account',
  template : `

  `,
  styles : [``]
})
export class AccountComponent implements OnInit{

  constructor(private accountService: AccountService){}

  // Always perform service methods in the ngOnInit method
  ngOnInit(){
    this.accountService.where([new ACondition(this.accountService.type, 'Id', 'NotNull', null)], 'AND', null, null, new APageInfo(1, 1)).subscribe(res => {
      /*
        res === [
          {
            Name: 'Account A',
            BillingStreet: '1234 Main Street',
            MyCustomField: 44,
            PriceList: {
              ...
            }
          }
        ]
      */
    });
    this.accountService.describe(Account, 'MyCustomField', false).subscribe(res => {
      // Describe information for My_Custom_Field__c
    });

    this.accountService.search('Main street').subscribe(res => {
      // SOSL Search Results
      // Note : search does not follow the model pattern and will return results specified in the query
    });

    this.accountService.get(['00Fxxxxxxx', '00Fxxxxxxx']).subscribe(res => {
      // Returns an array of account records
    })

    this.accountService.aggregate([new ACondition(this.accountService.type, 'Id', 'NotNull', null)]).subscribe(res => {
      // Returns aggregates for the specified clause. (i.e. total records as well as max/min values for all 
      // fields specified in the model)
    })

    this.accountService.create([new Account()]).subscribe(res => {
      // Returns list of id's created
    })

    this.accountService.update([new Account()]).subscribe(res => {
      // Returns list of id's updated
    })  

    this.accountService.upsert([new Account()]).subscribe(res => {
      // Returns list of objects upserted
    }) 

    this.accountService.delete([new Account()]).subscribe(res => {
      // Returns list of boolean values for accounts that were successfully deleted
    })
  }
}

deploy

To lint all *.ts files:

$ npm run lint

To deploy your code to your Salesforce org

$ npm run deploy

# Known Issues

@Angular/cli 6.0.0 Can't Resolve Stream

If you have upgraded to @angular/cli 6, and you're seeing the following error

WARNING in C:/Workspace/ngs-workspace/node_modules/xml2js/node_modules/sax/lib/sax.js
Module not found: Error: Can't resolve 'stream' in 'C:\Workspace\ngs-workspace\node_modules\xml2js\node_modules\sax\lib'

ERROR in C:/Workspace/ngs-workspace/node_modules/csv-parse/lib/index.js
Module not found: Error: Can't resolve 'stream' in 'C:\Workspace\ngs-workspace\node_modules\csv-parse\lib'
ERROR in C:/Workspace/ngs-workspace/node_modules/csv-stringify/lib/index.js
Module not found: Error: Can't resolve 'stream' in 'C:\Workspace\ngs-workspace\node_modules\csv-stringify\lib'
ERROR in C:/Workspace/ngs-workspace/node_modules/xml2js/lib/parser.js
Module not found: Error: Can't resolve 'timers' in 'C:\Workspace\ngs-workspace\node_modules\xml2js\lib'
i 「wdm」: Failed to compile.

Fix: Add path

Add the following to your tsconfig.app.json file under 'compilerOptions':

"paths" : {
  "jsforce" : ["./node_modules/jsforce/build/jsforce.min.js"]
  ...
}

Uncaught Error: No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.

In order to work on a visualforce page, your app needs to be setup to use the hash routing location strategy instead of the default

Fix: Set the useHash flag in your app-routing.module.ts file

In your app-routing.module.ts file, set the useHash flag in the RouterModule.forRoot(...) call

@NgModule({
  imports: [RouterModule.forRoot(appRoutes,  { useHash: true })],
  exports: [RouterModule]
})
export class AppRoutingModule { }

result-matching ""

    No results matching ""