Note: This release is in preview. Features described here don’t become generally available until the latest general availability date that Salesforce announces for this release. Before then, and where features are noted as beta, pilot, or developer preview, we can’t guarantee general availability within any particular time frame or at all. Make your purchase decisions only on the basis of generally available products and features.
SaleRequest Class
Namespace
Usage
This class holds all the required details about a sale request. Gateway adapters read the fields of this class object while constructing a sale JSON request thatis sent to the payment gateway. The object of this class is made available through commercepayments.paymentGatewayContext by calling getPaymentRequest().
Example
1/**
2 * Responsibilities:
3 * - Set merchant and reference details
4 * - Convert amount into minor units (e.g., cents)
5 * - Map payment method types (card, ACH, SEPA, etc.)
6 * - Include stored payment method token for recurring payments
7 * - Optionally include enhanced Level 2/3 data
8 *
9 * @param saleRequest Input request containing payment and shopper details
10 * @return JSON string payload for the payment gateway
11 */
12 private String buildSaleRequest(commercepayments.SaleRequest saleRequest) {
13
14 // Resolve currency (fallback to user's default if missing)
15 String currencyIso = saleRequest.currencyIsoCode;
16 if (currencyIso == null) {
17 currencyIso = UserInfo.getDefaultCurrency();
18 }
19
20 // Extract payment method
21 commercepayments.SaleApiPaymentMethodRequest paymentMethod = saleRequest.paymentMethod;
22
23 // Initialize JSON generator
24 JSONGenerator jsonGeneratorInstance = JSON.createGenerator(true);
25 jsonGeneratorInstance.writeStartObject();
26
27 // Merchant configuration (from Named Credential)
28 jsonGeneratorInstance.writeStringField('merchantAccount', '{!$Credential.Username}');
29
30 // Unique reference using timestamp + random suffix
31 jsonGeneratorInstance.writeStringField(
32 'reference',
33 String.valueOf(Datetime.now().getTime()) +
34 String.valueOf(Math.random()).substring(2, 8)
35 );
36
37 // Amount block
38 jsonGeneratorInstance.writeFieldName('amount');
39 jsonGeneratorInstance.writeStartObject();
40 jsonGeneratorInstance.writeStringField(
41 'value',
42 String.valueOf((saleRequest.amount * 100.0).intValue()) // convert to minor units
43 );
44 jsonGeneratorInstance.writeStringField('currency', currencyIso);
45 jsonGeneratorInstance.writeEndObject();
46
47 // Payment method block
48 jsonGeneratorInstance.writeFieldName('paymentMethod');
49 jsonGeneratorInstance.writeStartObject();
50
51 String shopperReference;
52 String type = 'scheme'; // default = card
53
54 // Handle stored payment method data (tokenized payments)
55 if (saleRequest.paymentMethodData != null) {
56
57 String token = saleRequest.paymentMethodData.get('gatewayToken');
58 String paymentMethodType = saleRequest.paymentMethodData.get('paymentMethodType');
59 shopperReference = saleRequest.paymentMethodData.get('gatewayReference');
60
61 // Map payment method types to gateway-specific values
62 if ('us_bank_account'.equals(paymentMethodType)) {
63 type = 'ach';
64 } else if ('sepa_debit'.equals(paymentMethodType)) {
65 type = 'sepadirectdebit';
66 } else if ('au_becs_debit'.equals(paymentMethodType)) {
67 type = 'directdebit_AU';
68 } else if ('bacs_debit'.equals(paymentMethodType)) {
69 type = 'directdebit_GB';
70 }
71
72 jsonGeneratorInstance.writeStringField('type', type);
73 jsonGeneratorInstance.writeStringField('storedPaymentMethodId', token);
74 }
75
76 // Add enhanced scheme data ONLY for card payments
77 // Note: Gateway might have validations on L2/L3 data so do test them out before using L2/L3 else transactions might fail
78 if (enhancedPaymentData != null && 'scheme'.equals(type)) {
79 jsonGeneratorInstance.writeFieldName('additionalData');
80 jsonGeneratorInstance.writeStartObject();
81 populateEnhancedSchemeData(jsonGeneratorInstance, enhancedPaymentData);
82 jsonGeneratorInstance.writeEndObject(); // additionalData
83 }
84
85 jsonGeneratorInstance.writeEndObject(); // paymentMethod
86
87 // Recurring / shopper configuration
88 jsonGeneratorInstance.writeStringField('shopperInteraction', 'ContAuth');
89 jsonGeneratorInstance.writeStringField('recurringProcessingModel', 'UnscheduledCardOnFile');
90 jsonGeneratorInstance.writeStringField('shopperReference', shopperReference);
91
92 // Immediate capture
93 jsonGeneratorInstance.writeNumberField('captureDelayHours', 0);
94
95 jsonGeneratorInstance.writeEndObject(); // root
96
97 return jsonGeneratorInstance.getAsString();
98 }
99
100 /**
101 * Populates Level 2 and Level 3 enhanced scheme data.
102 *
103 * @param jsonGeneratorInstance JSON generator
104 * @param enhancedPaymentData Enhanced payment data input
105 */
106 private void populateEnhancedSchemeData(JSONGenerator jsonGeneratorInstance,
107 commercepayments.EnhancedPaymentDataInput enhancedPaymentData) {
108
109 // -------- Level 2 fields --------
110
111 if (enhancedPaymentData.totalTaxAmount != null) {
112 jsonGeneratorInstance.writeStringField(
113 'enhancedSchemeData.totalTaxAmount',
114 toMinorUnits(enhancedPaymentData.totalTaxAmount)
115 );
116 }
117
118 if (enhancedPaymentData.shippingAmount != null) {
119 jsonGeneratorInstance.writeStringField(
120 'enhancedSchemeData.freightAmount',
121 toMinorUnits(enhancedPaymentData.shippingAmount)
122 );
123 }
124
125 if (enhancedPaymentData.discountAmount != null) {
126 jsonGeneratorInstance.writeStringField(
127 'enhancedSchemeData.discountAmount',
128 toMinorUnits(enhancedPaymentData.discountAmount)
129 );
130 }
131
132 if (enhancedPaymentData.invoiceNumber != null) {
133 jsonGeneratorInstance.writeStringField(
134 'enhancedSchemeData.customerReference',
135 enhancedPaymentData.invoiceNumber
136 );
137 }
138
139 // -------- Level 3 fields (line items) --------
140
141 if (enhancedPaymentData.lineItems != null) {
142 Integer index = 1;
143
144 for (commercepayments.LineItemInput item : enhancedPaymentData.lineItems) {
145 populateLineItemData(
146 jsonGeneratorInstance,
147 item,
148 'enhancedSchemeData.itemDetailLine' + index + '.'
149 );
150 index++;
151 }
152 }
153
154 // Shipping / destination info
155 if (enhancedPaymentData.shipFromZip != null) {
156 jsonGeneratorInstance.writeStringField(
157 'enhancedSchemeData.shipFromPostalCode',
158 enhancedPaymentData.shipFromZip
159 );
160 }
161
162 if (enhancedPaymentData.shipToZip != null) {
163 jsonGeneratorInstance.writeStringField(
164 'enhancedSchemeData.destinationPostalCode',
165 enhancedPaymentData.shipToZip
166 );
167 }
168
169 if (enhancedPaymentData.shipToCountry != null) {
170 jsonGeneratorInstance.writeStringField(
171 'enhancedSchemeData.destinationCountryCode',
172 enhancedPaymentData.shipToCountry
173 );
174 }
175 }
176
177 /**
178 * Populates Level 3 line item data.
179 *
180 * @param jsonGeneratorInstance JSON generator
181 * @param item Line item input
182 * @param prefix Field prefix for indexed items
183 */
184 private void populateLineItemData(JSONGenerator jsonGeneratorInstance,
185 commercepayments.LineItemInput item,
186 String prefix) {
187
188 if (item.sku != null) {
189 jsonGeneratorInstance.writeStringField(prefix + 'productCode', item.sku);
190 }
191
192 if (item.name != null) {
193 jsonGeneratorInstance.writeStringField(prefix + 'description', item.name);
194 }
195
196 if (item.quantity != null) {
197 jsonGeneratorInstance.writeStringField(prefix + 'quantity', String.valueOf(item.quantity));
198 }
199
200 // Unit price is always written
201 jsonGeneratorInstance.writeStringField(
202 prefix + 'unitPrice',
203 toMinorUnits(item.unitPrice)
204 );
205
206 if (item.taxAmount != null) {
207 jsonGeneratorInstance.writeStringField(
208 prefix + 'taxAmount',
209 toMinorUnits(item.taxAmount)
210 );
211 }
212
213 if (item.discount != null) {
214 jsonGeneratorInstance.writeStringField(
215 prefix + 'discountAmount',
216 toMinorUnits(item.discount)
217 );
218 }
219
220 if (item.commodityCode != null) {
221 jsonGeneratorInstance.writeStringField(prefix + 'commodityCode', item.commodityCode);
222 }
223
224 if (item.uom != null) {
225 jsonGeneratorInstance.writeStringField(prefix + 'unitOfMeasure', item.uom);
226 }
227 }
228
229 /**
230 * Converts amount to minor units (e.g., dollars → cents).
231 *
232 * @param amount Decimal amount
233 * @return String representation of minor units
234 */
235 private static String toMinorUnits(Decimal amount) {
236 if (amount == null) return null;
237
238 Decimal value = (amount * 100)
239 .setScale(0, System.RoundingMode.HALF_UP);
240
241 return String.valueOf(value.intValue());
242 }SaleRequest Constructors
The following are constructors for SaleRequest.
SaleRequest(amount)
Signature
global SaleRequest(Double amount)
Parameters
-
amount:
Type: Double
Amount of the sale request.
SaleRequest Properties
The following are properties for SaleRequest.
enhancedPaymentData
Supported only for third-party payment gateways; not supported for native payments.
Signature
public commercepayments.EnhancedPaymentDataInput enhancedPaymentData {get; set;}
Property Value
Type: commercepayments.EnhancedPaymentDataInput
paymentInitiationSourceId
Supported only for third-party payment gateways; not supported for native payments. See PaymentInitiationSource object documentation for more information.
Signature
public String paymentInitiationSourceId {get; set;}
Property Value
Type: String
paymentMethod
Signature
global commercepayments.SaleApiPaymentMethodRequest paymentMethod {get; set;}
Property Value
paymentMethodData
This field is populated when SaleInput specifies a saved payment method. Accessible using paymentMethodData on SaleRequest. The map contains these fields from SavedPaymentMethod: GatewayToken, Type, GatewayReference, and StandardEntryCode for direct gateway interaction without querying the database.
Signature
public Map<String,String> paymentMethodData {get; set;}
submittedByMerchant
Signature
public Boolean submittedByMerchant {get; set;}
Property Value
Type: Boolean
SaleRequest Methods
The following are methods for SaleRequest.
equals(obj)
Signature
global Boolean equals(Object obj)
Parameters
-
obj:
Type: Object
Return Value
Type: Boolean
hashCode()
Signature
global Integer hashCode()
Return Value
Type: Integer