Erpy for Craft CMS

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

EntityDirectionDelta syncPage size
CustomersERP → CommerceYes, on lastModifiedDateTime200
ProductsERP → CommerceYes, on lastModifiedDateTime200
InventoryERP → CommerceNo500
OrdersCommerce → ERP
Order statusERP → CommerceYes200
ShipmentsERP → CommerceYes200
InvoicesERP → CommerceYes200
CreditERP → CommerceNo200

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.

FieldWhat to put there
Client ID / Client secretFrom your integration in the Visma Developer Portal.
ScopeThe 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 IDSent as the ipp-company-id header.
WarehouseThe warehouse stock is read from and order lines are raised against.
Sales order typeDefaults to SO.
Create orders on holdOn 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.