Field Mapping & Data Type Comparison: How ERPs Handle Dates, Currencies, Multi-Language Fields, and Custom Fields Differently

Type: ERP Integration Systems: Salesforce, SAP S/4HANA, Oracle ERP Cloud, NetSuite, D365 F&O, Workday, Acumatica, Business Central Confidence: 0.85 Sources: 8 Verified: 2026-03-03 Freshness: evolving

TL;DR

System Profile

This card compares how eight major ERP/CRM platforms represent and handle fundamental data types in their APIs. It covers cloud deployments only. On-premise variants may differ significantly.

SystemRoleAPI SurfaceDirection Covered
Salesforce (v62.0)CRM + ERP-adjacentREST, SOAP, Bulk 2.0Read + Write
SAP S/4HANA Cloud (2502)ERP — financials + SCMOData V2/V4Read + Write
Oracle ERP Cloud (25A)ERP — financials + procurementREST, FBDIRead + Write
Oracle NetSuite (2025.1)ERP — mid-marketREST, SuiteQL, SOAPRead + Write
D365 F&O (10.0.40+)ERP — financials + SCMOData V4, DMFRead + Write
Workday (2025R1)HCM + FinancialsREST, SOAP (WWS)Read + Write
Acumatica (2025 R1)ERP — mid-marketREST, ODataRead + Write
Business Central (v25)ERP — SMBREST API pages, OData V4Read + Write

Quick Reference

Date/DateTime Format Comparison

SystemDate FormatDateTime FormatTimezone StorageTimezone in API ResponseTimezone on Write
SalesforceYYYY-MM-DDYYYY-MM-DDTHH:mm:ss.SSSZUTC alwaysUTC (Z suffix)Must send UTC [src1]
SAP S/4HANAYYYY-MM-DDYYYY-MM-DDTHH:mm:ssUTC (OData V4)UTC (no offset in V4)UTC recommended [src2]
Oracle ERP CloudYYYY-MM-DDYYYY-MM-DDTHH:mm:ss+00:00UTCUTC with offsetUTC or offset-aware
NetSuiteMM/DD/YYYY (SOAP) / YYYY-MM-DD (REST)YYYY-MM-DDTHH:mm:ss.SSS-08:00User timezone (PST default)User's timezone offsetMust specify timezone [src4]
D365 F&OYYYY-MM-DDYYYY-MM-DDTHH:mm:ssZUTCUTCUTC [src5]
WorkdayYYYY-MM-DDYYYY-MM-DDTHH:mm:ss.SSS-07:00Tenant timezoneTenant timezone offsetMust specify or uses tenant default
AcumaticaYYYY-MM-DDYYYY-MM-DDTHH:mm:ss+00:00UTC (REST)UTC with offsetUTC recommended
Business CentralYYYY-MM-DDYYYY-MM-DDTHH:mm:ssZUTCUTCUTC

Currency & Amount Handling

SystemStorage ModelDecimal PrecisionCurrency IdentifierZero-Decimal Currencies (JPY, KRW)Multi-Currency
SalesforceDecimal (e.g., 100.50)Up to 18 digits, scale configurableCurrencyIsoCodeStored as decimal (100.00 = 100 JPY)Multi-currency org setting [src1]
SAP S/4HANASmallest unit via CURR type (e.g., 10050 for $100.50)Defined by TCURX table; default 2TransactionCurrencyTCURX entry with 0 decimalsParallel currencies (up to 10) [src2, src3]
Oracle ERP CloudDecimal (e.g., 100.50)Configurable precision + extended precisionInvoiceCurrencyCodePrecision = 0Multi-currency per ledger
NetSuiteDecimal (e.g., 100.50)0 or 2 decimal places onlycurrency.id (internalId)Currency Precision = 0Multi-subsidiary, multi-currency [src8]
D365 F&ODecimal (e.g., 100.50)Default 2; configurableCurrencyCode (ISO)Rounding rule = 1 (no decimals)Multi-company, multi-currency
WorkdayDecimal (e.g., 100.50)2-4 decimalsCurrency_ReferenceVia currency definitionMulti-currency per company
AcumaticaDecimal (e.g., 100.50)Configurable (default 2)CuryID (ISO)Decimal places = 0Multi-currency per company
Business CentralDecimal (e.g., 100.50)Configurable (Amount Rounding Precision)currencyCode (ISO)Amount Rounding Precision = 1Multi-currency per company

