Contract Data Normalization
Overview
Contract Data Normalization
Bushel’s system contains a large amount of data that is sourced from various upstream systems. This data is often normalized and transformed in microservices to ensure that it is consistent and usable across Bushel’s ecosystem. This section includes information on how Bushel normalizes Contract data to ensure that it is consistent and usable across Bushel’s ecosystem.
Contract Type
Incoming contract type and subtype values from external systems are normalized into a standard representation before they are displayed or stored.
How these values are determined from sourceType and sourceSubtype:
-
Both inputs are trimmed before processing.
-
The service first tries to infer a standard
ContractTypefromsourceTypeusing common aliases. If this succeeds,typeis set andsubtypeis taken fromsourceSubtype. -
If
sourceTypeis not standard, it then tries to infertypefromsourceSubtypeusing the same aliases. When this succeeds,subtypeis taken fromsourceType. -
If neither field matches a standard alias, the service attempts to infer
typefrom extended terms insourceType(for example, certain vendor-specific values that clearly imply a sales or purchase type). When this succeeds,subtypeis taken fromsourceSubtype. -
If a standard type is found and the resulting
subtypeis identical to the type name (ignoring case), the subtype is cleared (set tonull) to avoid redundant labels. -
If no standard type can be determined and both inputs are non-null and equal (ignoring case), the shared value is treated as the
subtype. -
If no standard type can be determined and the inputs are different, the non-blank values are combined into a single
subtypestring joined with ` - ` (for example,"Not - Standard").
The concatType value is then built by joining the normalized type name (if present) and subtype with ` - `, and omitting any blank parts. This label is what the display-format setting uses when rendering contract type in the UI.
Examples:
| sourceType | sourceSubtype | (type, subtype) | concatType |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Normalization attempts to infer the standard type using both the raw type and subtype fields, including common aliases and selected extended terms. When no match is found, the service preserves the original values by combining the non-blank inputs into a single subtype value, as shown above.
Signature Status
Incoming signature status values (sourceSignatureStatus) from external systems are normalized into a standard SignatureStatus value before they are stored and used for display or filtering.
The normalized value is stored as signatureStatus on the contract and is one of:
-
signed -
needs_signature -
no_signature_required -
nullwhen no mapping applies
Normalization follows these rules:
-
If
sourceSignatureStatusis exactly"Signed", it is always mapped toSignatureStatus.signed, even if no tenant configuration is present. -
Otherwise, if there is no tenant configuration or
sourceSignatureStatusis blank, the normalizedsignatureStatusisnull. -
When a tenant configuration exists, the service reads
contractSignatureStatusMappingsJSON on the tenant, which must contain adefaultMappingobject and may contain adatasourceOverridesarray. -
Each mapping object maps a raw status code (for example,
"S","N") to a display string (for example,"Signed","Needs Signature"). Supported display strings are:-
"Signed"→SignatureStatus.signed -
"Needs Signature"→SignatureStatus.needs_signature -
"No Signature Required"→SignatureStatus.no_signature_required
-
Mapping resolution works as follows:
-
If no datasource overrides are defined,
defaultMappingis used for all datasources. -
If
datasourceOverridesis present, the service looks for an entry whosedatasourceIdmatches the contract’s datasource. If found and it contains amappingsobject, that object is used; otherwise,defaultMappingis used as a fallback. -
If the mapping object does not contain an entry for the raw
sourceSignatureStatus, or the mapped display string is not one of the supported values above, the normalizedsignatureStatusisnull.
The original raw value is always preserved separately as sourceSignatureStatus on the contract entity and can be inspected for debugging or support, but UI and filtering should rely on the normalized signatureStatus field.