Sync NAV <> HubSpot
1. Grundstruktur des Sync-Services
Das Repository hopsteiner-businesscentral2HubSpot ist ein Express API Service, der als Middleware zwischen NAV (Business Central) und HubSpot fungiert.
Architektur
NAV (Business Central)
│
│ REST API
▼
Express Sync Service
│
│ HubSpot API
▼
HubSpot CRM
Der Service hat zwei Aufgaben:
| Richtung | Beschreibung |
|---|---|
| NAV → HubSpot | Daten aus NAV holen und in HubSpot speichern |
| HubSpot → NAV | Änderungen aus HubSpot über Webhooks zurück nach NAV senden |
2. NAV → HubSpot (Hauptfluss)
Das passiert über diese Routes:
routes.post(`/sync-companies`, handleCustomers);
routes.post(`/sync-salescontracts`, handleSalesContracts);
routes.post(`/sync-msos`, handleMSOs);
routes.post(`/sync-postedinvoices`, handlePostedInvoices);
routes.post(`/sync-swss`, handleSWSs);
routes.post(`/sync-swslines`, handleSWSLines);
routes.post(`/sync-msolines`, handleMSOLines);
routes.post(`/sync-postedinvoicelines`, handlePostedInvoiceLines);
Diese Endpunkte starten jeweils einen Sync-Controller.
Beispiel:
// Customers - Companies(HS)
const handleCustomers = async ({ interval }) => {
try {
const handleDBCustomers = async (interval) => {
let isNextPage = false;
// API filter: ?$top=5&$filter=Last_Modified_Date_Time gt 2023-10-01T20:42:15Z
let formattedDate;
let url;
if (interval === "daily") {
formattedDate = moment()
.utc()
.subtract(2, "days")
.format("YYYY-MM-DDTHH:mm:ss[Z]");
console.log("interval", interval, formattedDate);
url = `${MS_API_URL}/Hubspot_APIs_Customers?$filter=Last_Modified_Date_Time gt ${formattedDate}`;
} else {
console.log("interval", interval);
url = `${MS_API_URL}/Hubspot_APIs_Customers`;
}
...
}
...
}
}
Was das bedeutet:
MS_API_URList die Basis einer Microsoft-/NAV-/Business-Central-APIHubspot_APIs_Customersklingt sehr stark nach einem eigens angelegten API-Endpunkt- der Zusatz
?$filter=...ist typisch OData-Syntax, wie sie bei NAV / Business Central oft verwendet wird - auch
@odata.nextLinkim Response bestätigt, dass das sehr wahrscheinlich ein OData-Webservice ist
Warum das so dafür spricht:
- der Endpoint-Name
Hubspot_APIs_Customerssieht nicht nach Standard-HubSpot aus, sondern nach einer kundenspezifischen NAV/Business-Central API/Page/Webservice - Felder wie
Last_Modified_Date_Time,No,Salesperson_Email,Hubspot_Company_Nowirken wie typischeNAV-/BC-Feldnamen - die Daten werden zuerst aus dieser Microsoft-API gezogen und dann lokal in MongoDB gespeichert (
Customer.findOneAndUpdate(...)) - danach werden sie nach HubSpot synchronisiert
3. Ablauf eines Sync-Prozesses
Der Ablauf ist immer gleich aufgebaut.
- Daten aus NAV API holen
Beispiel (typischer NAV Request):
${MS_API_URL}/Hubspot_APIs_MSO_Lines?$filter=Last_Date_Modified gt ${formattedDate}
Das ist eine Business Central Web API.
- Die API liefert Daten aus Tabellen wie:
| NAV Tabelle | Zweck |
|---|---|
| Vendor | Grower / Company |
| Sales Contract | Verträge |
| MSO | Verkaufsaufträge |
| MSO Lines | Auftragspositionen |
| Posted Invoice | Rechnungen |
| Posted Invoice Lines | Rechnungspositionen |
- Die API liefert JSON.
Beispiel:
{
"Code": "12345",
"Name": "Hop Grower GmbH",
"City": "Mainburg",
"Country": "DE"
}
- Daten lokal speichern (MongoDB)
Die geladenen NAV-Daten werden zunächst in MongoDB gespeichert.
Beispiel:
await MSO.findOneAndUpdate(
{ businessCentralId: mso.Sales_Order_No },
{
businessCentralId: mso.Sales_Order_No,
data: mso,
company: dbCustomer?._id
},
{ new: true, upsert: true }
);
Damit existiert im Sync-Service eine lokale Kopie der NAV-Daten.
Diese Datenbank wird anschließend für den HubSpot-Sync verwendet.
Vorteile:
- Wiederholbare Syncs
- Batch-Verarbeitung
- bessere Fehleranalyse
- Entkopplung von NAV und HubSpot
- Daten transformieren
Im Controller wird das NAV-Format auf HubSpot-Format gemappt.
Beispiel:
NAV Feld HubSpot Feld
---------------------------------------
Code → hop_company_number
Name → name
City → city
Country → country
4. Daten zu HubSpot senden
Danach werden die Daten über die HubSpot API gespeichert.
Typische API Calls:
POST /crm/v3/objects/companies/batch/upsert
POST /crm/v3/objects/contacts/batch/upsert
POST /crm/v3/objects/deals/batch/upsert
Beispiel Payload:
{
"inputs": [
{
"properties": {
"name": "Hop Grower GmbH",
"hop_company_number": "12345"
}
}
]
}
HubSpot speichert das dann in:
| HubSpot Objekt | Daten |
|---|---|
| Companies | Kunden / Grower |
| Contacts | Ansprechpartner |
| Deals | Verträge |
| Custom Objects | MSO, SWS etc |
5. Reihenfolge des Sync
Im Code steht ausdrücklich:
// Follow the API route sequence to maintain association in hubspot.
Warum? Weil HubSpot Relations braucht.
Die Reihenfolge ist:
1 Companies
2 SalesContracts
3 MSOs
4 PostedInvoices
5 SWS
6 SWSLines
7 MSOLines
8 PostedInvoiceLines
Beispiel Relation:
Company
│
└── Sales Contract
│
└── MSO
│
└── MSO Lines
Wenn du zuerst Lines importierst, existiert das Parent-Objekt noch nicht.
Full Sync Endpoint
Dieser Endpoint führt alle Syncs nacheinander aus.
routes.post(`/sync-all`, async (req, res) => {...})
Ablauf:
sync-all
│
├── handleCustomers()
├── handleSalesContracts()
├── handleMSOs()
├── handlePostedInvoices()
├── handleSWSs()
├── handleSWSLines()
├── handleMSOLines()
└── handlePostedInvoiceLines()
Das ist ein Full Import von NAV nach HubSpot.
6. HubSpot → NAV (Webhook)
Dieser Endpoint empfängt Änderungen aus HubSpot.
routes.post(`/webhook`, handleWebhook);
Beispiel: Wenn in HubSpot ein Contract geändert wird:
HubSpot
│
│ webhook
▼
Express Service
│
│ NAV API
▼
Business Central
Das System:
- empfängt den Webhook
- liest die Änderung
- sendet Update zurück an NAV
7. Datenquellen im System
Zusammenfassung.
| System | Rolle |
|---|---|
| NAV / Business Central | Master System |
| Express Sync Service | Integration Layer |
| HubSpot | CRM |
8. Gesamtfluss
Datenfluss NAV => HubSpot:
NAV (Business Central)
│
│ REST API
▼
Express Sync Service
│
│ Mapping
▼
HubSpot API
│
▼
HubSpot CRM
Datenfluss HubSpot => NAV:
HubSpot
│
│ Webhook
▼
Express Service
│
▼
NAV API
9. Wichtig für dein Verständnis
Die Daten werden NICHT direkt von NAV nach HubSpot geschrieben.
Es gibt immer diesen Middleware Service:
NAV → Node Service (Express) → HubSpot
Der Vorteil:
- Daten Mapping
- Filter (z.B. Last_Date_Modified)
- Fehlerhandling
- Logging
- Batch Upload
Kurzfassung:
| Schritt | Beschreibung |
|---|---|
| 1 | Node API Endpoint wird aufgerufen |
| 2 | Controller ruft NAV API auf |
| 3 | NAV Daten werden geladen |
| 4 | Daten werden gemappt |
| 5 | Daten werden über HubSpot API gespeichert |