Custom Field / Extensibility Comparison

SystemCustom Field MechanismAPI AccessNaming ConventionDiscovery via APIMax Custom Fields
SalesforceCustom Fields on standard/custom objectsFull REST/SOAP; __c suffixMyField__cdescribe endpoint~800 per object [src1]
SAP S/4HANAKey User ExtensibilityExposed if published to ODataYY1_FieldName prefix$metadataVaries by object
Oracle ERP CloudDescriptive Flexfields (DFF) + Extensible Flexfields (EFF)Via segment namesAttribute1..Attribute30Not via REST metadataUp to 30 DFF segments per context
NetSuiteCustom Fields (entity, transaction, item, CRM)Full REST/SOAP/SuiteQLcustbody_name, custentity_namemetadata-catalogThousands [src4]
D365 F&OExtended data types + extensible enumsVia OData data entitiesStandard naming; no forced prefix$metadataEntity design limited [src6]
WorkdayCalculated Fields + Custom ObjectsCustom Reports (RaaS) for readsCustom object namingNot via standard RESTPlan-dependent
AcumaticaUser-Defined Fields (customization project)REST with Usr prefixUsrFieldName (case-sensitive)$metadataScreen customization limited
Business CentralTable Extensions + Page Extensions (AL)Only fields on API page definitionStandard AL naming$metadata on API pagePublisher extension required

Picklist / Enum / Lookup Value Handling

SystemMechanismAPI RepresentationRestricted Values?Null/Blank HandlingMulti-Select
SalesforcePicklistString valueRestricted or unrestrictedBlank = NULL in DBSemicolon-delimited [src1]
SAP S/4HANADomain Fixed Values / Check TablesString (domain value)Hard: check table enforcedEmpty string or initial valueMulti-row child entity
Oracle ERP CloudLookups (Standard + Extensible)String (lookup code)Enforced against lookup typeNULL on non-requiredChild table pattern
NetSuiteList/Record fields + Custom ListsString or internalIdEnforced against listNULL or empty stringPipe-delimited (SOAP), array (REST)
D365 F&OEnum (base + extensible)Integer internally; String via ODataEnforced0 = first enum valueBitmap or child table [src6]
WorkdayReference ID / Integration IDWID or Reference_IDEnforcedNULL not accepted for requiredNot standard
AcumaticaSelector / Combo BoxString valueEnforcedEmpty string allowedComma-separated
Business CentralEnum (AL)Integer or String via ODataEnforcedDefault value (0 or empty)Not supported

Null / Empty Value Handling

SystemNull SemanticsEmpty String BehaviorDefault Value LogicClearing a Field via API
SalesforceFields can be NULL; API returns nullTreated as NULL for most typesDefault values on create if not specifiedSend null or fieldsToNull (SOAP)
SAP S/4HANADepends on data element; many have initial valuesEmpty = initial value for CHAR; 0 for numericData dictionary initial valuesSend initial value or omit from PATCH
Oracle ERP CloudNULL on optional fieldsEmpty string and NULL treated differently in some contextsSetup configuration defaultsSend null explicitly
NetSuiteNULL supported; API returns nullDistinct from NULLField configuration defaultsSend null (REST) or nullFieldList (SOAP)
D365 F&ONULL for nullable types; 0 for enums/numericsEmpty string != NULL for stringsEnum defaults to 0; numerics to 0Send null (some fields reject it)
WorkdayNULL not accepted for requiredN/A — structured referencesBusiness process config defaultsOmit field = leave unchanged
AcumaticaNULL on optional fieldsSome fields treat as NULLGI or automation defaultsSend null in REST JSON
Business CentralNULL on optional fieldsAccepted for text fieldsTable definition defaultsSend null or empty string

Multi-Language / Locale Field Handling

