In this workshop we will be developing and packaging a sample AppExchange ISV app that works with the Salesforce B2B Commerce and Order Management products, which are both part of the Salesforce core platform tech stack. For packaging, we will be using Second-Generation Packaging (2GP).
- Tooling Setup
- Build our app in the Commerce org
- Pull the created metadata out of the Commerce org using VS Code
- Package it
- Demo: connect our package to your Partner Community publishing console, submit for Security Review and list it on the AppExchange
Here are the pre-requisites that workshop attendees should have installed on their computers:
- Java/JDK version 17, 11, or 8 (if you click these links, scroll down to the table on the site it opens)
- Git
- Salesforce CLI
- VS Code
- Salesforce Extensions for VS Code
Use case: The sample app we will be building is a Shipping Calculation app which B2B Commerce will use to calculate shipping costs in real-time once checkout begins, and Order Management will use for re-ship requests. Note: We are keeping the app simple for the sake of this exercise. Realistically, an app may have more to it than this, such as integration with shipping logistics provider APIs, updates on shipping status, etc.
We will be connecting to two orgs: one to build our app inside of, and one to allow us to package the app and list it on AppExchange. We will refer to these as our Commerce Org and our Dev Hub, respectively.
- Tooling setup:
- First, we will clone the Github repo we’ve prepared for this workshop, in the interest of time we have partially built our ISV app in advance
- Go to the commerce-workshop Github repo, click the green Code button, and copy the URL from there
- Now open VS Code. You may see either the “Get Started” screen in VS Code, or it may open the most recent directory you’ve been working in.
- Here is what the Get Started screen looks like:
- If you do not see this Get Started screen:
- From the Get Started Screen, click on Clone Git Repository...
- This will open the command palette with instructions to provide the repository URL
- Paste the URL we copied from Github earlier, and hit the Enter/Return key
- A popup window will open. Click Desktop, then click Select Repository Location
- This will open a new popup window. Click Open
- This will open VS Code in the context of the new repository we have just cloned to our local machine. You should now see commerce-workshop as the root folder in VS Code’s left pane
- Next, we will connect the Salesforce CLI to the Dev Hub org (so we can later package our app)
- In VS Code, click on No Default Org Set on the bottom toolbar, which will open the Command Palette
- In the Command Palette, click on SFDX: Authorize a Dev Hub
- This will open a new tab in your browser with a Salesforce login screen
- 1. Note: these instructions are written for a live workshop where I set up the orgs and everyone’s logins beforehand. If you are following along yourself, you can create your own [Dev Hub](https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/sfdx_setup_enable_devhub.htm) and your own Commerce org (using either a [Trialforce Template and Environment Hub](https://salesforce.quip.com/q9RUACra2Jfa) or a [Demo org](https://partners.salesforce.com/pdx/s/learn/article/demo-station-for-partners-MCUTYORCVUVNCJTIVCKP6VHUKF3M?language=en_US) for the Commerce org) for free
- Log in with your username and password for this Dev Hub org:
- Username: <>.commerce-workshop-dev-hub
- Password: (I will give this to you in the workshop)
- Click Allow, which authorizes the Salesforce CLI to connect to this Dev Hub org in the context of your user login
- If it asks for your phone number, click Remind Me Later
- Finally, connect the Salesforce CLI to your Commerce org (where we will build our app)
- In VS Code, once again click on No Default Org Set on the bottom toolbar, which will open the Command Palette
- This time in the Command Palette, click on SFDX: Authorize an Org (not a Dev Hub)
- This brings up a set of options, click Production
- Next, for the org’s alias, type commerce-workshop-develop and hit Enter/Return
- This will open a new tab in your browser with a Salesforce login screen
- Log in with your username and password for this org:
- Username: <>.commerce-workshop-develop
- Password: (I will give this to you in the workshop)
- Click Agree, to authorize the Salesforce CLI to connect to this org
- Notice the bottom toolbar of VS Code no longer says “No Default Org Set”, it says commerce-workshop-develop, which is the alias we gave to the Commerce org. It also shows a plug icon to indicate that Salesforce CLI is connected to default org
- Congrats! The Salesforce CLI is now connected to both orgs we need: the Dev Hub (to package our app later), and the Commerce org (where we will build our app now)
- First, we will clone the Github repo we’ve prepared for this workshop, in the interest of time we have partially built our ISV app in advance
- Build the app in the Commerce org
- Part 1: Push code into the Commerce Org
- In VS Code, we will now take two Apex classes, ShippingService.cls and ShippingServiceTest.cls, that we got from cloning the Github repo and push them into the Commerce org so we can use them in the app we’re going to develop
- In the left pane of VS Code you should see a file directory. If you don’t see this, click on the topmost icon in the left sidebar to open it.
- Click on the force-app folder
- From there, right-click on the classes folder, which opens a pop-up menu
- Click on the SFDX: Deploy Source to Org option, near the bottom
- You should receive a success message pop-up window near the bottom right of your VS Code window
- Now, toward the left side of the bottom toolbar, click on the below icon, which resembles a mini browser window. This opens the Commerce org in your browser. Notice you don’t have to log in again!
- Part 2: Configure a Sample Order Management ISV App
- Overview: Since our use case is a Shipping Calculation ISV App, we will clone and modify one of Order Management’s out-of-the-box flows, a reshipment flow, to leverage our ISV app’s functionality
- In the Commerce org, click the cog wheel toward the top right of your screen and click Setup.
- Type “Flow” in the quick find search near the top left of the Setup menu, and click Flows.
- Find and click on the Flow named Create Reship Order to open it
- Click Save As
- In the popup window, click A New Flow
- For Flow Label, type Create Reship Order Clone. The API name will be auto-populated to Create_Reship_Order_Clone
- Click Save
- Now in your newly cloned flow, drag the screen to the right on the flow canvas (the big area on the right side), and look for the blue Screen element titled Location Selection
- From the Flow Toolbox (the panel on the left side of the screen), drag an Action element onto the canvas, to the right of the Location Selection element
- In the pop-up that opens, for the Category on the left side, click Commerce
- Then in the Action box on the right, select Calculate Shipping Price, which is an invocable Apex method in the Apex class we pushed into the org earlier.
- Name the element Calculate Shipping Price.
- For the Label, type Calculate Shipping Price and click Done
- 1. The use case is a bit contrived- we are adding a shipping calculation to a re-ship request flow. Usually a re-ship request happens because a customer’s original shipment was lost or damaged and many companies will not charge any money to re-ship, to provide good customer service. This use case educational only, and is not business advice on whether to charge customers for shipping or not.
- So that we can easily see the results of this Apex action, drag a Screen element from the Flow Toolbox on the left into the canvas to the right of our new Apex action
- First, give the Screen element a label on the right side of the pop-up: Shipping Price Confirmation Screen
- Then, from the left side of the pop-up, drag a Display Text component onto the screen in the center, and then click on it
- On the right side, give this Display Text an API name such as ShippingConfirmation
- Below that, paste the text: The price to reship will be £{!Calculate_Shipping_Price} or alternatively, type it and click the box that says Insert a resource... and type calc to locate the variable holding the output of our invocable apex and then click on it
- Click Done to save the screen
- 1. This is an important concept to understand. If you use Apex inside of a Flow, the output of the Apex is automatically stored as a variable and can be referenced later, used in calculations, decisions, business logic, etc.
- Change the connections between the elements on the flow canvas:
- Click the connector between the Location Selection and Set Stage To Part 4 elements and hit the Delete key
- Click the white dot at the bottom of the Location Selection element and drag it onto the Calculate Shipping Price element.
- Do the same to connect Calculate Shipping Price to Shipping Price Confirmation Screen
- Lastly, connect Shipping Price Confirmation Screen to Set Stage To Part 4
- Save the Flow and then click Activate
- One last step to surface our new Flow! From Setup, start typing Actions & Recommendations in the quick search box in the top left and click on Actions & Recommendations
- On the row that says Summer ’22 Flow Package, click on the dropdown arrow on the far right, then click Edit
- In the popup window, click Next, then Next again
- Now click the Default tab toward the top left
- In the search box that appears, search your new flow, Create Reship Order Clone, and drag it into the list on the right
- Click Next again
- Again search your new flow, Create Reship Order Clone, and check the checkbox on the left of it
- Click Save
- Now it is time to see your flow in action! From the App Launcher (the 9 dots in a square in the top left), type and select Order Management
- Search 00001301 and click on the matching Order Summary Record
- You should see a screen like this:
- Look for your Create Reship Order Clone flow in the Actions & Recommendations section. If you don’t see it, click on the blue Add button and then start typing Create Reship Order Clone and then click on it
- Work your way through the flow until you see our new the screen we added, which shows that our invocable apex method was successfully called by our flow and returned an amount for the shipping price
- We have successfully finished development on an ISV app for Salesforce Order Management!
- Next Steps on your own for further learning:
- The Commerce orgs (which you get to keep until they expire) have a more realistic sample implementation of our Shipping app in the Apex class B2BDeliverySample (go to Setup >> Apex Classes to find this in your org), feel free to save the code for reference.
- Part 3: Configure a Sample B2B Commerce ISV App
- In the org, click the cog wheel toward the top right of your screen and click Setup.
- Type “Flow” in the quick find search near the top left of the Setup menu, and click Flows.
- Scroll to find and click on the checkout flow that is currently in use, Checkout Flow Template to open it
- Click Save As
- For Flow Label, type Checkout Flow Template Clone. The API name will be auto-populated to Checkout_Flow_Template_Clone.
- Click Save
- Now in your newly cloned flow, drag the screen downward on the flow canvas (the big area on the right side), and find the step that calculates Shipping Cost, and notice that it is a subflow
- We will replace this step with a method from our Apex class that we deployed to this org earlier. To keep things simple, we will not use a subflow here.
- The use case is, we are swapping out the out-of-the box way that B2B Commerce calculates shipping costs, and replacing it with our Apex class that would normally call out to our off-platform, third party ISV app to perform complex shipping calculations based on inputs such as an array of items and their sizes, weights, quantities, shipping methods, distance needed to deliver, etc. For this workshop we are simply mocking the callout and returning a static currency amount.
- From the Flow Toolbox panel on the left side, drag an Action element on to the canvas near the Shipping Cost subflow icon
- In the pop-up that opens, for the Category on the left side, click Commerce
- Then in the Action box on the right, select Calculate Shipping Price, which is an invocable Apex method in the Apex class we pushed into the org earlier.
- Name the element Calculate Shipping Price and click Done
- Click on the Shipping Cost subflow element and hit the Delete key
- Notice the arrows that were connected to the Shipping Cost element disappear too
- We will need to re-create those arrows to connect our new Calculate Shipping Price element to the correct existing Flow elements to form a smooth end-to-end Flow
- Drag from the white circle at the bottom of the Main Decision Hub element onto the Calculate Shipping Price element and release
- If you need to, zoom out by clicking the “-” icon in the bottom left of the flow canvas
- In the popup window that appears, make sure Shipping Cost is selected and click Done
- Next, drag from the white circle at the bottom of the Calculate Shipping Price element onto the Assignment Loop element and release
- We are done with the Flow. Here is what it should look like:
- Drag from the white circle at the bottom of the Main Decision Hub element onto the Calculate Shipping Price element and release
- Again, this Apex would normally be used to call out to an ISV app. For demo purposes, we are returning a static value to mock this callout
- Click Save in the top right corner to save the Flow
- Click Activate
- Go into Setup, type All Sites in the quick search, and click All Sites
- Click on Builder next to the AlpineB2B site
- In Experience Builder, click Home in the top toolbar on the left, then click on Checkout
- Click on the Checkout Flow component to bring up a floating panel on the right. In this panel, select your new Flow, Checkout Flow Template Clone so that it will run the newly cloned flow instead of the original checkout flow demoed earlier
- In the top right of Experience Builder, click Publish, the Publish again so that your changes can be seen in the Site
- SKIP for workshop Try out the new checkout flow to show the difference
- On your tab that still has salesforce open (not the B2B Site), click the app launcher and type Contacts, and click Contacts
- Search for Bonnie Buyer and click into this record
- Click on the dropdown arrow in the actions area near the top right of the screen, and click on Log in to Experience as User
- 1. Note: if you don’t see this button appearing, click the cog wheel near the top right of the screen, click **Edit Page**, click the top right area with these action buttons, then click **Add Action** near the bottom right, add the **Log in to Experience as User** action to the list, and click **Done**. Click **Save** and then click **Activation** to make sure the page is assigned as the Org Default, then return to the page by clicking the left arrow in the top left of the edit screen
- Add one of the products to your cart, click the cart icon, and click Checkout to see our flow working
- The development work is complete!
- Part 1: Push code into the Commerce Org
- Pull the created metadata out of the org using VS Code
- Note: Today we are developing in a non-scratch org due to scratch org tooling for Order Management still being worked on. If we were developing in a scratch org, all of our changes to the org’s metadata would automatically be tracked, and we could just pull changes without having to remember every piece of metadata we created or changed
- To retrieve our B2B Commerce flow, paste the following command into VS Code’s embedded terminal:
- All of the functionality that we developed inside the org, along with the pre-written code we got from Github initially, is now in our local directory which can be seen in VS Code’s left pane. Next step is to package it for distribution and sale
- We are going to skip a few steps of development lifecycle here. Here is an opinionated view of the steps we are skipping:
- Normally, we would deploy the metadata into a scratch org to test whether it can be deployed successfully and that it functions as expected inside a different org (Unit tests, QA, UAT, integration test, etc.)
- If the above tests are successful, we would stage & commit the changes to git and push to the developer’s personal branch on the Github repo
- We would open a Pull Request, which would trigger a CI/CD job which would run a static code analysis, deploy the metadata into a scratch org, run all apex (and any other types of) tests, and if everything passes, notify a dev lead to do a code review
- A Dev Lead merges the Pull Request into, for example, a release branch
- Then we are ready to package the app (or just create a new package version, if it is an existing packaged app)
- Package your app
- We are going to go fast here. See this terrific documentation for more context on each step we do here:
- Paste and enter the following commands, in order:
sfdx force:package:create -n "Commerce Workshop App B2B" -r force-app -t Managed
- Note: you will likely get the error “The package name must be unique for the namespace”. Modify the command above to add some characters to then end of the name so that your name is unique, and run it again. Use this new name in the below steps as well.
sfdx force:package:version:create —p "Commerce Workshop App B2Bv2" —w 10 -x -c -f config/project-scratch-def.json
- We are once again skipping steps here - Normally we would install the package (before promoting it) into a scratch org to test that we can install/upgrade successfully, and that the functionality works as expected
sfdx force:package:version:promote -p "Commerce Workshop App B2B@0.1.0-1" -n
- Submit package for Security Review & List on AppExchange
- At this point we are ready to connect our package to our Partner Community login so that we can submit it for Security Review and list it live on the AppExchange
- We will just demo this, since we don’t want to actually list this sample app on AppExchange or dirty your data
- Some background: typically your company receives its PBO (Partner Business Org) when the first person from the company creates a login in the Partner Community as an ISV.
- This person’s username and password to log in to the PBO and to the Partner Community are the same
- We strongly advise ISVs to use this PBO as their Dev Hub, which means it will own all 2GPs (second-generation packages)
- To connect your package to your Partner Community login:
- Log in to the Partner Community
- Click on the Publishing tab
- then click on the Organizations subtab
- If you don’t see your Dev Hub org, click the Connect Org button and log in to it
- Now go to the Packages subtab and you should see your package
- Notice there are options here to Start Review and Create Listing. These can be done in parallel. Security Review takes time, so in the meantime you can design and optimize how you want your future AppExchange Listing to look
- Security Review goes a lot smoother if you understand what best practices it will check for before you start developing a real ISV application
- Here is how to prepare for and submit for Security Review, and a requirements checklist to help you ace your review. Please read this carefully, as Security Review can cause major go-live delays if we have to have many cycles of submitting, rejection, and resubmitting
- Once you are notified that your app has passed Security Review, you can go to the Listings subtab and click the Publish Listing button to make your app live on the AppExchange for customers to find!
- Congratulations, your live AppExchange listing will now start generating leads!
- At this point we are ready to connect our package to our Partner Community login so that we can submit it for Security Review and list it live on the AppExchange