Erpy for Visma
Erpy for Visma connects Craft Commerce to Visma.net ERP (Financials) through the Visma.net integration API, authenticated with Visma Connect. The add-on is free; it needs Erpy, which is the paid part and owns the sync engine, the identity map, mapping, the queue and the log.
Install
composer require justinholtweb/craft-erpy-visma
php craft plugin/install erpy-visma
Then Erpy → Connections → New connection and pick Visma.net ERP. The add-on has no settings screen of its own; everything lives on the connection.
What it syncs
| Entity | Direction | Delta sync | Page size |
|---|---|---|---|
| Customers | ERP → Commerce | Yes, on lastModifiedDateTime | 200 |
| Products | ERP → Commerce | Yes, on lastModifiedDateTime | 200 |
| Inventory | ERP → Commerce | No | 500 |
| Orders | Commerce → ERP | ||
| Order status | ERP → Commerce | Yes | 200 |
| Shipments | ERP → Commerce | Yes | 200 |
| Invoices | ERP → Commerce | Yes | 200 |
| Credit | ERP → Commerce | No | 200 |
Contract prices are not synced; the base price comes from the item's default price. The connector declares multi-company support: one connection per Visma.net company.
Connecting
Visma.net uses OAuth 2.0 client credentials through Visma Connect. There is no consent screen to click through, but your integration has to be approved for the customer's tenant in the Visma Developer Portal before any of this works.
| Field | What to put there |
|---|---|
| Client ID / Client secret | From your integration in the Visma Developer Portal. |
| Scope | The scopes granted to your integration. Defaults to vismanet_erp_service_api:read vismanet_erp_service_api:create. A read-only installation can drop the create scope, but then it cannot send orders. |
| Company ID | Sent as the ipp-company-id header. |
| Warehouse | The warehouse stock is read from and order lines are raised against. |
| Sales order type | Defaults to SO. |
| Create orders on hold | On by default, so an order can be reviewed before it reaches the warehouse. |
Test connection reads the inventory list:
- 401. The client id and secret, or the integration has not been approved for this customer's tenant.
- 403. The token is valid but lacks the Visma.net ERP scope, or the company id belongs to a tenant this integration was not granted.
- "Yes, but the company has no items". The test passed, but the company is probably the wrong one. See below.
Things to know about Visma.net
A wrong company is a silent failure. Every request is scoped to a company by the
ipp-company-id header. Omit it, or send the wrong one, and the API answers with a perfectly
successful empty list. That is worse than an error, which is why the connection test checks for it.
Delta syncing is two parameters, not one. Visma filters on lastModifiedDateTime only when it
also gets lastModifiedDateTimeCondition. Send the timestamp alone and it returns everything,
which looks like a working delta sync until somebody times it. The connector always sends both.
Paging is by page number. Visma returns no cursor; a short page means the end.
Look-up values change shape. Visma wraps some values in {"value": …, "description": …} and
sends a bare string for the same field elsewhere, depending on the endpoint. The connector accepts
both. When you reach into raw. on the mapping screen, check the preview to see which one you got.
Stock is the inventory summary. On hand, available and allocated per warehouse. Set Warehouse to read one warehouse only. Items of type Non-Stock Item come through without inventory tracking, and anything whose status is not Active arrives blocked.
Your order number is customerOrderNbr. The Commerce order number goes out in the sales
order's customer order number (up to 50 characters). Before creating an order the connector asks
Visma for a sales order with that number. Order status comes back matched on it. Visma answers a
create with 204 and the new order's address in the Location header rather than a body.
Every order needs a customer number. Link the Craft user to a Visma customer, or set a Guest customer code on the order mapping: the customer number guest orders are booked against.
Correcting a field
The connector reads the SKU from inventoryNumber. If your web SKU is held elsewhere, such as the
item's alternate ID or a custom attribute your partner added, correct it on the Products
mapping:
raw.alternateId → sku transform: trim
Where the field is a look-up value, add .value to the path, e.g. raw.itemClass.value, and check
the mapping preview. Visma is not consistent about which fields are wrapped.
See Field mapping for the rule syntax and the full transform list, Syncing for runs and watermarks, and Troubleshooting when something does not arrive.