SystemTranslation MechanismAPI Access to TranslationsStorage ModelFallback
SalesforceTranslation Workbench (labels, picklist values)Describe API returns labels per localeSingle-value fields; translated labels are metadataDefault org language
SAP S/4HANAText tables (e.g., T001T)$expand=to_Text or language navSeparate text table per entityLogon language, then EN
Oracle ERP CloudMLS on seeded fieldsAccept-Language headerSeparate translation table per MLS entityBase language
NetSuiteMulti-Language feature (field-level)SOAP: language headerLanguage-specific columns on recordDefault subsidiary language [src4]
D365 F&OLabel translations; TranslationHelper for dataAccept-Language header for enum labelsMetadata store for labels; custom for dataSystem language [src7]
WorkdayBuilt-in multi-languageAccept-Language headerWorkday-managed storeTenant language
AcumaticaLocale-specific attributes (limited)Locale setting on authPrimarily UI labelsSystem locale
Business CentralTranslation files (.xlf)Accept-Language for UI labelsApp resource files; data single-languageSystem language

Character Encoding & String Limits

SystemEncodingMax String LengthMax Long TextUnicodeSpecial Character Gotchas
SalesforceUTF-8255 (Text)131,072 chars (Long Text Area)Full (incl. 4-byte emoji)Escape ' in SOQL; BOM in CSV causes issues
SAP S/4HANAUTF-8 (OData)CHAR: 1-1333 bytesSTRING: up to 2GBFull (OData); legacy codepage dependentDouble ' in ABAP; URL-encode $filter
Oracle ERP CloudUTF-8240 (flexfields typical)CLOB-backed (no practical limit)FullEscape backslashes and quotes in JSON
NetSuiteUTF-8300 (Free-Form Text)1,000,000 chars (Long Text)FullDouble ' in SuiteQL; UTF-8 BOM recommended for CSV
D365 F&OUTF-16 (internal); UTF-8 (OData)EDT-defined (20-100 typical)Memo: very large (theoretical)FullDouble ' in OData $filter
WorkdayUTF-8Field-dependentRich text supportedFullEscape XML entities in SOAP
AcumaticaUTF-8Default 256 per DACNote field: large textFullStandard JSON escaping
Business CentralUTF-8Text: 250; Code: 20BigText (internal)FullAL filter syntax differs from OData

Data Mapping

Cross-System Date/Time Transformation Rules

Source SystemTarget SystemTransformation RequiredCode Pattern
Salesforce (UTC)NetSuite (PST default)Convert UTC to target user timezonenew Date(sf_datetime).toLocaleString('en-US', {timeZone: 'America/Los_Angeles'})
SAP (smallest unit)Salesforce (decimal)Divide by 10^(TCURX decimals)sf_amount = sap_amount / Math.pow(10, tcurx_decimals)
Salesforce (UTC)D365 F&O (UTC)No conversion neededDirect mapping
NetSuite (PST)SAP (UTC)Convert from PST/PDT offset to UTCParse offset; convert to UTC
D365 (integer enum)Salesforce (string picklist)Map integer to string labelLookup table: {0: 'No', 1: 'Yes'}
Salesforce (18-char ID)NetSuite (externalId)Store SF 18-char ID as externalIdDirect string mapping
SAP (text table)Salesforce (single value)Select text for target localeFilter to_Text by Language eq 'EN'
Oracle (DFF segment)D365 (custom field)Map Attribute1..N to named fieldStatic mapping per DFF context

Data Type Gotchas

Error Handling & Failure Points

Common Data Type Errors

Error ScenarioSalesforceSAP S/4HANAOracle ERP CloudNetSuiteD365 F&O
Invalid date formatINVALID_TYPE_ON_FIELDOData parse error (400)JBO-27024INVALID_DATE_FORMATOData 400
Currency mismatchFIELD_INTEGRITY_EXCEPTIONCX_BAPI_ERRORINVALID_CURRENCYINVALID_CURRENCYCurrencyCode validation error
Picklist/enum invalidINVALID_OR_NULL_FOR_RESTRICTED_PICKLISTCheck table violation (400)Lookup validation failureSSS_INVALID_TYPE_ARGEnum value out of range
Null on required fieldREQUIRED_FIELD_MISSINGmandatory field missingJBO-27014SSS_MISSING_REQD_ARGUMENTOData required field error
String too longSTRING_TOO_LONGOData payload errorORA-12899FIELD_VALIDATIONValue exceeds max length
Encoding issueBulk CSV: INVALID_CONTENT_TYPE if BOMCodepage conversion errorUnicode decode errorSuiteQL parse errorOData parse error

