This guide covers how to integrate TGM Manager with enterprise ERP systems like SAP, Microsoft Dynamics, and Oracle.
Table of Contents¶
- Overview
- Supported ERP Systems
- Architecture
- Configuration
- API Reference
- Entity Mappings
- Sync Operations
- Webhooks
- Troubleshooting
Overview¶
TGM Manager provides bi-directional synchronization with major ERP systems, allowing you to:
- Import data from ERP: Sync customers, equipment, work orders from your ERP into TGM
- Export data to ERP: Push TGM records (inspections, work orders, failures) back to your ERP
- Real-time sync: Configure webhooks for instant synchronization
- Scheduled sync: Automate full and incremental syncs on a schedule
Key Features¶
- Support for SAP, Microsoft Dynamics 365, and Oracle ERP systems
- Configurable field-level mappings
- Conflict resolution strategies
- Audit trail for all sync operations
- Rate limiting and retry mechanisms
- Secure credential storage (encrypted)
Supported ERP Systems¶
SAP¶
| System | Description | Authentication |
|---|---|---|
| SAP S/4HANA | Latest SAP ERP suite | OAuth 2.0, Basic Auth |
| SAP ECC | SAP ERP Central Component | Basic Auth, Certificate |
| SAP Business One | SMB ERP solution | API Key, Basic Auth |
Microsoft Dynamics¶
| System | Description | Authentication |
|---|---|---|
| Dynamics 365 Finance & Operations | Enterprise ERP | OAuth 2.0 (Azure AD) |
| Dynamics 365 Business Central | SMB ERP | OAuth 2.0 (Azure AD) |
| Dynamics NAV | On-premise NAV | Basic Auth, NTLM |
| Dynamics AX | Legacy Dynamics AX | Basic Auth |
Oracle¶
| System | Description | Authentication |
|---|---|---|
| Oracle Cloud ERP | Oracle Fusion Cloud | OAuth 2.0, OCI |
| Oracle E-Business Suite | On-premise EBS | Basic Auth |
| Oracle NetSuite | Cloud ERP | Token-based, OAuth 2.0 |
| Oracle JD Edwards | JDE EnterpriseOne | Basic Auth |
Architecture¶
┌─────────────────────────────────────────────────────────────┐
│ TGM Manager │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Admin API │ │ Webhook │ │ Scheduled Sync │ │
│ │ Endpoints │ │ Receiver │ │ Service │ │
│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │
│ │ │ │ │
│ └────────────────┼─────────────────────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ ERP Sync Engine │ │
│ │ - Connection Mgmt │ │
│ │ - Entity Mapping │ │
│ │ - Transformation │ │
│ └─────────┬─────────┘ │
│ │ │
│ ┌────────────────┼────────────────┐ │
│ │ │ │ │
│ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │
│ │ SAP │ │Dynamics │ │ Oracle │ │
│ │Connector│ │Connector│ │Connector│ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
└─────────┼───────────────┼───────────────┼───────────────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ SAP │ │Dynamics │ │ Oracle │
│ System │ │ 365 │ │ Cloud │
└─────────┘ └─────────┘ └─────────┘
Components¶
- Admin API: REST endpoints for managing connections and mappings
- Webhook Receiver: Handles real-time events from ERP systems
- Scheduled Sync Service: Runs automated full/incremental syncs
- ERP Sync Engine: Core sync logic, transformation, conflict resolution
- ERP Connectors: Protocol-specific adapters for each ERP type
Configuration¶
Step 1: Create an ERP Connection¶
Admin UI or API:
curl -X POST http://localhost:1337/api/admin/erp/connections \
-H "Authorization: Bearer $JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Production SAP",
"description": "Main SAP S/4HANA system",
"erpType": "SAP_S4HANA",
"authType": "OAUTH2",
"baseUrl": "https://my-sap-system.example.com/sap/opu/odata4/sap",
"clientId": "your-client-id",
"clientSecret": "your-client-secret",
"sapClient": "100",
"sapSystemId": "PRD",
"sapLanguage": "EN",
"enabled": true,
"syncEnabled": true,
"syncDirection": "BIDIRECTIONAL",
"syncIntervalMinutes": 60,
"webhookEnabled": true
}'
Step 2: Configure Entity Mappings¶
Map TGM entities to ERP entities:
curl -X POST http://localhost:1337/api/admin/erp/connections/1/mappings \
-H "Authorization: Bearer $JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tgmEntityType": "UNIT",
"erpEntityName": "Equipment",
"syncEnabled": true,
"syncDirection": "BIDIRECTIONAL",
"conflictResolution": "ERP_WINS",
"batchSize": 100,
"fieldMappings": [
{
"tgmField": "name",
"erpField": "Description",
"fieldType": "STRING",
"syncDirection": "BIDIRECTIONAL",
"required": true
},
{
"tgmField": "serialNumber",
"erpField": "SerialNumber",
"fieldType": "STRING",
"syncDirection": "INBOUND",
"isKeyField": true
},
{
"tgmField": "manufacturer",
"erpField": "ManufacturerName",
"fieldType": "STRING",
"syncDirection": "INBOUND"
}
]
}'
Step 3: Test the Connection¶
curl -X POST http://localhost:1337/api/admin/erp/connections/1/test \
-H "Authorization: Bearer $JWT_TOKEN"
Response:
{
"connectionId": 1,
"connectionName": "Production SAP",
"erpType": "SAP_S4HANA",
"status": "success",
"message": "Successfully connected to SAP S/4HANA",
"testedAt": "2024-01-15T10:30:00"
}
API Reference¶
Connection Endpoints¶
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/erp/connections |
List all connections |
| GET | /api/admin/erp/connections/{id} |
Get connection details |
| POST | /api/admin/erp/connections |
Create new connection |
| PUT | /api/admin/erp/connections/{id} |
Update connection |
| DELETE | /api/admin/erp/connections/{id} |
Delete connection |
| POST | /api/admin/erp/connections/{id}/test |
Test connection |
| POST | /api/admin/erp/connections/{id}/enable |
Enable connection |
| POST | /api/admin/erp/connections/{id}/disable |
Disable connection |
Entity Mapping Endpoints¶
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/erp/connections/{id}/mappings |
List entity mappings |
| GET | /api/admin/erp/mappings/{id} |
Get mapping details |
| POST | /api/admin/erp/connections/{id}/mappings |
Create mapping |
| PUT | /api/admin/erp/mappings/{id} |
Update mapping |
| DELETE | /api/admin/erp/mappings/{id} |
Delete mapping |
Sync Endpoints¶
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/erp/connections/{id}/sync-jobs |
List sync jobs |
| GET | /api/admin/erp/sync-jobs/{id} |
Get sync job details |
| GET | /api/admin/erp/sync-jobs/{id}/detail |
Get detailed job info with error logs |
| GET | /api/admin/erp/sync-jobs/running |
Get all running jobs |
| POST | /api/admin/erp/connections/{id}/sync/full |
Trigger full sync |
| POST | /api/admin/erp/connections/{id}/sync/incremental |
Trigger incremental sync |
| POST | /api/admin/erp/connections/{id}/sync/entity |
Sync single entity |
| POST | /api/admin/erp/sync-jobs/{id}/cancel |
Cancel running sync |
| POST | /api/admin/erp/sync-jobs/{id}/retry |
Retry failed job |
| GET | /api/admin/erp/connections/{id}/sync/statistics |
Get sync statistics |
Schedule Configuration Endpoints¶
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/erp/connections/{id}/schedule |
Get schedule configuration |
| PUT | /api/admin/erp/connections/{id}/schedule |
Update schedule configuration |
| POST | /api/admin/erp/connections/{id}/schedule/enable |
Enable scheduled sync |
| POST | /api/admin/erp/connections/{id}/schedule/disable |
Disable scheduled sync |
Dashboard Endpoint¶
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/erp/dashboard |
Get sync dashboard with statistics |
Reference Data Endpoints¶
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/admin/erp/supported-erp-types |
List supported ERP types |
| GET | /api/admin/erp/syncable-entities |
List syncable TGM entities |
Entity Mappings¶
Syncable TGM Entities¶
| Entity Type | Description | Typical ERP Mapping |
|---|---|---|
COMPANY |
Customer/Company records | Customer, Business Partner |
LOCATION |
Site locations | Plant, Location, Address |
UNIT |
Equipment/Assets | Equipment, Fixed Asset |
COMPONENT |
Equipment components | BOM Item, Material |
USER |
TGM Users | Employee, HR Record |
WORK_ORDER |
Work orders | Service Order, PM Order |
INSPECTION |
Inspection records | Measurement Document |
FAILURE |
Failure/Breakdown records | Notification, Incident |
INVENTORY |
Inventory items | Material, Stock Item |
INVOICE |
Billing documents | Billing Document, Invoice |
Field Mapping Types¶
| Type | Description |
|---|---|
STRING |
Text fields |
INTEGER |
Whole numbers |
DECIMAL |
Decimal numbers |
BOOLEAN |
True/false values |
DATE |
Date only |
DATETIME |
Date and time |
ENUM |
Enumerated values (requires mapping) |
REFERENCE |
Foreign key reference |
JSON |
Complex nested data |
Sync Directions¶
| Direction | Description |
|---|---|
INBOUND |
ERP → TGM only |
OUTBOUND |
TGM → ERP only |
BIDIRECTIONAL |
Both directions |
Conflict Resolution Strategies¶
| Strategy | Description |
|---|---|
TGM_WINS |
TGM data overwrites ERP data |
ERP_WINS |
ERP data overwrites TGM data |
NEWEST_WINS |
Most recently modified record wins |
MANUAL |
Flag for manual resolution |
MERGE |
Attempt to merge non-conflicting fields |
Schedule Configuration¶
Get Current Schedule¶
curl http://localhost:1337/api/admin/erp/connections/1/schedule \
-H "Authorization: Bearer $JWT_TOKEN"
Response:
{
"connectionId": 1,
"connectionName": "Production SAP",
"syncEnabled": true,
"syncIntervalMinutes": 60,
"syncIntervalFormatted": "1 hour",
"webhookEnabled": true,
"webhookUrl": "/api/webhooks/erp/1",
"maxRetries": 3,
"retryDelaySeconds": 30,
"rateLimitRequests": 100,
"rateLimitPeriodSeconds": 60,
"lastFullSync": "2024-01-14T00:00:00",
"lastIncrementalSync": "2024-01-15T09:00:00",
"nextScheduledSync": "2024-01-15T10:00:00",
"nextSyncIn": "30 minutes",
"isScheduleActive": true,
"activeJobsCount": 0
}
Update Schedule Configuration¶
curl -X PUT http://localhost:1337/api/admin/erp/connections/1/schedule \
-H "Authorization: Bearer $JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"syncEnabled": true,
"syncIntervalMinutes": 30,
"webhookEnabled": true,
"maxRetries": 5,
"retryDelaySeconds": 60,
"rateLimitRequests": 50,
"rateLimitPeriodSeconds": 60
}'
Enable/Disable Schedule¶
Enable with 30-minute interval:
curl -X POST "http://localhost:1337/api/admin/erp/connections/1/schedule/enable?intervalMinutes=30" \
-H "Authorization: Bearer $JWT_TOKEN"
Disable schedule:
curl -X POST http://localhost:1337/api/admin/erp/connections/1/schedule/disable \
-H "Authorization: Bearer $JWT_TOKEN"
Sync Operations¶
Full Sync¶
A full sync compares all records between TGM and the ERP:
curl -X POST http://localhost:1337/api/admin/erp/connections/1/sync/full \
-H "Authorization: Bearer $JWT_TOKEN"
Response:
{
"id": 123,
"erpConnectionId": 1,
"erpConnectionName": "Production SAP",
"jobType": "FULL",
"direction": "BIDIRECTIONAL",
"status": "RUNNING",
"totalRecords": 1500,
"processedRecords": 0,
"startedAt": "2024-01-15T10:30:00",
"createdAt": "2024-01-15T10:30:00"
}
Incremental Sync¶
An incremental sync only processes records changed since the last sync:
curl -X POST http://localhost:1337/api/admin/erp/connections/1/sync/incremental \
-H "Authorization: Bearer $JWT_TOKEN"
Single Record Sync¶
Sync a specific record immediately:
curl -X POST "http://localhost:1337/api/admin/erp/connections/1/sync/entity?entityType=UNIT&recordId=456&direction=OUTBOUND" \
-H "Authorization: Bearer $JWT_TOKEN"
Dashboard Overview¶
Get a comprehensive dashboard of all ERP sync operations:
curl http://localhost:1337/api/admin/erp/dashboard \
-H "Authorization: Bearer $JWT_TOKEN"
Response:
{
"totalConnections": 3,
"enabledConnections": 2,
"connectedConnections": 2,
"errorConnections": 0,
"runningJobsCount": 1,
"runningJobs": [
{
"jobId": 125,
"connectionId": 1,
"connectionName": "Production SAP",
"jobType": "INCREMENTAL",
"progressPercent": 45,
"processedRecords": 450,
"totalRecords": 1000,
"startedAt": "2024-01-15T10:30:00",
"runningFor": "5 minutes"
}
],
"recentFailedJobs": [
{
"jobId": 120,
"connectionId": 2,
"connectionName": "Dynamics 365",
"jobType": "FULL",
"errorMessage": "Authentication failed",
"errorCount": 15,
"failedAt": "2024-01-15T08:00:00",
"isRetryable": true
}
],
"connectionHealth": [
{
"connectionId": 1,
"connectionName": "Production SAP",
"erpType": "SAP_S4HANA",
"connectionStatus": "CONNECTED",
"lastSuccessfulSync": "2024-01-15T09:00:00",
"recentErrorCount": 0,
"healthStatus": "HEALTHY"
}
],
"upcomingSyncs": [
{
"connectionId": 1,
"connectionName": "Production SAP",
"syncType": "INCREMENTAL",
"nextSyncAt": "2024-01-15T11:00:00",
"timeUntilSync": "25 minutes"
}
],
"generatedAt": "2024-01-15T10:35:00"
}
Get All Running Jobs¶
curl http://localhost:1337/api/admin/erp/sync-jobs/running \
-H "Authorization: Bearer $JWT_TOKEN"
Monitoring Sync Jobs¶
Check sync job status:
curl http://localhost:1337/api/admin/erp/sync-jobs/123 \
-H "Authorization: Bearer $JWT_TOKEN"
Response:
{
"id": 123,
"erpConnectionId": 1,
"erpConnectionName": "Production SAP",
"jobType": "FULL",
"direction": "BIDIRECTIONAL",
"status": "COMPLETED",
"totalRecords": 1500,
"processedRecords": 1500,
"successCount": 1485,
"errorCount": 15,
"skipCount": 0,
"progressPercent": 100,
"startedAt": "2024-01-15T10:30:00",
"completedAt": "2024-01-15T10:45:30",
"durationMs": 930000,
"durationFormatted": "15m 30s"
}
Get Detailed Job Info with Error Logs¶
For failed or completed jobs with errors, get detailed error information:
curl http://localhost:1337/api/admin/erp/sync-jobs/123/detail \
-H "Authorization: Bearer $JWT_TOKEN"
Response:
{
"id": 123,
"erpConnectionId": 1,
"erpConnectionName": "Production SAP",
"jobType": "FULL",
"status": "COMPLETED",
"totalRecords": 1500,
"processedRecords": 1500,
"successCount": 1485,
"errorCount": 15,
"errorLogs": [
{
"recordIndex": 0,
"entityType": "UNIT",
"tgmRecordId": 456,
"erpRecordId": "EQ-12345",
"errorCode": "VALIDATION_ERROR",
"errorMessage": "Required field 'SerialNumber' is missing",
"isRetryable": true
},
{
"recordIndex": 1,
"entityType": "UNIT",
"tgmRecordId": 789,
"erpRecordId": null,
"errorCode": "NOT_FOUND",
"errorMessage": "Equipment not found in ERP",
"isRetryable": false
}
],
"durationFormatted": "15m 30s"
}
Retry a Failed Job¶
If a sync job failed, you can retry it:
curl -X POST http://localhost:1337/api/admin/erp/sync-jobs/123/retry \
-H "Authorization: Bearer $JWT_TOKEN"
This creates a new sync job based on the failed job's configuration.
Webhooks¶
Overview¶
Configure webhooks to receive real-time notifications from your ERP when data changes.
Webhook URL¶
When you enable webhooks on a connection, TGM provides a webhook URL:
https://your-tgm-server.com/api/webhooks/erp/{connectionId}
For ERP-specific webhooks:
- SAP: https://your-tgm-server.com/api/webhooks/erp/sap/{connectionId}
- Dynamics: https://your-tgm-server.com/api/webhooks/erp/dynamics/{connectionId}
- Oracle: https://your-tgm-server.com/api/webhooks/erp/oracle/{connectionId}
Webhook Security¶
TGM validates webhooks using:
- Webhook Secret: A shared secret in the
X-Webhook-Secretheader - HMAC Signature: Validates payload integrity via
X-Webhook-Signatureheader
The webhook secret is generated when you enable webhooks and can be retrieved from the connection settings.
Configuring SAP Webhooks¶
- In SAP, go to Event Mesh or Integration Suite
- Create an outbound webhook subscription
- Configure the TGM webhook URL
- Add the webhook secret header
Configuring Dynamics Webhooks¶
- In Dynamics 365, go to Settings > Service Endpoints
- Create a new webhook endpoint
- Enter the TGM webhook URL
- Configure authentication (validation token supported)
Configuring Oracle Webhooks¶
- In Oracle Integration Cloud, configure an outbound connection
- Set the webhook URL
- Configure the signature header for payload verification
ERP-Specific Configuration¶
SAP S/4HANA Configuration¶
{
"name": "SAP S/4HANA Production",
"erpType": "SAP_S4HANA",
"authType": "OAUTH2",
"baseUrl": "https://my-s4hana.example.com/sap/opu/odata4/sap",
"clientId": "your-oauth-client-id",
"clientSecret": "your-oauth-client-secret",
"sapClient": "100",
"sapSystemId": "PRD",
"sapInstanceNumber": "00",
"sapLanguage": "EN",
"connectionSettings": {
"oauthTokenUrl": "https://my-s4hana.example.com/sap/bc/sec/oauth2/token"
}
}
Microsoft Dynamics 365 Business Central¶
{
"name": "Dynamics 365 BC",
"erpType": "DYNAMICS_365_BC",
"authType": "OAUTH2",
"dynamicsTenantId": "your-azure-tenant-id",
"dynamicsEnvironment": "production",
"dynamicsCompanyId": "your-company-guid",
"clientId": "your-azure-app-client-id",
"clientSecret": "your-azure-app-client-secret",
"connectionSettings": {
"apiVersion": "v2.0"
}
}
Microsoft Dynamics 365 Finance & Operations¶
{
"name": "Dynamics 365 F&O",
"erpType": "DYNAMICS_365_FO",
"authType": "OAUTH2",
"dynamicsTenantId": "your-azure-tenant-id",
"dynamicsEnvironment": "your-environment-name",
"clientId": "your-azure-app-client-id",
"clientSecret": "your-azure-app-client-secret",
"connectionSettings": {
"resource": "https://your-environment.operations.dynamics.com"
}
}
Oracle Cloud ERP¶
{
"name": "Oracle Cloud ERP",
"erpType": "ORACLE_CLOUD",
"authType": "OAUTH2",
"oracleInstanceUrl": "https://your-instance.fa.us2.oraclecloud.com",
"oracleIdentityDomain": "your-identity-domain",
"clientId": "your-oracle-client-id",
"clientSecret": "your-oracle-client-secret",
"connectionSettings": {
"apiVersion": "v1"
}
}
Oracle NetSuite¶
{
"name": "NetSuite Production",
"erpType": "ORACLE_NETSUITE",
"authType": "OAUTH2",
"baseUrl": "https://your-account-id.suitetalk.api.netsuite.com",
"connectionSettings": {
"accountId": "your-account-id",
"consumerKey": "your-consumer-key",
"consumerSecret": "your-consumer-secret",
"tokenId": "your-token-id",
"tokenSecret": "your-token-secret"
}
}
Troubleshooting¶
Common Issues¶
Connection Test Fails¶
- Check credentials: Verify client ID, secret, and other auth settings
- Check network: Ensure TGM server can reach the ERP endpoint
- Check permissions: Verify the ERP user/app has required API access
Sync Job Stuck in Running State¶
Jobs running longer than 2 hours are automatically marked as stale. You can:
- Cancel the job manually:
POST /api/admin/erp/sync-jobs/{id}/cancel - Check for locks in the ERP system
- Review error logs for API timeouts
Webhook Not Received¶
- Verify webhook URL is accessible from the ERP
- Check webhook secret matches
- Review ERP webhook delivery logs
- Check TGM application logs for incoming requests
Data Mismatch After Sync¶
- Review field mappings for incorrect transformations
- Check conflict resolution strategy
- Verify sync direction settings
- Review the sync job error details
Viewing Logs¶
Application logs include sync details:
grep "ERP" logs/application.log
grep "ErpSync" logs/application.log
Sync Statistics¶
Get detailed sync statistics:
curl http://localhost:1337/api/admin/erp/connections/1/sync/statistics \
-H "Authorization: Bearer $JWT_TOKEN"
Response:
{
"connectionId": 1,
"connectionName": "Production SAP",
"lastFullSync": "2024-01-14T00:00:00",
"lastIncrementalSync": "2024-01-15T09:00:00",
"syncedRecordsByEntity": {
"UNIT": 1250,
"WORK_ORDER": 890,
"COMPANY": 45
},
"recentFailures": 3,
"lastJobStatus": "COMPLETED",
"lastJobSuccessCount": 150,
"lastJobErrorCount": 2
}
Security Considerations¶
- Credentials are encrypted at rest using AES-256
- Use OAuth2 where possible instead of basic auth
- Rotate secrets periodically
- Limit API permissions in the ERP to only required operations
- Enable audit logging for all sync operations
- Use webhooks over HTTPS only
- Validate webhook signatures to prevent spoofing
Best Practices¶
- Start with INBOUND sync to import data from ERP first
- Test with a subset before running full syncs
- Configure appropriate batch sizes based on ERP API limits
- Set up monitoring for failed sync jobs
- Use incremental syncs for regular synchronization
- Schedule full syncs during off-peak hours
- Document field mappings for maintenance
- Review conflict resolution strategy for each entity type
Support¶
For additional help:
- Review the API documentation at /swagger-ui.html
- Check application logs for detailed error messages
- Contact your ERP administrator for API access issues