ERP Integration in Jules
How Jules synchronizes data with external ERP systems — fields, entities, sync patterns, and implementation guide.
ERP Integration in Jules
Developer documentation — Jules supports bidirectional synchronization with external ERP systems for contracts, operations, invoices, allocations, and master data.
Table of Contents
- Overview
- ERP Fields on Entities
- Which Entities Support ERP Sync
- Sync Mutations
- Contract Sync
- Invoice Sync
- Container-Level Sync
- User-Company ERP Sync
- Adding ERP Sync to a New Entity
- Key Design Decisions
Overview
Jules is designed to coexist with customer ERP systems (SAP, Navision, Sage, custom ERPs). The integration model is:
- Jules → ERP: mutations trigger data push to the ERP (operations, invoices, allocations, master data)
- ERP → Jules: the ERP's internal ID and reference values are stored back on the Jules entity via
erpId/erpValue
There is no universal ERP connector — each organization configures its own ERP integration at the infrastructure level. Jules exposes the sync hooks (fields + mutations); the actual HTTP/webhook/file-based transport to the ERP is handled by the integration layer.
ERP Fields on Entities
Three fields appear on all ERP-syncable entities:
| Field | Type | Description |
|---|---|---|
erpId | String? | The entity's primary identifier in the external ERP (e.g., SAP document number) |
erpValue | String? | A secondary ERP reference value (e.g., ERP internal key, sequential number) |
erpCompanyId | String? | The ERP's identifier for the counterparty company on this transaction |
All three are nullable. Null means the entity has not been synced to the ERP yet.
Which Entities Support ERP Sync
| Entity | erpId | erpValue | erpCompanyId | Notes |
|---|---|---|---|---|
| Operation | ✅ | ✅ | ✅ | Purchase and sale operations |
| OperationQuality | ✅ | — | — | Per quality line on an operation |
| Contract | ✅ | ✅ | ✅ | Bidirectional sync supported |
| ContractStream | ✅ | — | — | Per quality stream on a contract |
| Allocation | ✅ | ✅ | — | Per allocation |
| Invoice | ✅ | ✅ | ✅ | Buy/sell/provider invoices |
| InvoiceLine | ✅ | — | — | Per invoice line item |
| ContainerInvoicingLine | ✅ | — | — | Per container cost element |
| Company | ✅ | ✅ | — | Counterparty master data |
| Site | ✅ | — | ✅ | Site master data |
| Contact | ✅ | — | — | Contact master data |
| Booking | ✅ | ✅ | — | Freight bookings |
| Shipment | ✅ | — | — | Shipments |
Sync Mutations
Each entity exposes a dedicated sync mutation that can be called to push data to the ERP:
| Entity | Sync mutation |
|---|---|
| Allocation | synchronizeAllocationToErp |
| Booking | syncBookingToErp |
| Contract | synchronizeContractToErp / updateContractErp |
| Invoice | synchronizeInvoiceToErp |
| Company | updateCompanyErp / createManyCompaniesErp |
| Site | updateSiteErp |
| Contact | updateContactErp |
| UserToCompany | createManyUsersToCompaniesErp / deleteManyUsersToCompaniesErp |
These mutations typically:
- Validate the entity is in a syncable state (e.g., CONFIRMED status)
- Push data to the ERP via the configured integration
- Store the ERP's response (
erpId,erpValue) back on the entity
Contract Sync
Contract synchronization is the most complete bidirectional integration:
Key points:
- Only
CONFIRMEDcontracts are eligible for ERP sync - Each
ContractStream(quality line) carries its ownerpId - Contract renewal via duplication preserves the original ERP reference as a parent reference
Invoice Sync
Invoice sync is typically the highest-priority integration:
- Invoice sync fires after the invoice reaches
CONFIRMEDstatus - Each
InvoiceLineandContainerInvoicingLinecarries its ownerpIdfor line-level reconciliation - The
erpCompanyIdon the invoice identifies the counterparty in the ERP's chart of accounts
Container-Level Sync
ContainerInvoicingLine has independent ERP sync tracking. This is important for organizations that book costs at the line level in their ERP (common with SAP):
- Each invoicing line (freight, pre-carriage, agent commission, etc.) has its own
erpId - This allows partial sync: some lines may be synced while others are pending
- The sync status of a line is independent of the parent invoice's sync status
User-Company ERP Sync
When an internal user is assigned to manage a counterparty company, this assignment can be synced:
createManyUsersToCompaniesErp— push new user-company assignments to ERPdeleteManyUsersToCompaniesErp— remove assignments from ERP
This is used in organizations where the ERP tracks which account manager is responsible for each customer/supplier.
Adding ERP Sync to a New Entity
To add ERP sync to a new Prisma model:
Step 1 — Add fields to the Prisma schema
model MyNewEntity {
// ... existing fields
erpId String?
erpValue String?
erpCompanyId String?
}
Run prisma migrate to apply the migration.
Step 2 — Expose fields in the GraphQL type
Add erpId, erpValue, erpCompanyId to the GraphQL object type in the entity's .type.ts file.
Step 3 — Add update input
Add optional erpId, erpValue, erpCompanyId to the entity's update input type so the sync response can write back to Jules.
Step 4 — Create the sync mutation
// In the entity's resolver
@Mutation(() => MyNewEntity)
@isAuthenticated()
async synchronizeMyEntityToErp(
@Args('id') id: string,
@Context() ctx: GqlContext,
): Promise<MyNewEntity> {
return this.myEntityService.synchronizeToErp(id, ctx);
}
Step 5 — Implement the service method
The service method should:
- Load the entity
- Validate sync preconditions (status, required fields)
- Call the ERP integration (organization-specific transport layer)
- Store
erpIdanderpValuefrom the ERP response - Return the updated entity
Key Design Decisions
No universal connector
Jules does not ship with a pre-built connector to any specific ERP. The erpId/erpValue fields and sync mutations are the contract surface — the actual transport (REST, SOAP, file exchange, message queue) is configured per organization.
Idempotent sync
Sync mutations are designed to be idempotent. Calling synchronizeAllocationToErp on an already-synced allocation should update the ERP record rather than creating a duplicate.
Status gating
Most sync mutations require the entity to be in a final or confirmed state before syncing. Draft or in-progress entities are not eligible for ERP sync to prevent pushing incomplete data.
Line-level granularity
The ERP sync model goes down to the invoice line and container invoicing line level. This matches the typical ERP requirement for posting individual cost elements to the general ledger.
Last updated today
Built with Documentation.AI