Failure Points in Production

Anti-Patterns

Wrong: Assuming all ERPs use UTC for datetime fields

// BAD — Treating NetSuite datetime as UTC
const order_date = new Date(netsuite_record.tranDate); // "2026-03-15T00:00:00.000-08:00"
const utc_date = order_date.toISOString(); // Wrong if not parsing offset correctly
// Sends to Salesforce as 2026-03-15T08:00:00Z — 8 hours off!

Correct: Parse timezone offset from each system's format

// GOOD — Respect the timezone offset in NetSuite's response
const ns_datetime = "2026-03-15T00:00:00.000-08:00";
const parsed = new Date(ns_datetime); // JS Date correctly handles offset
const utc_iso = parsed.toISOString(); // "2026-03-15T08:00:00.000Z" — correct UTC
// For Salesforce, send the UTC value directly

Wrong: Mapping SAP amounts directly without TCURX conversion

# BAD — Direct mapping of SAP amount to Salesforce
salesforce_amount = sap_record['NetAmount']  # 10050 (SAP smallest unit for USD)
# Salesforce receives 10050.00 instead of 100.50 — 100x overcharge!

Correct: Apply TCURX-based currency conversion

# GOOD — Convert SAP smallest-unit amount using TCURX decimal places
TCURX_DECIMALS = {'USD': 2, 'EUR': 2, 'JPY': 0, 'KWD': 3, 'BHD': 3}
currency = sap_record['TransactionCurrency']
decimals = TCURX_DECIMALS.get(currency, 2)  # Default 2 if not in lookup
salesforce_amount = sap_record['NetAmount'] / (10 ** decimals)
# USD: 10050 / 100 = 100.50 (correct)
# JPY: 10050 / 1 = 10050 (correct — no decimals for yen)

Wrong: Writing D365 enums as integers without checking entity behavior

// BAD — Assuming all D365 entities accept integer enum values
const payload = { "IsActive": 1 }; // NoYes.Yes = 1
// Some OData entities reject this and require the string form

Correct: Use the OData string label format for D365 enum writes

// GOOD — Use string label format; test each entity individually
const payload = { "IsActive": "Yes" }; // OData exposes as string
// For entities requiring full qualified form:
// "IsActive": "Microsoft.Dynamics.DataEntities.NoYes'Yes'"

Common Pitfalls

Integration Pattern Decision Tree

START — Data type mismatch between Source ERP and Target ERP
├── Date/DateTime issue?
│   ├── Both systems UTC? → Direct mapping
│   ├── NetSuite involved? → Convert from user-timezone to UTC first
│   ├── Date-only? → Use YYYY-MM-DD; strip time component
│   └── Full datetime? → Preserve with timezone conversion
├── Currency amount issue?
│   ├── SAP source? → Lookup TCURX decimals; divide by 10^decimals
│   ├── Zero-decimal currency (JPY, KRW)? → Verify both systems handle correctly
│   └── Multi-currency? → Map currency code alongside amount
├── Picklist/Enum mismatch?
│   ├── String → Integer (D365)? → Build lookup table
│   └── Multi-select? → Check delimiter (SF=semicolon, NS=pipe, Acumatica=comma)
├── Custom field issue?
│   ├── Oracle target? → Map DFF segments; set context first
│   ├── Acumatica target? → Use 'Usr' prefix exactly
│   ├── Business Central? → Verify field on API page definition
│   └── Others → Use standard custom field API (SF __c, NS cust*, SAP YY1_)
└── Null handling?
    ├── Target rejects NULL? → Map to default value
    └── Clear a field?
        ├── Salesforce → null in JSON or fieldsToNull (SOAP)
        ├── NetSuite → null (REST) or nullFieldList (SOAP)
        └── D365 → null (check if nullable first)

