Skip to content

Commit efce93d

Browse files
committed
W-9302034 and W-10275269: Adds cart to order sample apex back in.
Also fixes anchor navigation tabs on the flow to be buttons (better matches the flow which uses buttons so as not to confuse users). This also fixes some color formatting issues. Additionally, the async subflows now pass a cart id on error to error screen so as to avoid that ugly "No cart id" error we were seeing.
1 parent 5704f65 commit efce93d

File tree

6 files changed

+331
-21
lines changed

6 files changed

+331
-21
lines changed

examples/checkout-main/flows/Checkout_Subflow_Calculate_Promotions.flow

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,12 @@
221221
<locationX>1177</locationX>
222222
<locationY>855</locationY>
223223
<flowName>Checkout_Subflow_Error</flowName>
224+
<inputAssignments>
225+
<name>cartId</name>
226+
<value>
227+
<elementReference>cartId</elementReference>
228+
</value>
229+
</inputAssignments>
224230
<inputAssignments>
225231
<name>ErrorMessage</name>
226232
<value>

examples/checkout-main/flows/Checkout_Subflow_Confirm_Price.flow

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,12 @@
221221
<locationX>1177</locationX>
222222
<locationY>855</locationY>
223223
<flowName>Checkout_Subflow_Error</flowName>
224+
<inputAssignments>
225+
<name>cartId</name>
226+
<value>
227+
<elementReference>cartId</elementReference>
228+
</value>
229+
</inputAssignments>
224230
<inputAssignments>
225231
<name>ErrorMessage</name>
226232
<value>
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
/**
2+
* This is designed as a handy starting point for writing code to convert a cart to an order. The built in CartToOrder invocable
3+
* action is maintained and has additions and fixes not found in this class. Whenever possible, it is suggested to use that invocable
4+
* action rather than relying on this invocable action that has limited support and is not tested each release.
5+
*
6+
* Multi-currency has not been tested, though you'll see a couple uses of currency codes (CurrencyIsoCode) commented out in this class.
7+
* If you are using multi-currency in your org, I would uncomment those lines out.
8+
*/
9+
public class B2BCartToOrderDraft {
10+
11+
public class B2BCartToOrderDraftRequest {
12+
13+
@InvocableVariable(required=true)
14+
public ID checkoutSessionId;
15+
16+
@InvocableVariable(required=true)
17+
public ID cartId;
18+
}
19+
20+
/**
21+
* @description Maps a cart to an order. Activates it, and closes the cart. Returns the resulting order summary id.
22+
* @param request The checkout session and cart id.
23+
* @return The OrderId that resulted from this class.
24+
*/
25+
@InvocableMethod(label='Map Cart to Order Draft' description='Maps the cart and related data to an order' category='B2B Commerce')
26+
public static List<ID> cartToOrder(List<B2BCartToOrderDraftRequest> request) {
27+
28+
// screen flows do not run in bulk
29+
Id cartId = request[0].cartId;
30+
Id checkoutSessionId = request[0].checkoutSessionId;
31+
32+
// load the primary delivery group (only one supported at this time)
33+
Id cartDeliveryGroupId = [SELECT Id FROM CartDeliveryGroup WHERE CartId = :cartId][0].Id;
34+
35+
Id orderId = mapAndInsertCartToOrder(cartId);
36+
updateCheckoutSession(checkoutSessionId, orderId);
37+
38+
Id orderDeliveryGroupId = mapAndInsertCartDeliveryGroupToOrderDeliveryGroup(cartDeliveryGroupId, orderId);
39+
mapAndInsertCartItems(cartDeliveryGroupId, orderId, orderDeliveryGroupId);
40+
41+
List<ID> orderIds = new List<ID>();
42+
orderIds.add(orderId);
43+
return orderIds;
44+
}
45+
46+
/**
47+
* @description Satisfy the preconditions required to use the following call to Activate the Order
48+
*/
49+
private static void updateCheckoutSession(Id checkoutSessionId, Id orderId) {
50+
try {
51+
CartCheckoutSession checkoutSession = [SELECT OrderId, NextState FROM CartCheckoutSession WHERE Id = :checkoutSessionId LIMIT 1];
52+
checkoutSession.OrderId = orderId;
53+
checkoutSession.NextState = 'Complete';
54+
update checkoutSession;
55+
} catch (Exception e) {
56+
System.debug('An error occurred updating checkout session with the draft order Id');
57+
}
58+
}
59+
60+
/**
61+
* @description Maps the cart entity to an order entity and returns the id of the order entity that was created.
62+
* @param cartId The cart id to map to an order.
63+
* @return The id of the order that was created.
64+
*/
65+
private static Id mapAndInsertCartToOrder(Id cartId) {
66+
// Get the cart data needed to populate the order
67+
List<WebCart> carts = [SELECT Id,
68+
AccountId,
69+
OwnerId,
70+
WebStoreId,
71+
PoNumber,
72+
BillingStreet,
73+
BillingCity,
74+
BillingState,
75+
BillingPostalCode,
76+
BillingCountry,
77+
// CurrencyIsoCode -- multi-currency only
78+
BillingLatitude,
79+
BillingLongitude
80+
FROM WebCart WHERE Id = :cartId];
81+
WebCart cart = carts[0];
82+
83+
84+
// Create the order
85+
Date now = Date.today();
86+
Order order = new Order(
87+
AccountId = cart.AccountId,
88+
OwnerId = cart.OwnerId,
89+
SalesStoreId = cart.WebStoreId,
90+
PoNumber = cart.PoNumber,
91+
BillingStreet = cart.BillingStreet,
92+
BillingCity = cart.BillingCity,
93+
BillingState = cart.BillingState,
94+
BillingPostalCode = cart.BillingPostalCode,
95+
BillingCountry = cart.BillingCountry,
96+
BillingLatitude = cart.BillingLatitude,
97+
BillingLongitude = cart.BillingLongitude,
98+
// CurrencyIsoCode = cart.CurrencyIsoCode, -- multi-currency only
99+
EffectiveDate = now,
100+
OrderedDate = now,
101+
Status = 'Draft'
102+
);
103+
104+
insert(order);
105+
return order.Id;
106+
}
107+
108+
/**
109+
* @description Maps the cart delivery group entity to an order delivery group entity and returns the id of the
110+
* order delivery group entity that was created.
111+
* @param cartDeliveryGroupId The cartDeliveryGroup id to map.
112+
* @param orderId The orderDeliveryGroup is linked to the original order.
113+
* @return The id of the order delivery group that was created.
114+
*/
115+
private static Id mapAndInsertCartDeliveryGroupToOrderDeliveryGroup(Id cartDeliveryGroupId, Id orderId) {
116+
// Get the cart delivery group data needed to populate the order delivery group
117+
List<CartDeliveryGroup> cartDeliveryGroups = [SELECT
118+
DesiredDeliveryDate,
119+
DeliverToName,
120+
ShippingInstructions,
121+
DeliverToStreet,
122+
DeliverToCity,
123+
DeliverToState,
124+
DeliverToPostalCode,
125+
DeliverToCountry,
126+
DeliverToLatitude,
127+
DeliverToLongitude,
128+
DeliveryMethodId
129+
FROM CartDeliveryGroup WHERE Id = :cartDeliveryGroupId];
130+
CartDeliveryGroup cartDeliveryGroup = cartDeliveryGroups[0];
131+
132+
// Create the order delivery group
133+
Date desiredDeliveryDate = toDate(cartDeliveryGroup.DesiredDeliveryDate);
134+
OrderDeliveryGroup orderDeliveryGroup = new OrderDeliveryGroup(
135+
DesiredDeliveryDate = desiredDeliveryDate,
136+
DeliverToName = cartDeliveryGroup.DeliverToName,
137+
DeliveryInstructions = cartDeliveryGroup.ShippingInstructions,
138+
DeliverToStreet = cartDeliveryGroup.DeliverToStreet,
139+
DeliverToCity = cartDeliveryGroup.DeliverToCity,
140+
DeliverToState = cartDeliveryGroup.DeliverToState,
141+
DeliverToPostalCode = cartDeliveryGroup.DeliverToPostalCode,
142+
DeliverToCountry = cartDeliveryGroup.DeliverToCountry,
143+
DeliverToLatitude = cartDeliveryGroup.DeliverToLatitude,
144+
DeliverToLongitude = cartDeliveryGroup.DeliverToLongitude,
145+
OrderDeliveryMethodId = cartDeliveryGroup.DeliveryMethodId,
146+
OrderId = orderId
147+
);
148+
149+
insert(orderDeliveryGroup);
150+
return orderDeliveryGroup.Id;
151+
}
152+
153+
/**
154+
* @description Maps the cart items to a set of order items. This also creates order item adjustments.
155+
* Tax adjustments could probably also be done here, but are not part of the example.
156+
* @param cartDeliveryGroupId the cartDeliveryGroup id for this set of cart items.
157+
* @param orderId The items are linked to the original order.
158+
* @param orderDeliveryGroupId The items are linked to the order delivery group.
159+
*/
160+
private static void mapAndInsertCartItems(Id cartDeliveryGroupId, Id orderId, Id orderDeliveryGroupId) {
161+
// Get the cart items needed to populate the order items and adjustments
162+
List<CartItem> cartItems = [SELECT
163+
AdjustmentAmount,
164+
Product2Id,
165+
Type,
166+
Quantity,
167+
ListPrice,
168+
SalesPrice,
169+
TotalLineAmount
170+
FROM CartItem WHERE CartDeliveryGroupId = :cartDeliveryGroupId];
171+
172+
List<OrderItem> orderItems = new List<OrderItem>();
173+
// For each item, map it to an order, then add adjustments
174+
for (CartItem cartItem : cartItems) {
175+
orderItems.add(mapCartItemToOrderItem(cartItem, orderId, orderDeliveryGroupId));
176+
}
177+
178+
// If there are no items to insert, we can't do anything
179+
if (orderItems.size() == 0 || cartItems.size() != orderItems.size()) {
180+
return;
181+
}
182+
183+
insert(orderItems);
184+
185+
List<OrderItemAdjustmentLineItem> lineItemAdjustments = new List<OrderItemAdjustmentLineItem>();
186+
for (Integer index = 0; index < cartItems.size(); index++) {
187+
OrderItemAdjustmentLineItem lineItemAdjustment = mapOrderItemAdjustmentLineItemTo(cartItems.get(index), orderItems.get(index).Id);
188+
if (lineItemAdjustment != null) {
189+
lineItemAdjustments.add(lineItemAdjustment);
190+
}
191+
}
192+
if (lineItemAdjustments.size() > 0) {
193+
insert(lineItemAdjustments);
194+
}
195+
}
196+
197+
/**
198+
* @description Maps the cart item to an order item.
199+
* @param cartItem The cartItem to map to an order item.
200+
* @param orderId The item is linked to the original order.
201+
* @param orderDeliveryGroupId The item is linked to the order delivery group.
202+
* @return The order item to be inserted.
203+
*/
204+
private static OrderItem mapCartItemToOrderItem(CartItem cartItem, Id orderId, Id orderDeliveryGroupId) {
205+
String orderItemType = getOrderItemType(cartItem.Type);
206+
Decimal unitPrice = getUnitPrice(cartItem);
207+
208+
OrderItem orderItem = new OrderItem(
209+
Product2Id = cartItem.Product2Id,
210+
Type = orderItemType,
211+
Quantity = cartItem.Quantity,
212+
ListPrice = cartItem.ListPrice,
213+
UnitPrice = unitPrice,
214+
OrderId = orderId,
215+
OrderDeliveryGroupId = orderDeliveryGroupId,
216+
TotalLineAmount = cartItem.TotalLineAmount
217+
);
218+
219+
return orderItem;
220+
}
221+
222+
223+
224+
/**
225+
* @description Maps the cart item to create an adjustment line item. If the item would normally cost
226+
* $100, but costs $80, this is where that adjustment is recorded.
227+
* @param cartItem The cartItem to map to an order adjustment line item.
228+
* @param orderItemId The adjustment is mapped to an order item.
229+
* @return The order item adjustment to be inserted.
230+
*/
231+
private static OrderItemAdjustmentLineItem mapOrderItemAdjustmentLineItemTo(CartItem cartItem, Id orderItemId) {
232+
Decimal adjustmentAmount = getAdjustmentAmount(cartItem);
233+
if (adjustmentAmount == null || adjustmentAmount == 0.0) {
234+
return null;
235+
}
236+
237+
OrderItemAdjustmentLineItem orderItemAdjustmentLineItem = new OrderItemAdjustmentLineItem(
238+
Amount = adjustmentAmount,
239+
OrderItemId = orderItemId,
240+
Name = 'Price Adjustment'
241+
);
242+
243+
return orderItemAdjustmentLineItem;
244+
}
245+
246+
247+
/**
248+
* @description Gets the adjustment amount from the cart item. If none exists, returns zero.
249+
* @param cartItem Where to get the adjustment amount from.
250+
* @return The adjustment amount (0, if there is no adjustment).
251+
*/
252+
private static Decimal getAdjustmentAmount(CartItem cartItem) {
253+
if (cartItem.AdjustmentAmount == null) {
254+
return 0;
255+
}
256+
257+
return cartItem.AdjustmentAmount;
258+
}
259+
260+
/**
261+
* @description Gets the order item type from the sales item type. This maps the cart item type to the order item type.
262+
* @param salesItemType The cart item's type.
263+
* @return The order Item Type or null if the type doesn't map.
264+
*/
265+
private static String getOrderItemType(String cartItemType) {
266+
if (cartItemType == 'Product') {
267+
return 'Order Product';
268+
}
269+
if (cartItemType == 'Charge') {
270+
return 'Delivery Charge';
271+
}
272+
273+
return null;
274+
}
275+
276+
/**
277+
* @description Gets the unit price from the cart item. This tries to use the sales price but will default to the list price
278+
* if there is no sales price.
279+
* @param cartItem The item that has the prices.
280+
* @return The unit price.
281+
*/
282+
private static Decimal getUnitPrice(CartItem cartItem) {
283+
if (cartItem.SalesPrice != null) {
284+
return cartItem.SalesPrice;
285+
}
286+
287+
return cartItem.ListPrice;
288+
}
289+
290+
/**
291+
* @description Converts a DateTime object to a Date object.
292+
* @param dt The datetime to convert.
293+
* @return The new Date.
294+
*/
295+
private static Date toDate(DateTime dt) {
296+
if (dt != null) {
297+
return Date.newinstance(dt.year(), dt.month(), dt.day());
298+
}
299+
300+
return null;
301+
}
302+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>54.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>

examples/lwc/force-app/main/default/lwc/navigationButtons/navigationButtons.html

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@
22
<div class="slds-card__footer slds-p-vertical_x-small">
33

44
<!-- Previous Button -->
5-
<div if:true={canGoPrevious} class="slds-button slds-button_brand">
6-
<a href="javascript:void(0)" onclick={handlePreviousButton}
7-
>{previousButtonLabel}</a
8-
>
9-
</div>
5+
<button if:true={canGoPrevious} class="slds-button slds-button_outline-brand" onclick={handlePreviousButton}
6+
>{previousButtonLabel}</button
7+
>
108

119
<!-- Next Button -->
12-
<div class="slds-button slds-button_brand">
13-
<a href="javascript:void(0)" onclick={handleNextButton}
14-
>{nextButtonLabel}</a
15-
>
16-
</div>
10+
<button class="slds-button slds-button_brand" onclick={handleNextButton}
11+
>{nextButtonLabel}</button
12+
>
1713
</div>
1814
</template>

examples/lwc/force-app/main/default/lwc/paymentMethod/paymentMethod.html

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -108,16 +108,11 @@
108108

109109
<!-- Navigation buttons -->
110110
<div class="slds-card__footer slds-p-vertical_x-small">
111-
112-
<div if:true={canGoPrevious} class="slds-button slds-button_brand">
113-
<a href="javascript:void(0)" onclick={handlePreviousButton}
114-
>{previousButtonLabel}</a
115-
>
116-
</div>
117-
<div class="slds-button slds-button_brand">
118-
<a href="javascript:void(0)" onclick={handlePaymentButton}
119-
>{nextButtonLabel}</a
120-
>
121-
</div>
111+
<button if:true={canGoPrevious} class="slds-button slds-button_outline-brand" onclick={handlePreviousButton}
112+
>{previousButtonLabel}</button
113+
>
114+
<button class="slds-button slds-button_brand" onclick={handlePaymentButton}
115+
>{nextButtonLabel}</button
116+
>
122117
</div>
123118
</template>

0 commit comments

Comments
 (0)