Erpy for Craft CMS

Erpy for MYOB

Erpy for MYOB connects Craft Commerce to MYOB's two mid-market products: MYOB Acumatica (formerly MYOB Advanced) and MYOB Exo Business. 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-myob
php craft plugin/install erpy-myob

Then Erpy → Connections → New connection and pick the connector for the product you run. The add-on has no settings screen of its own; everything lives on the connection.

Connectors in this package

ConnectorPick it if you run
MYOB Acumatica (Advanced)MYOB Acumatica, or MYOB Advanced before the rename. A cloud product with an instance URL like https://example.myobadvanced.com.
MYOB ExoMYOB Exo Business, on-premise or hosted, reached through the Exo API.

They share a vendor and nothing else, which is why they live in one add-on rather than two plugins nobody could tell apart. MYOB Acumatica is also deliberately a separate implementation from Erpy for Acumatica: a MYOB merchant should not have to install a plugin for a product they do not run.

What it syncs

EntityMYOB AcumaticaMYOB Exo
CustomersERP → Commerce, deltaERP → Commerce, delta
ProductsERP → Commerce, deltaERP → Commerce, delta
InventoryERP → Commerce, full readERP → Commerce, delta
OrdersCommerce → ERPCommerce → ERP
Order statusERP → Commerce, deltaERP → Commerce, delta
ShipmentsERP → Commerce, delta
InvoicesERP → Commerce, delta
CreditERP → Commerce, full readERP → Commerce

Neither connector syncs contract prices. Both declare multi-company support. Page sizes are 200 (500 for inventory) on MYOB Acumatica and 100 on Exo.

MYOB Acumatica

Connecting

FieldWhat to put there
Instance URLe.g. https://example.myobadvanced.com.
Endpoint versionThe Default endpoint's version, from Integration → Web Service Endpoints. Defaults to 20.200.001. It differs between MYOB releases.
Username / PasswordA dedicated integration user.
Company / tenantLeave blank on a single-tenant instance.
BranchLeave blank for the user's default.
WarehouseStock is read from, and orders raised against, this warehouse.
Sales order typeDefaults to SO.
Create orders on holdOn by default, so an order can be reviewed before it reaches the warehouse.

On Test connection, a 401 means the username, password or tenant, and a 404 means the endpoint version.

Things to know

It is Acumatica underneath. MYOB licenses Acumatica's platform, so this is the contract-based REST API, with the same habits:

  • A session, not a token. The connector signs in once per run, shares the session cookie and signs out afterwards. MYOB counts concurrent sessions against your licence, so give the integration a user of its own.
  • Every value is wrapped as {"value": …}. The connector unwraps them; a mapping rule reading raw. has to add .value itself.
  • No paging metadata. A short page is the only signal that the end has been reached.

Stock is available stock from the inventory summary inquiry, which accounts for allocations. It has no modified date, so each inventory run reads everything.

Your order number is CustomerOrder. The Commerce order number goes out in the sales order's CustomerOrder field. The connector checks for it before creating an order, so a retry does not make a second one. Order status comes back matched on it.

MYOB Exo

Connecting

Exo needs three separate credentials and gives the same 401 when any one of them is wrong or missing. That is why each is its own labelled field.

FieldWhat to put there
API URLThe hosted gateway (default https://exo.api.myob.com), or your own Exo API host for an on-premise deployment.
Developer keyIdentifies your integration. Sent as x-myobapi-key.
Exo username / Exo passwordThe Exo user the integration acts as.
MYOB account email / passwordOnly on a hosted install, where the gateway also wants Basic credentials for the MYOB account.
BranchThe branch id new orders are raised against.
Stock locationThe numeric location id stock is read from, and orders raised against. Blank means the item's total.

On Test connection, a 401 means check all three credentials. On a hosted install it often means the account email and password are missing. A 403 means the developer key is not authorised for this Exo database.

Things to know

The Exo token is not the Basic header. The Exo user's credentials go in their own x-myobapi-exotoken header; the MYOB account's go in Authorization. Sending one in place of the other is the usual reason a correct set of credentials still gets a 401. The connector builds both from the fields above.

Customers are debtors. Exo is a debtor ledger rather than a CRM, and the customer code everywhere else in Erpy is Exo's account number, accno. It is numeric. Orders are raised against it, and a Guest customer code on the order mapping must be a numeric debtor account too.

A discontinued line is not deleted. Exo marks it with status. Anything but A arrives blocked. Items with stock type S come through without inventory tracking.

The stop flag has two levels. stopcredit is 1 to warn and 2 to block. Both come through as on hold, because either means nobody should sell on account without looking first.

Response shapes vary with the gateway. Exo answers with a bare array on some resources and an items envelope on others, depending on the gateway version in front of it. The connector accepts both.

Your order number is customerordernumber. The first 20 characters also go in reference. Order status is matched on customerordernumber. The connector does not look for an existing order before posting; Erpy's identity map is what stops an order being sent twice.

Correcting a field

On Exo, a product's base price is read from sellprice1. If your web price is a different price band, correct it on the Products mapping:

raw.sellprice2   →   price        transform: number

On MYOB Acumatica the same kind of rule needs the wrapper unwrapped, e.g. raw.DefaultPrice.value → price.

See Field mapping for the rule syntax and the full transform list, Syncing for runs and watermarks, and Troubleshooting when something does not arrive.