Diagnostic Commands

# === SALESFORCE: Inspect field metadata ===
curl "https://{instance}.my.salesforce.com/services/data/v62.0/sobjects/Account/describe" \
  -H "Authorization: Bearer ${SF_TOKEN}" | jq '.fields[] | {name, type, length, precision, scale, picklistValues}'

# === SAP S/4HANA: Check OData $metadata for field types ===
curl "https://{tenant}.s4hana.cloud.sap/sap/opu/odata4/sap/api_business_partner/srvd_a2x/sap/businesspartner/0001/\$metadata" \
  -H "Authorization: Bearer ${SAP_TOKEN}"
# Look for: Edm.Decimal (amounts), Edm.DateTimeOffset (datetimes), sap:unit annotation

# === ORACLE ERP CLOUD: Check entity fields ===
curl "https://{instance}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/latest/invoices/describe" \
  -H "Authorization: Bearer ${ORACLE_TOKEN}" | jq '.Resources[].attributes[] | {name, type}'

# === NETSUITE: Inspect record metadata ===
curl "https://{account_id}.suitetalk.api.netsuite.com/services/rest/record/v1/metadata-catalog/customer" \
  -H "Authorization: OAuth ..." | jq '.properties | to_entries[] | {name: .key, type: .value.type}'

# === DYNAMICS 365 F&O: Check entity metadata for enums ===
curl "https://{env}.operations.dynamics.com/data/\$metadata" \
  -H "Authorization: Bearer ${D365_TOKEN}" -o metadata.xml
# Parse XML for EnumType definitions and Property types

# === CURRENCY TEST: Validate decimal handling ===
# Create test record with amount 12345 in JPY, USD, and BHD
# Verify stored value in both source and target systems

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
Building field-level transformation logic between ERPsNeed rate limits or API surface comparisonERP REST API Comparison
Debugging data type mismatch errorsNeed a complete integration playbook for specific pairSystem-specific integration playbooks
Designing a canonical data model for multi-ERP hubNeed middleware/iPaaS selectioniPaaS comparison card
Validating currency handling before go-liveNeed a single-system deep-diveSingle-system API capability cards
Training developers on cross-platform type differencesNeed ERP selection guidanceERP selection cards

Cross-System Comparison

CapabilitySalesforceSAP S/4HANAOracle ERP CloudNetSuiteD365 F&OWorkdayAcumaticaBusiness Central
Date formatISO 8601 UTCISO 8601 UTC (V4)ISO 8601 w/ offsetISO 8601 w/ PSTISO 8601 UTCISO 8601 w/ offsetISO 8601 UTCISO 8601 UTC
Currency storageDecimalSmallest unitDecimalDecimalDecimalDecimalDecimalDecimal
Currency precisionConfigurableTCURX tableConfigurable0 or 2 onlyConfigurablePer currencyConfigurableConfigurable
Custom field accessFull (describe)If publishedLimited (DFF)Full (metadata)Via data entityLimited (RaaS)Full (REST)Publisher ext
Enum typeStringString (domain)String (lookup)String or IDIntegerReference IDStringInteger
Multi-languageMetadata onlyText tablesMLSField-levelCustom tablesBuilt-inLimitedLabel files
Null handlingNULL + fieldsToNullInitial valuesNULL explicitNULL + nullFieldListNULL or 0Omit = unchangedNULL explicitNULL or empty
UnicodeFull (UTF-8)Full (UTF-8 OData)Full (UTF-8)Full (UTF-8)Full (UTF-16)Full (UTF-8)Full (UTF-8)Full (UTF-8)
ID format18-char alphanum10-digit numericNumericNumeric (internalId)AlphanumericUUID (WID)IntegerUUID (systemId)
Booleantrue/falsetrue/falsetrue/falsetrue/false or T/FNoYes (0/1)true/falsetrue/falsetrue/false

Important Caveats

Related Units